ImJustACowLol
ImJustACowLol

Reputation: 951

Java: Splitting .GIF image in BufferedImages Gives Malformed Images

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:

Input gif

Example of malformed output image (the 3rd frame in the gif):

Malformed image

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

Answers (2)

Joop Eggen
Joop Eggen

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

ImJustACowLol
ImJustACowLol

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

Related Questions