4

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?

John Wiseman
  • 3,081
  • 1
  • 22
  • 31
Irigum
  • 175
  • 6
  • Have you cross referenced Qt's supported [formats](http://doc.qt.io/qt-5/qimage.html#Format-enum) vs matching formats supported by freeimage? – Steve Lorimer Mar 06 '18 at 21:59
  • That was the thought behind my last attempt, making sure to convert it to JPEG so that Qt can definitely read it... Anyways, I solved it now, see my answer below :) – Irigum Mar 06 '18 at 22:15

1 Answers1

4

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);

}
Irigum
  • 175
  • 6