c++imageqtqimagefreeimage

Using FreeImage with Qt


I have a piece of C++/Qt code where I want to load images using the FreeImage library (http://freeimage.sourceforge.net/) and store the final result in a QImage. I know that Qt can load a bunch of image formats directly, but I want to be able to load some formats that are not supported by Qt directly... I tried various approaches to get it to work, but none of them work.

Before I show some of my failed attempts, this is the rest of the function that is the same for all of them. The code snippets below are just copy&paste into this function:

QImage load(QString filename) {

    FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename.toStdString().c_str(), 0);
    if(fif == FIF_UNKNOWN)
        fif = FreeImage_GetFIFFromFilename(filename.toStdString().c_str());
    if(fif == FIF_UNKNOWN)
        return QImage();

    FIBITMAP *dib = nullptr;
    if(FreeImage_FIFSupportsReading(fif)) {
        dib = FreeImage_Load(fif, filename.toStdString().c_str());
        if(dib == nullptr)
            return QImage();
    } else
        return QImage();

    .... [conversion code comes here] ....

}

My first two attempts are very similar. The first one tries to load the image into a QImage:

    int width  = FreeImage_GetWidth(dib);
    int height = FreeImage_GetHeight(dib);
    int bpp    = FreeImage_GetBPP(dib);
    int size   = width * height * (bpp / 8);

    BYTE *pixels = FreeImage_GetBits(dib);

    QImage img;
    img = img.fromData(pixels, size);
    return img;

The second one does more or less the same, but with a QPixmap:

    int width  = FreeImage_GetWidth(dib);
    int height = FreeImage_GetHeight(dib);
    int bits   = FreeImage_GetBPP(dib);
    int size   = width * height * (bits / 8);

    BYTE *pixels = FreeImage_GetBits(dib);

    QPixmap pix;
    pix.loadFromData(pixels,size);
    return pix.toImage();

My third attempt was to try to get FreeImage to save the image to memory as JPEG and then load it into a QByteArray before constructing the image:

    FIMEMORY *stream = FreeImage_OpenMemory();
    FreeImage_SaveToMemory(FIF_JPEG, dib, stream);
    FreeImage_Unload(dib);
    long size = FreeImage_TellMemory(stream);

    QByteArray array = QByteArray::fromRawData((char*)stream->data, size);
    QImage img;
    img.loadFromData(array);
    return img;

None of these attempts work. I checked to see if it fails earlier, but it doesn't return any error until the very end when I obtain a NULL image. However, I am not sure if I am even thinking about it the right way... Anybody got any ideas/hints what I could try?


Solution

  • Okay, I actually ended up solving it myself :)

    The solution is somewhat similar to my last attempt, it involves saving the loaded image to memory (after ensuring it is a 24bit image) and "acquiring" the memory (still with FreeImage) after which it can be loaded into a QByteArray ready to read in by QImage:

    QImage load(QString filename) {
    
        // Get image format
        FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename.toStdString().c_str(), 0);
        if(fif == FIF_UNKNOWN)
            fif = FreeImage_GetFIFFromFilename(filename.toStdString().c_str());
        if(fif == FIF_UNKNOWN)
            return QImage();
    
        // Load image if possible
        FIBITMAP *dib = nullptr;
        if(FreeImage_FIFSupportsReading(fif)) {
            dib = FreeImage_Load(fif, filename.toStdString().c_str());
            if(dib == nullptr)
                return QImage();
        } else
            return QImage();
    
        // Convert to 24bits and save to memory as JPEG
        FIMEMORY *stream = FreeImage_OpenMemory();
        // FreeImage can only save 24-bit highcolor or 8-bit greyscale/palette bitmaps as JPEG
        dib = FreeImage_ConvertTo24Bits(dib);
        FreeImage_SaveToMemory(FIF_JPEG, dib, stream);
    
        // Free memory
        FreeImage_Unload(dib);
    
        // Load JPEG data
        BYTE *mem_buffer = nullptr;
        DWORD size_in_bytes = 0;
        FreeImage_AcquireMemory(stream, &mem_buffer, &size_in_bytes);
    
        // Load raw data into QImage and return
        QByteArray array = QByteArray::fromRawData((char*)mem_buffer, size_in_bytes);
        return QImage::fromData(array);
    
    }