I am trying to write an imageloading function for my program, however it is doing something strange.
public void loadImage(BufferedImage img, String filepath) {
try {
img = ImageIO.read(new File(filepath));
}
catch (IOException e) {
}
}
And I am calling it like so:
BufferedImage background = null;
loadImage(background, path);
I see in debugging that img loads properly, but background remains null the whole time and causes a NullPointerException.
When I change to a direct reference to background like background = ImageIO.read(new File(filepath)); then it works just fine.
What's even more strange is that System.out.println(img == background) prints true.
What am I doing wrong?
This is because Java passes arguments by value, not reference. As far as Java is concerned, img from loadImage has nothing to do with background. All you did was pass over the address to whatever background refers to, not the reference background itself. background basically told the parameter img, "Hey, point at whatever I'm pointing at."
When you go
img = ImageIO.read(new File(filepath));
You've just set img to refer to some new object, but background will still refer to whatever it was referring to before.
Instead, you should return the BufferedImage and set background to the return value, so something like
public BufferedImage loadImage(String filepath) {
try {
return ImageIO.read(new File(filepath));
}
catch (IOException e) {
}
return null;
}
background = loadImage(path);
This previous question has a little more info on the Pass-by-Value vs Pass-by-Reference issue in Java. Personally, the idea of the value of references being passed took me a while to get it through my head until I read this article.
Hope this helps.
As for your second note that img == background returns true, I'm not sure where you are checking this, but if you check it before img = ImageIO..., that will return true, because img and background both refer to null, since they are uninitialized.
==, when dealing with two Objects, will return true if and only if they both refer to the same object in memory, not if they are the same exact reference.
Related
So I have the following bit of code:
public static Image getImage(String filepath, Class cl) {
try {
return ImageIO.read(cl.getResource(filepath));
}
catch (IOException e) {
e.printStackTrace();
}
return null; // Will never execute
}
It's a basic try-catch block. If I am unable to read the image and return it, I immediately go into my catch block. However, because my return is within the scope of the try block and not the entire function, my compiler issues an error when I try to compile and run because it sees that it's possible that I never hit a return statement. Therefore, I've added the return null; line to suppress this warning, but I'd rather have a neater way of doing this without putting code that will never run. I've tried adding
#SuppressWarnings("all")
To my code, but it still gives me an error. Any ideas? I feel like there should be a way to tell the compiler to ignore errors like this.
Also, if it is of any use, I am using IntelliJ as my IDE.
I would suggest what #LuCio eagerly in the comments tried to say. Just don't catch the Exception and pass it upwards:
public static Image getImage(String filePath, Class<?> clazz) throws IOException {
return ImageIO.read(clazz.getResource(filePath));
}
That way you have created an easy helper method. If you would return null, you'd have to document that in JavaDoc and every caller will have to use a not-null assertion logic to then throw an error if it is null.
A try catch block does the same. So instead of passing null upwards you just propagate the exception upwards. You somewhere said that you want to assign the Image to a static field, so you can do that easily like this:
static {
try {
MY_IMAGE = getImage("somepath", MyClass.class);
} catch(IOException e){
throw new IOError(e); // will kill the Vm with an error
}
}
But maybe somewhere you have another action. Than to just kill the VM. Maybe use a default image:
final Image image;
try {
image = getImage("somepath", MyClass.class);
} catch(IOException e){
e.printStacktrace();
image = new SomeDefaultImage();
}
// do something with image
Which all in all is the way to go. You can't have a helper method to decide what to do when it fails. That should always be done by the calling code.
Ok so, I believe I was confusing the purpose of the catch block. Thank you to #Ben and #Zephyr and everybody else for your help. I will be amending my code to:
public static Image getImage(String filepath, Class cl) {
try {
return ImageIO.read(cl.getResource("hello"));
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
throw new IOError(e);
}
}
Edit: After some more discussions, and looking through other options other people have posted, I have updated my code above, which satisfies the compiler. Note that replacing the line
throw new IOError(e)
with
System.exit(0);
does not fix the error because, as far as I know, the compiler cannot tell at compile time whether the program would end. It would've been helpful to have a way of suppressing the warning, since we know that at runtime the program will always (or practically always) end, but alas #SuppressWarnings is of no use.
So I know to declare and initialize a global variable one would have to do something like this for example:
public static int Variable = 2;
But I want to know if there is a way to initialize a global BufferedImage variable with an image from a file. I can't use the above code, since I also need to include a try/catch statement.
Anyone have any solutions to my problem?
I think that you want to use a static bloc.
public static BufferedImage image = null ;
static
{
try {
image = javax.imageio.ImageIO.read(new File("Image path")) ; // Or whatever reader you use.
}
catch (IOException ex)
{
Logger.getLogger(Prototyper.class.getName()).log(Level.SEVERE, null, ex);
}
}
Btw, as mentioned in the first comment below, this is REALLY bad practice. Usually you want to use a Read static method, and you read the image where you need it, not by default.
I have an SWT table that is wrapped with a JFace TableViewer.
My requirements are:
Decorate the column image with the decorators as they are defined in the workbench decorator manager
Decorate the text of the columns with different colors
I was able to #1 by extending DecoratingLabelProvider and implementing ITableLabelProvider. I passed it my original TableLabelProvider and the workbench decorator manager, and I got icons with decorators.
Then I started to work on #2. I asked this question here and was told that IStyleLabelProvider (what I was trying to use for the colored text) was incompatible with ITableLabelProvider. So I switched to using a ColumnLabelProvider that implements IStyledLabelProvider.
However, now I am stuck. These 2 requirements seem to be mutually exclusive. I cannot extend both ColumnLabelProvider and DecoratingLabelProvider. When I tried to simply pass in the workbench decorator manager to the ColumnLabelProvider like this, but it did not decorate the image at all. Did I pass it in wrong, or will that only work in a DecoratingLabelProvider? What else can I try?
public Image getColumnImage(final Object element, final int columnIndex) {
if (columnIndex == MY_COLUMN_INDEX) {
final MyObject myObj = (MyObject) element;
final Image image = myObj .getImage();
Image newImage = null;
if(this.decorator != null) {
newImage = this.decorator.decorateImage(image, myObj );
}
return newImage == null ? image : newImage;
}
return null;
}
You can use DecoratingStyledCellLabelProvider which takes an IStyledLabelProvider and an ILabelDecorator as parameters:
new DecoratingStyledCellLabelProvider(styledLabelProvider,
PlatformUI.getWorkbench().getDecoratorManager()
.getLabelDecorator(), null);
I'm extending javax.swing.JComponent to display a variable number of tiles, which all have the same size.
If a tile needs a new appearance, a SwingWorker's doInBackground() renders a new BufferedImage for it. In done(), the image is stored and JComponent.repaint() is called, indicating the updated area and an intended delay. The overridden JComponent.paintComponent() will know what to do.
The size of the tiles can be changed via the GUI. Obvioulsy, it could happen that such a request takes place while the the SwingWorker's StateValue is PENDING or STARTED.
I don't see much sense in supporting cancel(); it complicates the code and since the actual rendering does not take very long, its effect would be minimal (or even harmful if the worker had to wait longer than it will need to execute). Rather, I would like to add efficiency and have the EDT code not start a new SwingWorker if a PENDING one exists for the same tile. Then, the SwingWorker just needs to fetch the latest settings when doInBackground() starts and check whether it should really store its result in done().
So where should the BufferedImage used by the SwingWorker be cast into existence? These seem to be the options:
Create it upfront. Drawbacks: The maximum size must be chosen because the specific size is unknown, and since paintComponent() may run concurrently, two images of maximum size must be kept for all tiles at all times (think ViewPort; a dynamic solution would only require a second image of the actually needed size for visible tiles, temporarily).
Create it when creating the SwingWorker. Drawback: The maximum size must be provided since it's unknown which size is required once doInBackground() gets fired.
Create it in the SwingWOrker. Problem: Given that JComponent.paintComponent() may have to call drawImage() often, it's advisable to use GraphicsConfiguration.createCompatibleImage() to create this image. This may break the single-threadedness limitations of AWT.
I would prefer the following, but since GraphicsConfiguration belongs to AWT, and the implementation depends on the platform, is this a safe thing to do?
...
final GraphicsConfiguration gc = this.getGraphicsConfiguration();
if ((obj.worker == null) ||
(obj.worker.getState() != SwingWorker.StateValue.PENDING)) {
obj.worker = new SwingWorker<BufferedImage, Void>() {
#Override public BufferedImage doInBackground() {
... // acquire size info via synchronised access
final BufferedImage img = gc.createCompatibleImage(...);
...
return img;
}
#Override public void done() {
if (obj.worker == this) {
obj.worker = null;
try { obj.image = this.get(); }
catch (Throwable t) { ... System.exit(1); }
Outer.this.requestTileRepaint(...);
}
}
};
obj.worker.execute();
}
...
Clarification
Looking at the above code, one might argue that there is no real muti-threading issue with this solution, since the GraphicsConfiguration object is created on the EDT exclusively for this particular worker. However,
I was looking at the abstract class implementation and it contains static objects and
it might be the case that each call to Component.getGraphicsConfiguration() returns the same object reference.
I was thinking that the safest approach would be to extract all relevant information from the GraphicsConfiguration on the EDT, pass it to the worker, and get a new BufferedImage() there with the suitable configuration. But I found some hints on the web that the result may lead to a surprising performance hit for drawImage(), suggesting that there might be config aspects which may not be covered explicitly.
Picking up haraldK's ideas, here is a thread-safe solution, which I have tested on a Linux PC with Java SE 1.6.0_26 and a Windows 8.1 notebook with Java SE 1.8.0_40. (Obviously, the code can be improved, buit that's beyond this Q&A.)
On both platforms, performance was comparable adjusted for processor speed, and also on both platforms, Transparency.BITMASK was handled via BufferedImage.TYPE_CUSTOM, while Transparency.OPAQUE and Transparency.TRANSLUCENT use specific corresponding BufferedImage.TYPE_* values.
Also on both platforms, there was no noticeable performance difference between using any of the two new BufferedImage() calls, while GraphicsConfiguration.createCompatibleImage() was definitely (30% to 50%) slower.
The whole mechanism is provided by an inner class. The outer class extends javax.swing.JComponent so there's no synchronisation at all at that level. However, the SwingWorkers are anonymous inner classes and deploy the image creation sync mechanism.
The distinction between the two categories of BufferedImage.getType() seems to be unnecessary on the tested platforms, but who knows.
In my case, the innter class also contains other information which the SwingWorkers need.
private static final class WokerSync
{
private Object refImageMutex = new Object();
private BufferedImage refImageOpaque = null;
private BufferedImage refImageTranspMask = null;
private BufferedImage refImageTranslucent = null;
public void setRefImagesFromEDT(final GraphicsConfiguration grConf) {
if (grConf != null) {
synchronized(this.refImageMutex) {
this.refImageOpaque = grConf.createCompatibleImage(1, 1, Transparency.OPAQUE);
this.refImageTranspMask = grConf.createCompatibleImage(1, 1, Transparency.BITMASK);
this.refImageTranslucent = grConf.createCompatibleImage(1, 1, Transparency.TRANSLUCENT);
}
}
}
private BufferedImage getCompatibleImage(final BufferedImage refImage, final int width, final int height) {
BufferedImage img = null;
if (refImage != null) {
final int grType = refImage.getType();
if (grType == BufferedImage.TYPE_CUSTOM) {
final ColorModel cm = refImage.getColorModel();
final WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
final String[] ps = refImage.getPropertyNames();
final int pl = (ps == null) ? 0 : ps.length;
final Hashtable<String,Object> ph = new Hashtable<String,Object>(pl);
for (int pi=0; pi<pl; pi++) {
ph.put(ps[pi], refImage.getProperty(ps[pi]));
}
img = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), ph);
} else {
img = new BufferedImage(width, height, grType);
}
}
return img;
}
public BufferedImage getCompatibleImageOpaque(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageOpaque, width, height);
}
return img;
}
public BufferedImage getCompatibleImageTranspMask(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageTranspMask, width, height);
}
return img;
}
public BufferedImage getCompatibleImageTranslucent(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageTranslucent, width, height);
}
return img;
}
}
At first I was going to make the question solely about the Image class, but I wanted to make it as broadly applicable as possible.
Basically, here's the scenario. I'm making a file for GUI constants, and in this file I'd like to have final variables for each of the Images I'm using. So my fields are declared like this UP_ARROW is:
public static final Image UP_ARROW;
Then I try to load them when the ImageIO API, like so:
static {
UP_ARROW = ImageIO.read(new File("img/upArrow.png"));
}
Unfortunately, this isn't valid, compilable code, because it explicitly throws IOException, which I have to deal with. So I modify it and surround it with a try/catch:
static {
try {
UP_ARROW = ImageIO.read(new File("img/upArrow.png"));
}
catch(IOException ioe) {
//TODO
}
}
Now I get a different compiler error. This time it says there's a possibility that the field may not have been initialized. Okay, that makes sense. Thank you for pointing that out to me, compiler. That seems like an easy fix:
static {
try {
UP_ARROW = ImageIO.read(new File("img/upArrow.png"));
}
catch(IOException ioe) {
UP_ARROW = null;
}
}
Now, no matter what, the UP_ARROW must be populated with either my image or null. I'm prepared to declare victory and move on. But now I get another, unexpected compiler error:
... Foiled again, compiler!
Hence the question: is there any way to get around this, such that I can dynamically load final fields at runtime? Or do I declare defeat and simply make the Images non-final?
Also, an explanation as to why the compiler won't allow this would be helpful as well. As I understand it, based on the code above, the UP_ARROW object could not have been assigned before reaching the catch{} block, because that's what must have thrown the exception. So if the try{} executes successfully, only one assignment takes place. If it does not execute successfully, still only one assignment take place. How is that not valid?
The following should do it:
static {
Image up_arrow = null;
try {
up_arrow = ImageIO.read(new File("img/upArrow.png"));
}
catch(IOException ioe) {
// log the error?
}
UP_ARROW = up_arrow;
}
It might make sense to enclose the final assignment in a finally block .
NPE's answer is good, but I think this one is (based off his and) better:
public enum Arrows {
UP ("img/upArrow.png"),
DOWN ("img/downArrow.png"),
LEFT ("img/leftArrow.png"),
RIGHT ("img/rightArrow.png");
public final Image myImage;
private Arrows(String fileName) {
Image tempImage;
try {
tempImage = ImageIO.read(new File(fileName));
} catch (IOException e) {
tempImage = null;
}
myImage = tempImage;
}
}
This solves your problem and gives you all the advantages of an enum over static final variables.