1

I want to extract gif frames to raw BGRA data, I used giflib to parse format. I've got first frame (I suppose it's like a key frame in video) that looks good and second (it's 15 frames actually, but let's simplify it) that looks like diff frame. Here is samples:

key frame diff frame

It seems to be simple to restore second full frame using diff data, but here is the problem: I have no idea what color index means "Not changed". Black pixels on diff frame is actually black – its index in color map is 255, which is rgb(0,0,0). I printed whole color table and didn't found any other black entries. It's here if interested. "BackgroundColor" index is 193, so it makes no sense either.

So, I can't separate "black" color from "no" color. What if second frame will really contain some new black pixels (it contains indeed because left eye moves on animation)? But program should handles it differently: get previous frame color for "no" color and get rgb(0,0,0) for "black" color.

UPD: here is my code. Subframes handling and memory cleanup is ommited. Here I supposed that "no" color index is last in colortable. It works actually for my test file, but I'm not sure it will work in general.

    DGifSlurp(image);
    int* master = malloc(image->SWidth * image->SHeight * sizeof(int));
    for (int i = 0; i < image->ImageCount; i++) {
        SavedImage* frame = &image->SavedImages[i];

        ColorMapObject* cmap = frame->ImageDesc.ColorMap ? frame->ImageDesc.ColorMap : image->SColorMap;

        int nocoloridx = cmap->ColorCount - 1;

        IplImage* mat = cvCreateImage(cvSize(frame->ImageDesc.Width, frame->ImageDesc.Height), IPL_DEPTH_8U, 4);
        mat->imageData = malloc(frame->ImageDesc.Width * frame->ImageDesc.Height * 4);

        for (int y = 0; y < frame->ImageDesc.Height; y++)
        for (int x = 0; x < frame->ImageDesc.Width; x++) {
            int offset = y * frame->ImageDesc.Width + x;
            int coloridx = frame->RasterBits[offset];
            if (coloridx == nocoloridx) {
                coloridx = master[offset];
            } else {
                master[offset] = coloridx;
            }
            GifColorType color = cmap->Colors[coloridx];
            cvSetComponent(mat, x, y, 0, color.Blue);
            cvSetComponent(mat, x, y, 1, color.Green);
            cvSetComponent(mat, x, y, 2, color.Red);
            cvSetComponent(mat, x, y, 3, 100);
        }

        cvNamedWindow("t", CV_WINDOW_AUTOSIZE);
        cvShowImage("t", mat);
        cvWaitKey(0);
    }
Tommi
  • 3,199
  • 1
  • 24
  • 38
  • 2
    Have you looked at http://giflib.sourceforge.net/gif_lib.html#idp49251024 ? Should give you the index of the transparent color, if any. – Hasturkun Nov 16 '14 at 15:33
  • I used giflib installed via homebrew, it's 4th branch, while extensions reader implemented in 5th version, if doc is correct. You sure that transparent color index is what I'm looking for? File may not contain transparency at all, but still can have animation with diff-compression. – Tommi Nov 16 '14 at 15:44
  • @Hasturkun It looks like you're right. For example, [here](http://en.wikipedia.org/wiki/Graphics_Interchange_Format#Animated_GIF) is header of animated gif with transparency flag == 0 and no transparent color specified. I parsed it with giflib, and every frame in it seems to be full (key) frame – not only still pixels, but animated right side of Earth too. The only thing is to get transparency key in giflib 4, but it's not related to this question. Feel free to post answer, I'll mark it as correct. – Tommi Nov 16 '14 at 16:03
  • I'm wrong, this isn't (only) about transparency. See [this](http://giflib.sourceforge.net/whatsinagif/animation_and_transparency.html) as well. You need to combine the disposal method, the offset of the frame (which you should be able to get from `frame->ImageDesc->Top` and `Left`, also has `Width` and `Height` which you'll need), and also transparency. I've tried none of this, I'm just reading the documentation (which is why I won't be posting this as an answer. I can't test anything atm) – Hasturkun Nov 16 '14 at 16:11
  • I have read this, and I know about top/left, I implemented it, but ommited in pasted code. But I completely missed the part with disposal method. I upgraded giflib to 5.0.5 and will dig further. Thanks for your help. – Tommi Nov 16 '14 at 16:18
  • @Tommi did you by chance figure this out? And do you mind sharing the answer? – Vahagn Tumanyan Aug 03 '16 at 11:45
  • @VahagnTumanyan not really. Not with `giflib`. In the end I used perfect `freeimage` library, which supports gif as well as many other formats. To restore full frame from diff I used [this code](https://github.com/tommiv/ngx_http_imgproc/blob/master/advancedio.c#L219). Whole function is pretty big and this if branch still contains a couple of todos, but I belive this could be your starting point. In a few words it replaces transparent pixels with color from previous restored frame, depeding on current frame' disposal method. – Tommi Aug 03 '16 at 15:34
  • I got a bit lost in your notations. So if disposal mode is background you just fill the static part of the the frame you want to extract as the background color. If it says do not dispose, the giflib documentation says that TOP and LEFT of the frame give you the smallest changing rectangle in the frame. But in your example and in my case the black regions are definitely not rectangular. – Vahagn Tumanyan Aug 03 '16 at 15:49
  • Disposal method is a part of GIF specs. Basically it says how to restore current frame from previous frames stream. "Not key" frames can be subarea of keyframe, indeed. In this case you should just copy whole pixels of untouched area from previous frame and process only that region which stored in current frame. In my implementation (if I remember it correctly) I fill outer area with transparency key first, so current frame will automatically replace it with master color on restore, but you can do as you wish. – Tommi Aug 03 '16 at 16:00

0 Answers0