0

I'm trying to use freeimage library to decode images, do some processing in opencv and encode it back. For now I trying to parse GIF files. Pixels data looks ok, I'm able to convert palette to rgb24, create IplImage and show it in highgui window.

The problem is with metatada. GIF files contains some info about how animation should run. Here I got disposal method for every frame, and stored it in array to compile resulting GIF later, on encode stage:

FITAG* tag;
int res = FreeImage_GetMetadata(FIMD_ANIMATION, frame, "DisposalMethod", &tag);
int* dispose = FreeImage_GetTagValue(tag);
// dispose[frameid] = *dispose; // <- problem with this line

Code runs ok, if commented line remains commented, but if uncomment it, I'll get error

freeimg(15745,0x7fff73f61300) malloc: * error for object 0x100c6e9c0: incorrect checksum for freed object - object was probably modified after being freed. * set a breakpoint in malloc_error_break to debug Program ended with exit code: 9

on 4th (!) frame. In other files current frame number can be 5, 7 etc. I don't even use dispose array yet, it's just stores some ints. How this can affect memory management? Below is complete app code:

#include <stdlib.h>
#include <stdio.h>
#include <FreeImage.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>

#define cvPxAddr(src, x, y, c) (src->widthStep * y + x * src->nChannels + c)
#define cvSetComponent(src, x, y, c, val) (src->imageData[cvPxAddr(src, x, y, c)] = val)
#define cvGetRawComponent(src, x, y, c) (src->imageData[cvPxAddr(src, x, y, c)])
#define cvGetComponent(src, x, y, c) ((u_char)cvGetRawComponent(src, x, y, c))

int main(int argc, const char * argv[]) {
    FIMULTIBITMAP* container = FreeImage_OpenMultiBitmap(FIF_GIF, "file.gif", 0, 1, 1, 0);

    int framecount = FreeImage_GetPageCount(container);

    char* winname = "Result";
    cvNamedWindow(winname, CV_WINDOW_AUTOSIZE);

    int* dispose = malloc(framecount * sizeof(int));

    for (int frameid = 0; frameid < framecount; frameid++) {
        FIBITMAP* frame = FreeImage_LockPage(container, frameid);

        int w = FreeImage_GetWidth(frame);
        int h = FreeImage_GetHeight(frame);
        int scan_width = FreeImage_GetPitch(frame);

        FITAG* tag;
        int res = FreeImage_GetMetadata(FIMD_ANIMATION, frame, "DisposalMethod", &tag);
        int* dispose = FreeImage_GetTagValue(tag);
        dispose[frameid] = *dispose; // <- commenting this line solves problem

        RGBQUAD* palette = FreeImage_GetPalette(frame);
        int transparencykey = FreeImage_GetTransparentIndex(frame);

        IplImage* image = cvCreateImageHeader(cvSize(w, h), IPL_DEPTH_8U, 4);
        image->imageData = malloc(w * h * 4);

        for (int y = 0; y < h; y++) {
            unsigned char* row = FreeImage_GetScanLine(frame, h - y);
            for (int x = 0; x < w; x++) {
                int coloridx = row[x];
                RGBQUAD color = palette[coloridx];
                cvSetComponent(image, x, y, 0, color.rgbBlue);
                cvSetComponent(image, x, y, 1, color.rgbGreen);
                cvSetComponent(image, x, y, 2, color.rgbRed);
                cvSetComponent(image, x, y, 3, coloridx == transparencykey ? 0 : 255);
            }
        }

        cvShowImage(winname, image);
        cvWaitKey(120);

        free(image->imageData);
        cvReleaseImageHeader(&image);

        FreeImage_UnlockPage(container, frame, 0); // <- here I got exception on nth frame
    }

    free(dispose);

    cvDestroyAllWindows();
    FreeImage_CloseMultiBitmap(container, 0);
    return 0;
}
Tommi
  • 3,199
  • 1
  • 24
  • 38
  • Check your return values, make sure to set `tag` to `NULL` before calling `FreeImage_GetTagValue`, then make sure it is valid after calling. Turn on more compiler warnings. `FreeImage_GetTagValue` actually returns an int pointer? Also make sure that pointer is also valid before trying to use it. – Chris O Nov 20 '14 at 11:54
  • Oh. It was me. `int* dispose = malloc(framecount * sizeof(int));` and `int* dispose = FreeImage_GetTagValue(tag);` should be different variables with different names. I don't get why compiler don't breaks with redefinition exception, but renaming second variable to disposeval solved issue. – Tommi Nov 20 '14 at 11:59
  • Good catch, the best practice here is: turn on all compiler warnings to highest levels, and treat them as errors. – Chris O Nov 20 '14 at 12:02
  • Thanks, somehow redefinition is a warning indeed, not an error. – Tommi Nov 20 '14 at 12:03
  • @Tommi: It's not an error because the `dispose` inside the nested scope _hides_ or _shadows_ the other variable in the outer scope. It's legal code but a bad practice. [See this related question.](http://stackoverflow.com/questions/958625/in-c-when-can-two-variables-of-the-same-name-be-visible-in-the-same-scope) – Blastfurnace Nov 20 '14 at 12:07
  • @Blastfurnace, thanks, now it makes perfect sense. I should be more careful. – Tommi Nov 20 '14 at 12:19

0 Answers0