Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QImageReader second read() results in empty image



  • Hallo,

    I currently implementing a map viewer utilizing QImageReader. Everything works well until i call the read() method a second time.

    QImageReader reader( "../../../../in/image.jpg");
    reader.setClipRect(QRect(0, 0, 1500, 800));
    reader.canRead(); //returns true
    
    QImage image = reader.read();
    

    up to now everything works well.

    reader.device()->seek(0); 
    reader.setClipRect(QRect(0, 0, 500, 400));
    reader.canRead(); // returns false
    
    QImage temp_image = reader.read(); // null image
    

    The second read() call results in a null image. I already tried to fix the problem reseting the handler using reader.device()->seek(0);
    But the result was the same - no image.

    Calling error() or errorString() before the second call of read() always returns "Unknown error". After the second read() call the method returns "Unable to read image data".

    I working with:
    Qt 5.12.0
    Qt Creator 4.8.0
    macOS 10.14

    Thanks



  • @MichMich
    For a start check the return result of reader.device()->seek(0). Though if it returns false I don't know what you're going to do about it.

    Since your question has gone unanswered, unless you want to look through the QImageReader (QImageIOHandler) source code, you may have to guess that it's not aware of your "seek" alteration, e.g. perhaps

    Note: QImageReader assumes exclusive control over the file or device that is assigned. Any attempts to modify the assigned file or device during the lifetime of the QImageReader object will yield undefined results.

    and perhaps create a new QImageReader off the file again instead.


  • Lifetime Qt Champion

    @MichMich
    Hi
    You could also try setFileName
    It might reset state of the reader.



  • Hallo, thank's for the response.

    @JonB
    reader.device()->seek(0) returns true, it sets the position correctly to 0, i checked the previouse value.
    I also tried to debug into the QImageReader source but i couldn't jump into the source. I mapped the debug path to the Qt sources, but this also doesn't work. I am currently building Qt from source to check if i can debug the reader.

    According to the error message i assume that the problem occurs in the row 1313: !d->handler->read(image).

    @mrjj
    Calling setFileName() before the second read everything works as expected. I receive an image.
    This could be a possible solution, but i am afraid that it could be adversely to the performance calling setFileName() repetitive. Each call will delete the old IODevice object and create a new one.

    Some background to my tool:
    My map viewer should be able to load large images. Also i have enough RAM and loading 1GB images should be now problem (but i didn't tested it up to now), i want to allow to load even larger images if necessary. I use setClipRect() to get a part of the image. If the user pans the image i want to dynamically load the according part of the image shifted by a delta. But i think i have to try calling setFileName() repetitive and check the performance.

    Or does someone have another advice?



  • @MichMich
    I do not know why the code fails to re-load. But given where you are now, although resetting the filename does indeed create a new QImageReader (which then works) with some overhead, on the grand scale of things if you are going to be loading 1GB+ from disk the time to do that should way outweigh any time to re-open the file, so you may have to live with it. Make sure if you do that the previous QImageReader with its image gets disposed properly so that it does not retain any memory footprint.


  • Qt Champions 2019

    Strange - looks like a jpg problem

    QImageReader reader("qticon64.jpg");
    //QImageReader reader("qticon64.png");
    reader.setClipRect(QRect(0, 0, 32, 32));
    qDebug() << "can read 1:" << reader.canRead();
    QImage image = reader.read();
    qDebug() << image;
    reader.device()->seek(0);
    qDebug() << "can read 2:" << reader.canRead();
    image = reader.read();
    qDebug() << image;
    

    Using a png file works ...



  • @Christian-Ehrlicher
    FYI, https://trac.ffmpeg.org/ticket/6113 reports this issue for "JPEG file seek". Though whether that's a red-herring or of some indicative interest I don't know....


  • Qt Champions 2019

    The Qt internal QJpegHandler simply can't read a file twice due to it's internal state handling - after the image was read, the state is ReadingEnd which prevents a further re-read. Since there is also no chance to get a signal when the device read pointer was (re)set I don't see an easy way to fix it.

    --> https://code.woboq.org/qt5/qtbase/src/plugins/imageformats/jpeg/qjpeghandler.cpp.html#_ZNK12QJpegHandler7canReadEv



  • I see, so the easiest way and best option according to the performance is to change from jpg files to png files.

    I already checked it out and it works as assumed.

    Thank you all for your help. I will mark the topic as solved.


Log in to reply