2009-01-21 75 views
19

我想使用Java将gif图像转换为jpeg。它的工作原理非常适合大多数图像,但我有一个简单透明的gif图片:使用java将透明gif/png转换为jpeg

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

[如果图像是缺少:这是一个蓝色圆圈与它周围的透明像素]

当我转换此图像使用下面的代码:

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

此代码的工作没有出现任何的异常,但结果无效的jpeg图像:

Output jpeg image http://img297.imageshack.us/img297/3493/indexedtest1qe5.jpg

[万一图像丢失:IE不能显示JPEG,火狐示出了具有无效颜色的图像。]

我使用的Java 1.5。

我也尝试将示例gif转换为png与gimp并使用png作为Java代码的输入。结果是一样的。

它是JDK中的错误吗?我怎样才能正确地转换图像,最好没有第三方库?

UPDATE:

答案表明,JPEG转换不能正确处理透明度(我仍然认为这是一个错误),并提出与预定义的颜色替换透明像素的解决方法。这两种建议的方法都非常复杂,所以我实现了一个更简单的方法(将发布为答案)。我接受使用此解决方法发布的第一个答案(由Markus提供)。我不知道哪个实施更好。我去了最简单的一个,我仍然发现它不工作的gif。

回答

1

JPEG不支持透明度。所以,即使您正确地获取圆圈颜色,仍然会有黑色或白色背景,具体取决于您的编码器和/或渲染器。

+0

黑色或白色(优选可配置的)背景将是对我接受的。但目前代码创建无效图像。 – asalamon74 2009-01-21 11:17:09

+0

是的,当前的代码不会自动将透明转换为白色(或黑色或其他),它不会抛出任何异常,并且不会创建有效的JPEG。创建的JPEG不是真的有效,我的Android手机在处理它们时遇到了一些麻烦(我正在开发一个web服务器<-> android客户端环境)。 – Spidey 2011-02-22 18:52:58

4

这个问题(至少在png转换为jpg时)是配色方案不一样,因为jpg不支持透明度。

我们已经成功地做的是沿着这些线路的东西(这是从不同的代码位拉 - 所以请原谅格式的粗陋):

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

这适用于巴纽JPG和GIF到JPG。你会有一个透明位的白色背景。你可以通过让g2在drawImage调用之前用另一种颜色填充图像来改变它。

8

正如我已经实现与预定义的颜色替换透明像素的更简单的方法问题的更新已经提到:

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

,我叫JPEG转换之前,此方法是这样的:

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

Rad。非常感谢! – JamesD 2011-04-14 20:50:43

+2

这个更简单的方法消耗的内存是否比接受的答案多一倍? – 2013-04-25 11:05:47

4

3个月后,但我有一个非常类似的问题(虽然甚至没有加载gif,但只是生成一个透明的图像 - 比如说,没有背景,一个彩色的形状 - 当保存到jpeg时,所有的颜色都是混乱的不仅是背景)

发现在this rather old thread of the java2d-interest list这段代码,想我会分享,因为快速测试后,它是超过您的解决方案高性能:

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

不幸的是,我不能说我了解正是它做什么;)

+1

The line `final DirectColorModel cm =(DirectColorModel)img.getColorModel();` 似乎是不可能的转换 - ColorModel无法转换为DirectColorModel(我试过代码并在运行时得到了转换异常) – 2012-07-12 21:17:40

41

对于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); 
3

如果您创建BufferedImage.TYPE_INT_ARGB类型的BufferedImage并保存为JPEG,则会导致出现奇怪的情况。在我的情况下,颜色呈橙色。在其他情况下,生成的图像可能无效,其他读者将拒绝加载它。

但是,如果你创建一个类型BufferedImage.TYPE_INT_RGB的图像,然后将其保存为JPEG工作正常。

我想,因此,这是在Java中的JPEG图像作家的错误 - 它应该只写什么它可以在不透明度(像什么.NET GDI +不)。或者在最坏的情况下抛出一个有意义的信息例外。 “不能写出具有透明度的图像”。

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