Reputation: 951
So I have a very small piece of code, which takes a .gif image as input, and then it splits this .gif image into an array of BufferedImage. After that, it stores the images in the array on the disk. When I do this, the output images contain heavy white-pixel noise which isn't visible in the input .gif image.
Example of the input gif:
Example of malformed output image (the 3rd frame in the gif):
The code I am using to split the gif is as follows:
public static void main(String[] args) throws Exception {
splitGif(new File("C:\\test.gif"));
}
public static void splitGif(File file) throws IOException {
ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next(); reader.setInput(ImageIO.createImageInputStream(new FileInputStream(file)), false);
for(int i = 0; i < reader.getNumImages(true); i++) {
BufferedImage image = reader.read(i);
ImageIO.write(image, "PNG", new File(i + ".png"));
}
}
Can anyone help me out?
Upvotes: 0
Views: 1028
Reputation: 109603
You solved it yourself, but for good order: every next frame is the accumulation of all prior frames filling up the transparent pixels in the current frame.
public static void splitGif(File file) throws IOException {
ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
reader.setInput(ImageIO.createImageInputStream(new FileInputStream(file)), false);
BufferedImage outImage = null;
Graphics2D g = null;
for (int i = 0; i < reader.getNumImages(true); i++) {
BufferedImage image = reader.read(i);
if (g == null) {
BufferedImage outImage = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
g = (Graphics2D) outImage.getGraphics();
}
g.drawImage(lastImage, 0, 0, null);
ImageIO.write(outImage, "PNG", new File(i + ".png"));
}
if (g != null) {
g.dispose();
}
}
getGraphics==createGraphics
should be balanced be a dispose
as documented.Upvotes: 1
Reputation: 951
So the problem was that when reading .gif files into java, then all pixels in a given frame that did not change color compared to their previous frame will be fully transparent. If you want to read a .gif and split it in an array of properly rendered BufferedImages, then you have to fill the transparent pixels of the current frame with the last non-transparent pixel of one of the previous frames.
Code:
public static void splitGif(File file) throws IOException {
ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
reader.setInput(ImageIO.createImageInputStream(new FileInputStream(file)), false);
BufferedImage lastImage = reader.read(0);
ImageIO.write(lastImage, "PNG", new File(0 + ".png"));
for (int i = 1; i < reader.getNumImages(true); i++) {
BufferedImage image = makeImageForIndex(reader, i, lastImage);
ImageIO.write(image, "PNG", new File(i + ".png"));
}
}
private static BufferedImage makeImageForIndex(ImageReader reader, int index, BufferedImage lastImage) throws IOException {
BufferedImage image = reader.read(index);
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
if(lastImage != null) {
newImage.getGraphics().drawImage(lastImage, 0, 0, null);
}
newImage.getGraphics().drawImage(image, 0, 0, null);
return newImage;
}
Upvotes: 2