简体   繁体   English

使用java将透明的gif/png转换为jpeg

[英]Converting transparent gif / png to jpeg using java

I'd like to convert gif images to jpeg using Java.我想使用 Java 将 gif 图像转换为 jpeg。 It works great for most images, but I have a simple transparent gif image:它适用于大多数图像,但我有一个简单的透明 gif 图像:

Input gif image http://img292.imageshack.us/img292/2103/indexedtestal7.gif 输入 gif 图片 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:此代码在不引发异常的情况下工作,但会导致无效的 jpeg 图像:

输出 jpeg 图像

[In case the image is missing: IE cannot show the jpeg, Firefox shows the image with invalid colors.] [如果图像丢失:IE 无法显示 jpeg,Firefox 会显示颜色无效的图像。]

I'm using Java 1.5.我正在使用 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.我还尝试使用 gimp 将示例 gif 转换为 png,并使用 png 作为 Java 代码的输入。 The result is the same.结果是一样的。

Is it a bug in the JDK?这是JDK中的错误吗? How can I convert images correctly preferably without 3rd party libraries?如何在没有 3rd 方库的情况下正确转换图像?

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.答案表明 jpeg 转换无法正确处理透明度(我仍然认为这是一个错误),并建议使用预定义颜色替换透明像素的解决方法。 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).我接受此解决方法的第一个已发布答案(由 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.我选择了最简单的一个,但我仍然找到了一个无法正常工作的 gif。

For Java 6 (and 5 too, I think):对于 Java 6(我认为也是 5):

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);

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:我以这种方式在 jpeg 转换之前调用此方法:

if( inputImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
    inputImage = fillTransparentPixels(inputImage, Color.WHITE);
}

The problem (at least with png to jpg conversion) is that the color scheme isn't the same, because jpg doesn't support transparency.问题(至少对于 png 到 jpg 的转换)是配色方案不一样,因为 jpg 不支持透明度。

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.这适用于 png 到 jpg 和 gif 到 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.您可以通过在调用 drawImage 之前让 g2 用另一种颜色填充图像来更改此设置。

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)晚了 3 个月,但我遇到了一个非常相似的问题(虽然甚至没有加载 gif,但只是生成了一个透明图像——比如,没有背景,一个彩色的形状——当保存到 jpeg 时,所有的颜色都搞砸了,不仅背景)

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:发现这段代码在这个相当古老的Java2D的利息清单的线程,想我会分享,因为快速测试后,它比你的解决方案高性能:

        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 ;)不幸的是,我不能说我完全理解它的作用;)

If you create a BufferedImage of type BufferedImage.TYPE_INT_ARGB and save to JPEG weird things will result.如果你创建一个 BufferedImage.TYPE_INT_ARGB 类型的 BufferedImage 并保存到 JPEG 会导致奇怪的事情。 In my case the colors are scewed into orange.在我的情况下,颜色被扭曲成橙色。 In other cases the produced image might be invalid and other readers will refuse loading it.在其他情况下,生成的图像可能无效,其他读者将拒绝加载它。

But if you create an image of type BufferedImage.TYPE_INT_RGB then saving it to JPEG works fine.但是,如果您创建 BufferedImage.TYPE_INT_RGB 类型的图像,则将其保存为 JPEG 可以正常工作。

I think this is therefore a bug in Java JPEG image writer - it should write only what it can without transparency (like what .NET GDI+ does).因此,我认为这是 Java JPEG 图像编写器中的一个错误 - 它应该只编写它可以不透明的内容(就像 .NET GDI+ 所做的那样)。 Or in the worst case thrown an exception with a meaningful message eg "cannot write an image that has transparency".或者在最坏的情况下抛出一个带有有意义消息的异常,例如“无法编写具有透明度的图像”。

JPEG has no support for transparency. JPEG 不支持透明度。 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.因此,即使您正确获得圆圈颜色,您仍然会有黑色或白色背景,具体取决于您的编码器和/或渲染器。

BufferedImage originalImage = ImageIO.read(getContent());
BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);

    for (int x = 0; x < originalImage.getWidth(); x++) {
        for (int y = 0; y < originalImage.getHeight(); y++) {
            newImage.setRGB(x, y, originalImage.getRGB(x, y));
        }
    }
 ImageIO.write(newImage, "jpg", f);

7/9/2020 Edit: added imageIO.write 7/9/2020编辑:添加imageIO.write

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM