Whenever dealing with the loading and rendering of images in Java, I have previously always used BufferedImages to store and manipulate the images in memory.
However, I have recently come across a few different sites that use the Image class instead of BufferedImage and this got me wondering - what are the differences?
I'm aware that a BufferedImage has a larger/optimised toolset, but does come at any cost? If so, when does this cost become noticeable? In which situations would you use an Image over a BufferedImage, or vice-versa?
BufferedImage extends Image. Image is just a base abstract class and you can't instantiate it. Under the hood you are using BufferedImage or another implementation for sure.
There shouldn't be any real performance difference between directly creating a BufferedImage and a Toolkit image (java.awt.Toolkit or Image#getScaledInstance). You'll never have an actual instance of Image because it's an abstract class; you'll only be dealing with its subclasses (e.g. BufferedImage).
Related
There are various ways of reading an image file in java such as BufferedImage and ImageIcon to name a few. I want to know what is the difference between these cases? Are they context dependent that in a particular case only one of them can be used?
What would be the best way of reading a image selected by JFileChooser by the user and separating the color channels of an image?
A good way is to use the different ImageIO.read methods, which return BufferedImage objects.
Image is an abstract class, so I think the real question is which subclass is more efficient for your program. Use VolatileImage if you need hardware acceleration. More on that here.
ImageIcon (and Toolkit#createImage/Toolkit#getImage) use a background loading process. That is, after you call these methods, they will return immediately, having created a background thread to actually load the image data.
These were/are used when loading large images across slow connections, like ye old 28k modems (ah, how I remember the days). This means that your application can continue running while the images are been downloaded.
You'll find in the Graphics class the drawImage methods accept an ImageObserver interface and that java.awt.Component implements this interface, this allows components the ability to automatically update themselves once the image has actually finished loading.
ImageIO on the other hand will not return until the image is fully loaded. It also makes it easier to introduce new readers/writers, making the API far more flexible then the original API. ImageIO also supports a wider range of images out of the box.
BufferedImage is also a far more flexible image class, especially when it comes to apply effects to the image.
Now, I, personally, prefer ImageIO. If I know I'm loading large images or images over a potentially slow connection, I will create my own background thread to load them. While a little more complicated, the trade offs greatly out weight the small amount of extra work -IMHO
What would be the best way of reading a image selected by JFileChooser by the user and separating the color channels of an image?
ImageIO without a doubt. In order to do any serious manipulation of an image loaded using something ImageIcon, you'd have to convert that image to a BufferedImage anyway
I've been researching the BufferedImage class to use for game programming purposes (so that I can make image maps for levels and use getRGB() to identify the tile in each pixel), but I'm very confused about how to actually make a BufferedImage. What's got me particularly confused is how you can't make a BufferedImage using an Image as a parameter. Step by step, how does one instantiate a BufferedImage for a simple image file (e.g. a .jpg)?
Simple steps - ImageIO.read(File file) as shown in the documentation
You can load an image with ImageIO.read(new File("example.jpg"));
I am wondering is there a way to convert Image to BufferedImage without code like a
new BufferedImage(...)
because every new init makes app run slower , moreover, if it is in paint() method :(
Please advise the most optimal conversion way.
Thanks
No. Not unless the original Image happens to be a BufferedImage already. Then you can just do a cast:
BufferedImage bufImg = null;
if (origImage instanceof BufferedImage) {
bufImg = (BufferedImage) origImage;
else {
bugImg = new BufferedImage(...);
// proper initialization
}
If it's not a BufferedImage it may very well be for instance a VolatileImage (the other concrete subclass in the API).
From the docs on volatile image:
VolatileImage is an image which can lose its contents at any time due to circumstances beyond the control of the application (e.g., situations caused by the operating system or by other applications).
As you may understand, such image can not provide the same interface as a BufferedImage, thus the only way to get hold of a BufferedImage is to create one, and draw the original image on top of it.
because every new init makes app run slower
Cache one BufferedImage, then only create a new image if the required size changes. Otherwise clear the Graphics object of the current instance and do whatever new drawing is needed.
Is there a way to draw a BufferedImage to JLabel with the paint() method?
One convenient approach is to implement the Icon interface. In this example, Histogram simply draws itself when the label is told to repaint().
If the source of the image requires a time-consuming operation such as scaling, pre-render the image as shown in the static factory, GradientImage.
Class Image is an abstract class—as a result, programs cannot instantiate class Image to create objects. To achieve platform independence, the Java implementation on each platform provides its own subclass of Image to store image information.
The text is about class java.awt.Image.
I don't understand the second part, namely:-
... provides its own subclass of Image to store image information.
Technically, how does that happen?
Image instances are typically created through methods such as Toolkit.createImage(). In this case, the actual instantiation of the Image object is delegated to the Toolkit class, which is platform-dependent.
Note that while you cannot directly instantiate class Image, you can instantiate BufferedImage, which is a concrete Image subclass.
The concrete subclass of Image might, in some cases, be a class which isn't part of the public API of the JDK. (In other cases, you might find that you're getting a BufferedImage, which is much nicer in the event that you intend to do something with the image you get.)
Try System.out.println(img.getClass().getName()); just to see what you're getting.
What is a Java type which can hold a PNG implement and provide access to it's pixel buffer?
BufferedImage img = ImageIO.read(new File("my.png"));
int color = img.getRGB(23,12);
I would take a look at Java Advanced Imaging, it handle multiple types of image files.
Take a look ImageIO and its numerous static helpers for reading and writing bytes/streams containing an image.
If you want to do pixel based operations on the entire image, I've found calling the getRGB() method every time to be fairly slow. In that case, you might want to try and get access to the actual pixel array holding the image data using something like:
byte[] pixel_array = ((DataBufferByte)img.getRaster().getDataBuffer()).getData()
There may be a more flexible way that doesn't make any presumptions on the array data type.