Search code examples
linuxqtqt5qpixmapqbytearray

In Memory QFile with fwrite


Rather than going to the filesystem to save and read back a PGM image file, I want to do this in memory. Can I somehow use a QBuffer as an in memory QFile to bypass saving to the filesystem:

            QFile filename(QString("/home/pi/frame-%1.pgm").arg(i));
            bool didOpen = filename.open(QIODevice::ReadWrite);
            qDebug() << "Did open file: " << didOpen << filename.fileName();
            int fileHandle = filename.handle();
            FILE * f = fdopen(dup(fileHandle), "wb");
            int res = fprintf(f, "P5 %d %d 65535\n", w, h);
            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
                    uint16_t v = img[y*w+x];
                    //v = htobe16(v);
                    res = fwrite((uint8_t*)&v, sizeof(uint16_t), 1, f);
                }
            }
            fclose(f);

            QPixmap pixmap;
            bool didLoad = pixmap.load(QString("/home/pi/frame-%1.pgm").arg(i));
            emit updateScreen(pixmap);

Solution

  • Actually, yes.

    You already have most of your data ready. We just need to turn it into a format that QPixmap can read directly. For that we use the QPixmap(const char *const[] xpm) constructor to make a pixmap from memory. By happy coincidence this constructor takes an array of pointers, not a straight array, which saves having to copy the bitmap data!

    Untested code:

    char *lines[] = (char **)malloc(sizeof(char *) * h + 1); // 1 extra for the header
    char header[100]; 
    sprintf(header, "P5 %d %d 65535\n", w, h);
    lines[0] = header;
    for (int y = 0; y < h; y++) {
       lines[y + 1] = (char *)&img[y * w]; // note y+1 offset
    }
    
    QPixmap pixmap(lines);
    emit updateScreen(pixmap);
    free(lines);
    

    Note: sizeof(char *) returns the size of a char pointer, so in the first line we allocate an array of pointers of h lines + 1 for the header. After setting the first "line" of the array to the header we copy the address offsets of your img memory block in the remaining "lines" and feed it to QPixmap. After that we're done.