+1  A: 

JPEG has no support for transparency. So even when you get the circle color correctly you will still have a black or white background, depending on your encoder and/or renderer.

Bombe
Black or white (preferably configurable) background would be acceptable for me. But currently the code creates invalid image.
asalamon74
+1  A: 

Maybe you have to check every pixel if it is alpha and set the background to white, if this is the color you want for the background.

Code is from here

AreaAveragingScaleFilter scaleFilter =
    new AreaAveragingScaleFilter(
      Math.round(originalWidth / factorX),
      Math.round(originalHeight / factorY));
ImageProducer producer = new FilteredImageSource(original.getSource(), scaleFilter);
ImageGenerator generator = new ImageGenerator();
producer.startProduction(generator);
BufferedImage scaled = generator.getImage();

for(int x = 0; x < scaled.getWidth(); x++) {
    for(int y = 0; y < scaled.getHeight(); y++) {
        int rgb = scaled.getRGB(x, y);
        int alpha = (rgb >> 24) & 0xff;
        if(alpha != 255) {
            scaled.setRGB(x, y,-1); //set white
        }
    }
}


JPEGImageWriteParam param = new JPEGImageWriteParam(null);
param.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality((float) 0.85);
java.util.Iterator<ImageWriter> it = ImageIO.getImageWritersBySuffix("jpg");
ImageWriter writer = it.next();
dest.getParentFile().mkdirs();
writer.setOutput(new FileImageOutputStream(dest));
writer.write(null, new IIOImage(scaled, null, null), param);
writer.dispose();
Markus Lausberg
Thanks for the tip. I've implemented a simpler way to replace the transparent pixels with white pixels. This workaroung works, but still very strange that the JDK creates invalid jpegs without this.
asalamon74
This can be done alot easier, as Lana suggested.
Alexander Kjäll
+2  A: 

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.

harmanjd
A: 

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);
}
asalamon74
+1  A: 

3 months late, but I am having a very similar problem (although not even loading a gif, but simply generating a transparent image - say, no background, a colored shape - where when saving to jpeg, all colors are messed up, not only the background)

Found this bit of code in this rather old thread of the java2d-interest list, thought I'd share, because after a quick test, it is much more performant than your solution:

        final WritableRaster raster = img.getRaster();
        final WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), img.getHeight(), 0, 0, new int[]{0, 1, 2});

        // create a ColorModel that represents the one of the ARGB except the alpha channel
        final DirectColorModel cm = (DirectColorModel) img.getColorModel();
        final DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());

        // now create the new buffer that we'll use to write the image
        return new BufferedImage(newCM, newRaster, false, null);

Unfortunately, I can't say I understand exactly what it does ;)

+3  A: 

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);
Lana
This method worked for me. Quite a bit simpler than the others, too.
jacobko