How to get scaled instance of a bufferedImage - java

I wanted to get scaled instance of a buffered image and I did:
public void analyzePosition(BufferedImage img, int x, int y){
img = (BufferedImage) img.getScaledInstance(getWidth(), getHeight(), Image.SCALE_SMOOTH);
....
}
but I do get an exception:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be cast to java.awt.image.BufferedImage
at ImagePanel.analyzePosition(ImagePanel.java:43)
I wanted then to cast to ToolkitImage then use the method getBufferedImage I read about in other articles. The problem is there is no class such as sun.awt.image.ToolkitImage I cannot cast to it because Eclipse does not even see this class. I use Java 1.7 and jre1.7.

You can create a new image, a BufferedImage with the TookitImage.
Image toolkitImage = img.getScaledInstance(getWidth(), getHeight(),
Image.SCALE_SMOOTH);
int width = toolkitImage.getWidth(null);
int height = toolkitImage.getHeight(null);
// width and height are of the toolkit image
BufferedImage newImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.getGraphics();
g.drawImage(toolkitImage, 0, 0, null);
g.dispose();
// now use your new BufferedImage

BufferedImage#getScaledInstance is actually inherited from java.awt.Image and only guarantees that it will return an Image so I would say it's not a good idea to try and assume the underlying return type in this case.
getScaledInstance is, also, not normally the fastest or best quality method
To scale a BufferedImage itself, you have a number of different options, but most simply take the original and repaint it to another image, applying some kind of scaling in process.
For example:
Scale the ImageIcon automatically to label size
Position Image in any Screen Resolution
how to make image stretchable in swing?
For more details about getScaledInstance, have a read of The Perils of Image.getScaledInstance()

Related

Is there a way to scale an image down to a specific size?

I am currently trying to get some kind of 2D dungeoncrawler (think: roguelike) running. Now I want to work with square tiles (32x32) but I wonder if there's a way to make my textures in a higher resolution, say 64x64, and scale them down onto a 32x32 square?
I imagine there has to be since almost all games do this in one way or another but all I can seem to find online is about 3D stuff.
Yeah. When you draw an image, you can add the new width and height to it to resize it.
public static BufferedImage resizeImage(BufferedImage image, int newwidth, int newheight) {
BufferedImage image2 = new BufferedImage(newwidth, newheight, BufferedImage.TYPE_INT_ARGB);
Graphics g = image2.getGraphics();
g.drawImage(image, 0, 0, newwidth, newheight, null);
g.dispose();
return image2;
}
Refer to here for more info.

ImageIO not printing proper color

I am trying to read a PNG image file from disk, draw some rectangles on it and save the modified image on the disk. Here's the scala code:
//l is a list of Rectangle objects of the form (x1,x2,y1,y2)
val image = ImageIO.read(sourceimage);
val graph=image.createGraphics()
graph.setColor(Color.GREEN)
l.foreach(x=>graph.draw(new java.awt.Rectangle(x.x1,x.y1,x.x2-x.x1,x.y2-x.y1)))
graph.dispose()
ImageIO.write(image,"png",new File(destimage))
The rectangles are drawn but in GREY color instead of GREEN. What am I doing wrong?
If the source image is a gray scale image, then it's unlikely that it will be capable of using any color of any sort.
Instead, you need to create a second, colored, BufferedImage and paint the original to it.
BufferedImage original = ImageIO.read(sourceimage);
BufferedImage iamge = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
g2d.drawImage(original, 0, 0, null);
// Continue with what you have
Sorry, I have no experience with PIL, but that's how you'd do it (basically) in pure Java

Java GUI image size

So I have an assignment where I need to create a catalog.
The catalog needs to have a list, an image and a description.
My entire code works, so I have no issue with the coding as such.
I do have an issue with the image size.
How do I take care of images on a java gui program to make them all into one size when it is running.
Please let me know :D
When you read in an image, create a new BufferedImage that is the exact size that you desire, get it's Graphics object via getGraphics(), draw the original image into the new image using Graphics#drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) where x and y are 0 and width and height are from the dimensions of the new image, dispose() of the Graphics object, and then display the new Image as an ImageIcon in a JLabel. Make sure though that the original image is the same size or larger than the new one, else your images will look gawd-awful.
For example, and note that this code may not be exactly correct since I don't have my IDE up:
BufferedImage originalImage = ImageIO.read(something); // read in original image
// create new empty image of desired size
BufferedImage newImage = new BufferedImage(desiredWidth, desiredHeight, BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.getGraphics(); // get its graphics object
// draw old image into new image
g.drawImage(originalImage, 0, 0, desiredWidth, desiredHeight, null);
g.dispose(); // get rid of Graphics object
// create ImageIcon and put in JLabel to display
Icon newIcon = new ImageIcon(newImage);
myJLabel.setIcon(newIcon);
I would propably create a JPanel to draw on one Image, and then work with the method:
myPanel.setSize(new Dimension(x,y))
or
myPanel.setPreferredSize(new Dimension....)
There is a method (image = imgobj.getScaledInstance(width, height, hints)) in awt.Image class which provides re-sizing capabilities very nicely, I always use this to re-size my images when I need. Please see here some examples :-), I hope it will work for you, it is the most convenient way to scale images I have ever seen. create a method pass the image to the method and size of the image you want and return the image back in return to reuse the code ;)

Fit Java Image into JFrame

I'm trying to display an Image that is bigger than the JFrame Dimensions. If I try to resize the Image smaller, then the Image quality is lost.
If I make the Image larger, the quality is not lost. Is this normal behavior in Java image package?
I guess what I'm trying to figure out is that probably I'm doing something wrong when reducing the Image size. So does Java provide a method to automatically do this without loosing image quality?
Same behavior like JButtons, where java automatically adjusts the space occupied by a JButton in a JPanel.
bufferedImage = resize(bufImage,500,600);
ImageIcon imageIcon = new ImageIcon(bufferedImage);
resizedIMage = imageIcon.getImage();
The actual resize is below. I took it from the internet.
private static BufferedImage resize(BufferedImage image, int width, int height) {
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
If you are using Java 5 or newer you can try RenderingHints.VALUE_INTERPOLATION_BICUBIC for your interpolation hint.
There is a very detailed description of the different scaling behaviours of Java2D in this article: perils-of-getScaledInstance
It contains examples of the different downscale results you can expect to see with the different approaches available in Java.
It also provides sample code that uses a multi-step aproach to downscale the image which appears to produce much better results than VALUE_INTERPOLATION_BILINEAR.
Override the paintComponent(Graphics g) method of whatever component will display the image and look at Graphics.drawImage()
You can even cast your Graphics instance into a Graphics2D for more functionalities. For example setRenderingHings()
Graphics2D g2 = (Graphics2D) g;
RenderingHints rh = g2.getRenderingHints ();
rh.put (RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints (rh);
I would get rid of this:
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
And always use BufferedImage.TYPE_INT_ARGB
That seems to give me good results.

Turn an array of pixels into an Image object with Java's ImageIO?

I'm currently turning an array of pixel values (originally created with a java.awt.image.PixelGrabber object) into an Image object using the following code:
public Image getImageFromArray(int[] pixels, int width, int height) {
MemoryImageSource mis = new MemoryImageSource(width, height, pixels, 0, width);
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(mis);
}
Is it possible to achieve the same result using classes from the ImageIO package(s) so I don't have to use the AWT Toolkit?
Toolkit.getDefaultToolkit() does not seem to be 100% reliable and will sometimes throw an AWTError, whereas the ImageIO classes should always be available, which is why I'm interested in changing my method.
You can create the image without using ImageIO. Just create a BufferedImage using an image type matching the contents of the pixel array.
public static Image getImageFromArray(int[] pixels, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0,0,width,height,pixels);
return image;
}
When working with the PixelGrabber, don't forget to extract the RGBA info from the pixel array before calling getImageFromArray. There's an example of this in the handlepixelmethod in the PixelGrabber javadoc. Once you do that, make sure the image type in the BufferedImage constructor to BufferedImage.TYPE_INT_ARGB.
Using the raster I got an ArrayIndexOutOfBoundsException even when I created the BufferedImage with TYPE_INT_ARGB. However, using the setRGB(...) method of BufferedImage worked for me.
JavaDoc on BufferedImage.getData() says: "a Raster that is a copy of the image data."
This code works for me but I doubt in it's efficiency:
// Получаем картинку из массива.
int[] pixels = new int[width*height];
// Рисуем диагональ.
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
if (i == j) {
pixels[j*width + i] = Color.RED.getRGB();
}
else {
pixels[j*width + i] = Color.BLUE.getRGB();
//pixels[j*width + i] = 0x00000000;
}
}
}
BufferedImage pixelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
pixelImage.setRGB(0, 0, width, height, pixels, 0, width);
I've had good success using java.awt.Robot to grab a screen shot (or a segment of the screen), but to work with ImageIO, you'll need to store it in a BufferedImage instead of the memory image source. Then you can call one static method of ImageIO and save the file. Try something like:
// Capture whole screen
Rectangle region = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capturedImage = new Robot().createScreenCapture(region);
// Save as PNG
File imageFile = new File("capturedImage.png");
ImageIO.write(capturedImage, "png", imageFile);
As this is one of the highest voted question tagged with ImageIO on SO, I think there's still room for a better solution, even if the question is old. :-)
Have a look at the BufferedImageFactory.java class from my open source imageio project at GitHub.
With it, you can simply write:
BufferedImage image = new BufferedImageFactory(image).getBufferedImage();
The other good thing is that this approach, as a worst case, has about the same performance (time) as the PixelGrabber-based examples already in this thread. For most of the common cases (typically JPEG), it's about twice as fast. In any case, it uses less memory.
As a side bonus, the color model and pixel layout of the original image is kept, instead of translated to int ARGB with default color model. This might save additional memory.
(PS: The factory also supports subsampling, region-of-interest and progress listeners if anyone's interested. :-)
I had the same problem of everyone else trying to apply the correct answer of this question, my int array actually get an OutOfboundException where i fixed it adding one more index because the length of the array has to be widht*height*3 after this i could not get the image so i fixed it setting the raster to the image
public static Image getImageFromArray(int[] pixels, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0,0,width,height,pixels);
image.setData(raster);
return image;
}
And you can see the image if u show it on a label on a jframe like this
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setVisible(true);
setting the image on the imageIcon().
Last advice you can try to change the Bufferedimage.TYPE_INT_ARGB to something else that matches the image you got the array from this type is very important i had an array of 0 and -1 so I used this type BufferedImage.TYPE_3BYTE_BGR

Categories

Resources