Mark Stephens Mark has been working with Java and PDF since 1999 and is a big NetBeans fan. He enjoys speaking at conferences. He has an MA in Medieval History and a passion for reading.

Odd coloured JPEGs in Java with ImageIO

1 min read

One of the best features about Java is the amount of low-level complexity it removes, allowing you to focus on developing the application. However, this does sometimes hide some important issues.

We found one of these with the ImageIO class which offers a whole series of methods to save an image as a Tiff, a PNG or a JPEG. All the complexity is hidden and you can save out the image in one line of code (magic). Unfortunately, it also hides an interesting feature…

ImageIO will happily save all kinds of images, including images with transparency (ARGB). And it will save it as a JPEG, even though JPEGs do not really support transparency. The problem comes when you try to view the JPEG. Java understands this hybrid image so it will load back correctly, but very few other tools do.

Because it has 4 bands (RGB are three and then transparency makes the fourth), most JPEG tools assume it must be in the CMYK colorspace and interpret the colors as CMYK. CMYK works completely differently to RGB so the image comes out looking wrong (often with a nasty red tint). Unfortunately, there is no way that a JPEG Decoder can spot this has happened – it is a bug in the way  ImageIO works. You can manually fix it by removing any alpha component from your BufferedImage before you save it in ImageIO with the following code

private static BufferedImage convertARGBToRGB(BufferedImage image) {
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
int[] pixelsOut = ((DataBufferInt) result.getRaster().getDataBuffer()).getData();
System.arraycopy(pixels, 0, pixelsOut, 0, pixels.length);
return result;
}

In our JDeli image library (which provides a complete JPG Converter), we have actually added a flag to read the JPEG correctly for you if you know the file is broken

try {
 Map map = new HashMap();
 map.put("DECODE_4_COMPONENTS_AS_ARGB","TRUE");
 BufferedImage image = JDeli.read(new File(“path/file.jpeg”), map); 
} catch (IOException e) {
 // Deal with read error here.
}

So while Java makes life much easier most of the time, there are some interesting gotchas out there…



Are you a Java Developer working with Image files?

Why do developers choose JDeli over free alternatives?

  1. Works with newer image formats such as AVIF, HEIC, JPEG XL, WEBP
  2. Better support than alternatives for JPEG, PNG, TIFF.
  3. Prevent JVM crashes caused by native code in other image libraries
  4. Better performance than other popular Java image libraries
Mark Stephens Mark has been working with Java and PDF since 1999 and is a big NetBeans fan. He enjoys speaking at conferences. He has an MA in Medieval History and a passion for reading.