7

I'm trying to access a animated GIF image with 21 frames and then read the 12th (cause it starts at 0?) frame.

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;

public class PictureSearch {

    public static void search(File file) {
        try {
            ImageReader reader = (ImageReader) ImageIO.getImageReadersBySuffix("gif").next();
            reader.setInput(ImageIO.createImageInputStream(file), false);
            BufferedImage caption = reader.read(12);

            System.out.println(caption.getHeight());
            System.out.println(caption.getWidth());

            caption.flush();

        } catch (IOException e) {
            System.out.println(e);
        }
    }

    public static void main(String[] args) throws IOException {
        List<String> suffixes = new ArrayList<String>();
        suffixes.add(".jpg");
        suffixes.add(".gif");
        suffixes.add(".bmp");
        suffixes.add(".png");

        Iterator<File> files = FileUtils.iterateFiles(new File(
                "F:/test/"), (IOFileFilter) new SuffixFileFilter(
                suffixes), TrueFileFilter.INSTANCE);

        while (files.hasNext()) {
            File file = (File) files.next();
            PictureSearch.search(file);
        }

    }
}

The reader should return me a buffered image with height 220 and width 200 (or height 205 and width 188 if it ignores white fields around the image). But what it does is it returns me a image of height 155 and width 174 what is absurd because i triple checked and the frame 12 is height 220 and width 200. Am I doing everything correctly in reading the frames?

Rihards
  • 10,241
  • 14
  • 58
  • 78
  • 1
    Can you post a link to the `.gif`? An [sscce](http://sscce.org) might help, too. – trashgod Apr 16 '11 at 17:35
  • @trashgod, here it is: http://i55.tinypic.com/263veb9.gif The source code above is basically all the code for reading the animated gif file.. – Rihards Apr 16 '11 at 17:55
  • I'm reading the file from my desktop when the incorrect width & height appear. Do i still need the read progress listener? – Rihards Apr 16 '11 at 17:59
  • @andrew, added sscce to the first post. – Rihards Apr 16 '11 at 18:09
  • @Richards, the solution for correct frame sizes is here - http://stackoverflow.com/questions/8933893/convert-animated-gif-frames-to-separate-bufferedimages-java – Andrey Mormysh Feb 19 '13 at 08:21

2 Answers2

4

The rectangle in your example appears to be a frame representing the changed portion of the image sequence, starting from 1. Open the file in Gimp to see.

enter image description here

Addendum: It looks like a feature intended to optimize rendering. At a guess, I'd say you could rely on the bounds of image number getMinIndex(); later frames appear to be subsumed in the first.

Addendum:

is there a way to get the full pixel data with the normal image and changes?

Assuming known geometry, you should be able to combine the first image and any later one in a BufferedImage, as shown here.

Code:

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;

public class GifBounds {

    /** @see https://stackoverflow.com/questions/5688104 */
    public static void main(String[] args) throws IOException {
        search(new URL("http://i55.tinypic.com/263veb9.gif"));
    }
    public static void search(URL url) throws IOException {
        try {
            ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
            reader.setInput(ImageIO.createImageInputStream(url.openStream()));
            int i = reader.getMinIndex();
            while (true) {
                BufferedImage bi = reader.read(i++);
                System.out.println(i
                    + ": " + bi.getWidth()
                    + ", " + bi.getHeight());
            }

        } catch (IndexOutOfBoundsException e) {
            // ignored
        }
    }
}

Console:

1: 200, 220
2: 79, 95
3: 77, 94
4: 78, 95
5: 79, 95
6: 77, 94
7: 78, 95
8: 79, 95
9: 77, 94
10: 180, 205
11: 97, 111
12: 173, 200
13: 174, 155
14: 174, 155
15: 174, 155
16: 174, 155
17: 174, 155
18: 174, 155
19: 174, 155
20: 167, 200
21: 97, 111
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I did some experiments that support your point. It seems the 12th image in the sequence has smaller Width x Height than the overall GIF. (And I was wrong about the image not being completely loaded.) – Andrew Thompson Apr 16 '11 at 18:49
  • @trashgod, yes indeed, what do you suggest me to do to fix this problem and get the frame and it's height and width correctly? – Rihards Apr 16 '11 at 19:09
  • @Richards: I've elaborated above, but I'd defer to @Andrew Thompson's greater experience in this area. Regarding your [sscce](http://sscce.org), I've eliminated the `apache` dependency in my example. – trashgod Apr 16 '11 at 19:30
  • @Andrew Thompson: I'd welcome your critical thoughts on my approach. In particular, I don't see a way to get the image count except to note the `IndexOutOfBoundsException`. Also, my sscce was based on your canonical example, which I would encourage you to undelete. – trashgod Apr 16 '11 at 19:37
  • @trashgod, also is there a way how to get the full pixel data with the normal image and changes (so i could work with the getRGB) of the frame not only the change region? – Rihards Apr 16 '11 at 19:57
  • @trashgod My e.g. is now reinstated. I have not worked with images with multiple frames in Java before, so I am not sure I can contribute anything beyond what you have discovered. I'll look more closely over your example and the JavaDocs & see if I can come up with anything worth adding. – Andrew Thompson Apr 16 '11 at 20:17
  • @trashgod "I don't see a way to get the image count .." See `ImageReader.getNumImages(true);`. I hacked your source to see it work. Would you like me to edit your example to show my tweaks to your code? ( I'm hoping that you will change it. ;) – Andrew Thompson Apr 16 '11 at 20:27
  • @Andrew Thompson: D'oh! I completely overlooked `getNumImages()`. The API even suggests using the exception under certain circumstances. I think I'll stand pat, as an example of that approach. Could I impose on you to update your answer showing your variation? I can see the value of having both for future reference. I would encourage @Richards to accept either. – trashgod Apr 17 '11 at 01:18
1

Code 1

import java.net.URL;
import java.awt.Image;
import javax.imageio.ImageIO;

class GetGifSize {

    public static void main(String[] args) throws Exception {
        URL urlToImage = new URL("http://i55.tinypic.com/263veb9.gif");
        Image image = ImageIO.read(urlToImage);
        System.out.println( "Image size is " +
            image.getWidth(null) +
            "x" +
            image.getHeight(null) );
    }
}

Output

Image size is 200x220

Code 2

A variant of the code posted by trashgod.

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;

public class GifBounds {

    /** @see http://stackoverflow.com/questions/5688104 */
    public static void main(String[] args) throws IOException {
        search(new URL("http://i55.tinypic.com/263veb9.gif"));
    }
    public static void search(URL url) throws IOException {
        ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
        reader.setInput(ImageIO.createImageInputStream(url.openStream()));
        int i = reader.getMinIndex();
        int offset = i-0;
        int count = reader.getNumImages(true);
        System.out.println("Image count: " + count);
        for (int ii=i; ii<(count-i); ii++) {
            BufferedImage bi = reader.read(ii);
            System.out.println(ii
                + offset
                + ": " + bi.getWidth()
                + ", " + bi.getHeight());
        }
    }
}

As an aside, I think you should mark trashgod's answer correct of the two answers.

It was first to get to the real core of the problem. And you gotta' love an answer with screen-shots. That's going 'the whole 9 yards'.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Yes, simple ImageIO.read() gives me correct height and width too, but I need to access the 12th frame of the animated gif and that gives me not the right height and width. – Rihards Apr 16 '11 at 18:11
  • OK got it. I'll take a closer look at your code and see what I can figure out for getting the correct width/height of the 'Nth' frame. – Andrew Thompson Apr 16 '11 at 18:19
  • +1 I can verify Andrew's sscce, and I can see the 21 frames in `Preview` and `Gimp`. – trashgod Apr 16 '11 at 18:22
  • (moments later) Unfortunately that is not an SSCCE I can run, since I don't have apache commons in my run-time class-path. Also, for an SSCCE, it pays to hot-link to an image on the net, as my example did. Can you correct those two points? – Andrew Thompson Apr 16 '11 at 18:22