I have an InfiniteScrollAdapter
in which I use Multibutton
to display a list featuring a photo and its description.
It works well but I need to make the photo rounded. That's why I got inspired by the official guide on image masking. Unfortunately what I get is only a black round. Here is the code I used:
MultiButton[] cmps = new MultiButton[reports.size()];
for (int iter = 0; iter < reports.size(); iter++) {
Report currentReport = reports.get(iter);
if (currentReport == null) {
InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), new Component[0], false);
return;
}
String photoFilenameInStorage = Report.getFilename(currentReport.getPhotoPath());
Image reportImage = URLImage.createToStorage(placeholder, photoFilenameInStorage, currentReport.getPhotoPath(), URLImage.RESIZE_SCALE_TO_FILL );
int w = reportImage.getWidth();
int h = reportImage.getHeight();
// Generates a mask to make the image round
Image maskImage = Image.createImage(w, h, 0xff000000);
Graphics g = maskImage.getGraphics();
g.setAntiAliased(true);
g.setColor(0xFFFFFF);
g.fillArc(0, 0, w, h, 0, 360);
Object mask = maskImage.createMask();
Image maskedImage = reportImage.applyMask(mask);
String summary = currentReport.getLocation();
cmps[iter] = new MultiButton(summary);
// Only shows a black filled circle!
cmps[iter].setIcon(maskedImage);
}
InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), cmps, true);
What I've noticed is that all examples I could find about the rounded image in CN1 dealt with Label
. Is it possible to apply a mask on a MultiButton
in Codename One? If so, how can I do that?
Any help appreciated,
Summary after reading the answers and comments 2017-02-16
I have had hard time to figure out why @Diamond's answer did work and not mine although I did follow @Shai's guide on masking to get rounded images. So I write the outcome of my findings in case other newbies at CN1 came across this issue. Thnaks again to @Diamond for his great explanations that helped a lot!
First of all, the round mask introduced above is working since it yields a black round. Indeed by the time where the mask is applied the reportImage
has not been downloaded yet since quoting from the javadoc
By default an image is fetched lazily as it is asked for by the GUI unless the fetch() method is invoked in which case the IO code is executed immediately.
Consequently reportImage
is still as black as the placeholder was defined. By the way this is why @Diamond suggested to define a round placeholder with a nice color to be shown before the actual (round) image gets available (see the first cmps[iter].setIcon(placeholder)
call in his answer).
And the URLImage will only be actually downloaded when the InfiniteScrollAdapter
needs and fetches the image.That's why @Diamond wraps
So as a conclusion the code above cannot work in an InfiniteScrollAdapter
and after all my trials I tend to think that the only way to achieve what I wanted to do is the code @Diamond wrote with @Shai's suggestion.
Please note that with if the downloaded picture is a PNG @Diamond's round mask adapter does not seem to work anymore => the resulting image is only rounded if the PNG is converted as JPEG.
Yes it is, Multibutton icon is a Label component which you can get by calling
cmps[iter].getIconComponent()
Edit:
Based on Shai's comment, your code should become something like this...
Round Mask Adapter:
private final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
@Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp.getWidth() > placeholderImage.getWidth()) {
int diff = tmp.getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp.getHeight() > placeholderImage.getHeight()) {
int diff = tmp.getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()),
Math.min(placeholderImage.getHeight(), tmp.getHeight()), true);
}
Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp = tmp.applyMask(mask);
return EncodedImage.createFromImage(tmp, false);
}
@Override
public boolean isAsyncAdapter() {
return true;
}
};
Code Improvement:
//Placeholder image
int size = Display.getInstance().convertToPixels(20);
Image placeholder = Image.createImage(size, size, 0xbfc9d2);
Graphics g = placeholder.getGraphics();
g.setAntiAliased(true);
g.setColor(0xbfc9d2);
g.fillArc(0, 0, size, size, 0, 360);
MultiButton[] cmps = new MultiButton[reports.size()];
for (int iter = 0; iter < reports.size(); iter++) {
Report currentReport = reports.get(iter);
if (currentReport == null) {
InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), new Component[0], false);
return;
}
String photoFilenameInStorage = Report.getFilename(currentReport.getPhotoPath());
String summary = currentReport.getLocation();
cmps[iter] = new MultiButton(summary);
// Only shows a black filled circle!
cmps[iter].setIcon(placeholder);
Display.getInstance().callSerially(() -> {
cmps[iter].setIcon( URLImage.createToStorage(cmps[iter].getIcon(), photoFilenameInStorage, currentReport.getPhotoPath(), RESIZE_SCALE_WITH_ROUND_CORNER_MASK));
cmps[iter].getParent().revalidate();
});
}
InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), cmps, true);
来源:https://stackoverflow.com/questions/42236165/is-it-possible-to-make-rounded-image-via-mask-on-multibutton-codename-one