Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make java's ImageBuffer to read a PNG file correctly?

For some reason, opening up some PNG files using ImageBuffer and ImageIO does not work. Here's some code I am using that works fine for resizing/cropping JPGs:

BufferedImage image = ImageIO.read(new File(location));

BufferedImage croppedImage = image.getSubimage(
    cropInfo.getX(), cropInfo.getY(), cropInfo.getW(), cropInfo.getH());

BufferedImage resizedImage = new BufferedImage(
    TARGET_WIDTH, TARGET_HEIGHT, croppedImage.getType());
Graphics2D g = resizedImage.createGraphics();
g.drawImage(croppedImage, 0, 0, TARGET_WIDTH, TARGET_HEIGHT, null);
g.dispose();

this.changeContentType("image/png", ".png"); // not really relevant. just a property

ImageIO.write(resizedImage, "png", new File(location));

return resizedImage;

The goal of this function is to take whatever type is given, resize and crop the image, and then save it to PNG with the same filename.

It works on Windows, but if I crop/resize on Linux (lenny), it crashes altogether and complains about the type of the file (it says the type is 0).

java.lang.IllegalArgumentException: Unknown image type 0
    java.awt.image.BufferedImage.<init>(BufferedImage.java:490)
    trainingdividend.domain.file.ServerImage.resizeImage(ServerImage.java:68)
    trainingdividend.domain.file.ServerImage.cropAndResize(ServerImage.java:80)
    trainingdividend.service.user.UserAccountManagerImpl.cropAvatar(UserAccountManagerImpl.java:155)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

Solutions?

Is there another library I can use altogether?

like image 348
egervari Avatar asked Apr 29 '11 18:04

egervari


2 Answers

When running my function on Windows, croppedImaged.getType() returns the value 5. So, the simple "hack" is to store the type, check to see if it's 0... and if it is, set the value to 5 manually.

int imageType = croppedImage.getType();
if(imageType == 0) imageType = 5;

We then pass in imageType instead and it should work on Linux.

I am sure this has the drawback that if the value is 0 in other cases, it will set it to 5 and that will be wrong. However, this seems to work for common image types on Linux and it hasn't caused any problems.

It's pretty clear that the Windows version of Java 1.6 is perfectly fine, but the Linux version has a bug in it.

like image 140
egervari Avatar answered Nov 18 '22 09:11

egervari


egervari, you can use a library like imgscalr (Apache 2) to do all the resizing for you "properly" that fixes issues like these with a very simple API -- it won't help with the cropping, but the resizing is what it does best (different speeds, qualities, even anti-aliasing if you want).

I would point out that the code you are using now (forcing a CUSTOM type into a 3BYTE_BGR type) should also account for inbound images with an alpha channel.

Also if you want to keep using your custom code, RGB and ARGB are two of the best supported image types in Java2D -- if you use a poorly supported image type, when Java2D goes to perform the image op, it falls back to its software rendering pipeline and doesn't use the specialized hardware accelerated ones. This doesn't just effect performance as you'll see the result actually look worse (e.g. in GIF You see this a lot).

Again, imgscalr takes care of all this for you automatically if you wanted to give it a try, but if not, I figured I'd just give a heads up incase you were running into some of these headaches.

java image processing is... temperamental :)

like image 44
Riyad Kalla Avatar answered Nov 18 '22 10:11

Riyad Kalla