tags:

views:

303

answers:

3

I need to examine a gif image in a C program. I looked into the FreeImage library but I can't figure it out. Could someone give an example of using FreeImage to get into all the little details about a gif image such as frames, background, transparency, etc... And how to increment through the frames and get the animation's current image/pixels. The problem I'm having is that you load the image into a FIMULTIBITMAP type, while most of the functions take a FIBITMAP type. I'm not seeing how you're supposed to use the library with gifs.

Also, is there a simpler library?

Ferruccio said to use libGD. Here's what I found with this library.

/* These read the first frame only */
BGD_DECLARE(gdImagePtr) gdImageCreateFromGif (FILE * fd);

I need all of the frames.

Below is kind of working. The problem is the image's width/height change to be smaller than the actual image. I think it's just showing what changed, but I'm not sure how to map that back onto the original image to make any use of it. Here's the Gif File.

Actually this library's not working like I assume it's supposed to work. For instance, I can't get the palette for the image. What I get is all zeros. Any suggestions on that?

#include <stdio.h>
#include <string.h>
#include <FreeImage.h>

int main(int argc, char *argv) {
        FIMULTIBITMAP *src;
        src = FreeImage_OpenMultiBitmap(FIF_GIF, "clock_logo_ani.gif", FALSE, TRUE, FALSE, GIF_DEFAULT);

        int count = FreeImage_GetPageCount(src);
        int page, i, row, col, background, transparent;
        RGBQUAD bkcolor;
        BYTE pixel;

        char buffer[25*16 + 16];

        RGBQUAD *palette;

        background = 0;
        for(page = 0; page < count; page++) {
            FIBITMAP *dib = FreeImage_LockPage(src, page);
            if(dib) {
                printf("%dx%d\n", FreeImage_GetHeight(dib), FreeImage_GetWidth(dib));
                FreeImage_GetBackgroundColor(dib, &bkcolor);
                background = (&bkcolor)->rgbReserved;
                transparent = FreeImage_GetTransparentIndex(dib);
                memset(buffer, ' ', sizeof(char) * 24 * 16 + 17 * sizeof(char));
                for( row = 0; row < 16; row++ ) {
                        for( col = 0; col < 24; col++ ) {
                                if ( FreeImage_GetPixelIndex(dib, col, row, &pixel) ) {
                                        if((int)pixel != 0)
                                                buffer[row * 25 + col] = '.';
                                }

                        }
                }
                for (row = 0; row < 16; row++)
                        buffer[row * 25 + 25] = '\n';
                buffer[row * 25] = '\0';
                printf("-----\n%s\n-----\n", buffer);
                FreeImage_UnlockPage(src, dib, FALSE);
            }
        }

        FreeImage_CloseMultiBitmap(src, GIF_DEFAULT);
}

Here's the output. Notice how the image's size changes.

16x24
-----
           ...           
        ..   ..         
       .       .        
      .         .       
     .           .      
     .           .      
    .             .     
    .      ...    .     
    .      .      .     
     .     .     .      
     .     .     .      
      .    .    .       
       .       .        
        ..   ..         
          ...           

-----
4x4
-----
 .                       
 .                      
  .                     













-----
4x3
-----
...                      















-----
4x3
-----
  .                      
.                       

.                       












-----
4x4
-----
.                        















-----
4x4
-----


.                       
 .                      












-----
4x4
-----



...                     












-----
4x4
-----

  .                     
 .                      
.                       












-----
A: 

I've had good luck with LibGD.

Ferruccio
I don't think it'll work for my purpose. I've edited the question with the reason.
Scott
A: 

If you are willing to use c++, ImageMagick has bindings to do this. It has a c api, but I don't see any functions to do that.

Todd Gardner
Nah it has to be C. I forgot about ImageMagick. I don't doubt you checked thoroughly, but I'm still checking to see if any of the C bindings will do what I want. :)
Scott
+1  A: 

In the code included in your question, once you lock the page, you can do:

bool isTransparent=FreeImage_IsTransparent(dib);
RGBQUAD* bkcolor;
bool didIGetBackgroundCorrectly=FreeImage_GetBackgroundColor(dib, bkcolor);

The pointer that FreeImage_LockPage gives you is that frame's image. You should be able to use it in any of the other functions that take the FIBITMAP type. (but remember, in the code above, you opened it read-only)

You already know how many frames are in the animation, "count" gives you that. (zero based, of course) It is pretty simple.

R Ubben
Do you know why those frames can be a different size than the actual image? I've updated the question with some new code.
Scott
You should be able to create a frame as a smaller size than the image. A gif optimizer can work by setting the transparency to leave part of the previous frame in place, letting the current frame (a smaller rectangle) overlay only areas that have changed. Look at Wikipedia's entry on Graphics Interchange Format and scroll down to their discussion of the animated GIF file format.
R Ubben
I understood that part, but what I don't understand is how I know what parts of the gif changed to lay the smaller image over.
Scott
Ok, I had to use GIF_PLAYBACK instead of GIF_DEFAULT. Now it gives me the full image.
Scott
What I would do is use Freeimage to do the decoding, but also parse the binary file itself to see where the various frames are located. Look at the Wikipedia article; see starting at byte 0x329 and byte 0x329D? Those tell you where that frame is placed over the image. In the article, frame 1 is a full frame: (0,0) to (400,400). The next frame could contain something like (10,20) to (100,100), meaning frame 2 overlays that rectangular part of the first, and so on.
R Ubben