Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting transparent gif / png to jpeg using java

I'd like to convert gif images to jpeg using Java. It works great for most images, but I have a simple transparent gif image:

Input gif image http://img292.imageshack.us/img292/2103/indexedtestal7.gif

[In case the image is missing: it's a blue circle with transparent pixels around it]

When I convert this image using the following code:

File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
File f = new File("indexed_test.jpg");
ImageIO.write(image, "jpg", f);

This code works without throwing an Exception, but results an invalid jpeg image:

Output jpeg image

[In case the image is missing: IE cannot show the jpeg, Firefox shows the image with invalid colors.]

I'm using Java 1.5.

I also tried converting the sample gif to png with gimp and using the png as an input for the Java code. The result is the same.

Is it a bug in the JDK? How can I convert images correctly preferably without 3rd party libraries?

UPDATE:

Answers indicate that jpeg conversion cannot handle transparency correctly (I still think that this is a bug) and suggest a workaround for replacing transparent pixels with predefined color. Both of the suggested methods are quite complex, so I've implemented a simpler one (will post as an answer). I accept the first published answer with this workaround (by Markus). I don't know which implementation is the better. I go for the simplest one still I found a gif where it's not working.

like image 969
asalamon74 Avatar asked Jan 21 '09 10:01

asalamon74


3 Answers

For Java 6 (and 5 too, I think):

BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);
like image 91
Lana Avatar answered Nov 04 '22 23:11

Lana


As already mentioned in the UPDATE of the question I've implemented a simpler way of replacing transparent pixels with predefined color:

public static BufferedImage fillTransparentPixels( BufferedImage image, 
                                                   Color fillColor ) {
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage image2 = new BufferedImage(w, h, 
        BufferedImage.TYPE_INT_RGB);
    Graphics2D g = image2.createGraphics();
    g.setColor(fillColor);
    g.fillRect(0,0,w,h);
    g.drawRenderedImage(image, null);
    g.dispose();
    return image2;
}

and I call this method before jpeg conversion in this way:

if( inputImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
    inputImage = fillTransparentPixels(inputImage, Color.WHITE);
}
like image 26
asalamon74 Avatar answered Nov 05 '22 01:11

asalamon74


The problem (at least with png to jpg conversion) is that the color scheme isn't the same, because jpg doesn't support transparency.

What we've done successfully is something along these lines (this is pulled from various bits of code - so please forgive the crudeness of the formatting):

File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage jpgImage;

//you can probably do this without the headless check if you just use the first block
if (GraphicsEnvironment.isHeadless()) {
  if (image.getType() == BufferedImage.TYPE_CUSTOM) {
      //coerce it to  TYPE_INT_ARGB and cross fingers -- PNGs give a    TYPE_CUSTOM and that doesn't work with
      //trying to create a new BufferedImage
     jpgImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
  } else {
     jpgImage = new BufferedImage(width, height, image.getType());
  }
} else {
     jgpImage =   GraphicsEnvironment.getLocalGraphicsEnvironment().
        getDefaultScreenDevice().getDefaultConfiguration().
        createCompatibleImage(width, height, image.getTransparency()); 
}

//copy the original to the new image
Graphics2D g2 = null;
try {
 g2 = jpg.createGraphics();

 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 g2.drawImage(image, 0, 0, width, height, null);
}
finally {
   if (g2 != null) {
       g2.dispose();
   }
}

File f = new File("indexed_test.jpg");

ImageIO.write(jpgImage, "jpg", f);

This works for png to jpg and gif to jpg. And you will have a white background where the transparent bits were. You can change this by having g2 fill the image with another color before the drawImage call.

like image 4
harmanjd Avatar answered Nov 04 '22 23:11

harmanjd