GIF image becomes wrong after ImageIO read() and write() operations
我有这个代码。 它只是读取一个GIF文件,使用背景重绘该文件并输出到新的GIF文件。
问题是结果文件变得奇怪。 我不知道为什么它质量会变差。 JPG文件上不会发生此问题。 如何解决?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class ImageTest { public static void main(String[] args) { f(); } private static final String EXTENSION ="gif"; private static final String FILENAME ="pinkHeart"; private static final String PATH ="/Users/hieugioi/Downloads/"; public static void f() { File file = new File(PATH + FILENAME +"." + EXTENSION); try { final BufferedImage originalImage = ImageIO.read(file); int imageType = getImageType(originalImage); final BufferedImage buff = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), imageType); final Graphics2D g = buff.createGraphics(); Color backgroundColor = Color.GRAY; g.setColor(backgroundColor); g.fill(new Rectangle(0, 0, buff.getWidth(), buff.getHeight())); g.drawImage(originalImage, null, 0, 0); File out = new File(PATH + FILENAME +"Out." + EXTENSION); ImageIO.write(buff, EXTENSION, out); } catch (IOException e) { e.printStackTrace(); } } public static int getImageType(BufferedImage img) { int imageType = img.getType(); if (imageType == BufferedImage.TYPE_CUSTOM) { if (img.getAlphaRaster() != null) { imageType = BufferedImage.TYPE_INT_ARGB_PRE; } else { imageType = BufferedImage.TYPE_INT_RGB; } } else if (imageType == BufferedImage.TYPE_BYTE_INDEXED && img.getColorModel().hasAlpha()) { imageType = BufferedImage.TYPE_INT_ARGB_PRE; } return imageType; } } |
输入图像(pinkHeart.gif):
输出图像(pinkHeartOut.gif):
更新案例2
输入图像(example.gif):
输出图像(exampleOut.gif):输出的黄色完全消失!
这里有两个独立的问题。
首先是假设您的输入图像具有透明度。据我所知,它们没有。因此,在两种情况下,背景都不会变为灰色,而是保持纯白色。这没有什么错,但也许不是您的预期/期望。
另一个("实际"问题)是
第二个输入图像的"问题"根本不是
通过在返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public static int getImageType(BufferedImage img) { int imageType = img.getType(); switch (imageType) { case BufferedImage.TYPE_CUSTOM: if (img.getAlphaRaster() != null) { imageType = BufferedImage.TYPE_INT_ARGB_PRE; } else { imageType = BufferedImage.TYPE_INT_RGB; } break; case BufferedImage.TYPE_BYTE_BINARY: // Handle both BYTE_BINARY (1-4 bit/pixel) and BYTE_INDEXED (8 bit/pixel) case BufferedImage.TYPE_BYTE_INDEXED: if (img.getColorModel().hasAlpha()) { imageType = BufferedImage.TYPE_INT_ARGB_PRE; } else { // Handle non-alpha variant imageType = BufferedImage.TYPE_INT_RGB; } break; } return imageType; } |
PS:这是一种替代方法,可避免完全创建原始图像副本的问题,并且速度更快,并且可以节省内存。它应该与您上面的代码意图完全相同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class ImageTest2 { public static void main(String[] args) throws IOException { f(new File(args[0])); } static void f(File file) throws IOException { BufferedImage image = ImageIO.read(file); // TODO: Test if image has transparency before doing anything else, // otherwise just copy the original as-is, for even better performance Graphics2D g = image.createGraphics(); try { // Here's the trick, with DstOver we'll paint"behind" the original image g.setComposite(AlphaComposite.DstOver); g.setColor(Color.GRAY); g.fill(new Rectangle(0, 0, image.getWidth(), image.getHeight())); } finally { g.dispose(); } File out = new File(file.getParent() + File.separator + file.getName().replace('.', '_') +"_out.gif"); ImageIO.write(image,"GIF", out); } } |
我认为这是最好的方法。详情
1 2 3 4 5 6 7 8 9 10 11 | BufferedImage src1 = ImageIO.read(new File("test.jpg")); BufferedImage src2 = ImageIO.read(new File("W.gif")); AnimatedGifEncoder e = new AnimatedGifEncoder(); e.setRepeat(0); e.start("laoma.gif"); e.setDelay(300); // 1 frame per sec e.addFrame(src1); e.setDelay(100); e.addFrame(src2); e.setDelay(100); e.finish(); |
我目前没有Java,但我认为您应该使用BufferedImage的ColorModel。
色彩模型