Чтение файлов изображений с помощью QImageReader с использованием QtConcurrent

Я пытаюсь использовать QImageReader для чтения частей файла изображения за один раз (для каждого фрагмента), так что для очень больших изображений они не считываются в память с диска, пока они не будут отображаться.

Кажется, что у меня проблемы с потоками.

Это то, что у меня есть:

#include "rastertile.h"

QMutex RasterTile::mutex;
RasterTile::RasterTile()
{
}

//RasterTile::RasterTile(QImageReader *reader, int nBlocksX, int nBlocksY, int xoffset, int yoffset, int nXBlockSize, int nYBlockSize)
RasterTile::RasterTile(QString filename, int nBlocksX, int nBlocksY, int xoffset, int yoffset, int nXBlockSize, int nYBlockSize)

    : Tile(nBlocksX, nBlocksY, xoffset, yoffset, nXBlockSize, nYBlockSize)
{
        this->reader = new QImageReader(filename);
        connect(&watcher,SIGNAL(finished()),this,SLOT(updateSceneSlot()));
}


void RasterTile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
    if(image.isNull())
    {
        TilePainter=painter;
        TileOption=option;
        TileWidget=widget;
        future = QtConcurrent::run(this, &RasterTile::LoadTilePixmap);
        watcher.setFuture(future);

    }else
    {
        QRectF imageRect = image.rect();
        painter->drawImage(imageRect, image);
    }

}

QImage RasterTile::LoadTilePixmap()
{
    QMutexLocker locker(&mutex);

    QImage img(nBlockXSize, nBlockYSize, QImage::Format_RGB32);

    QRect rect(tilePosX*nBlockXSize, tilePosY*nBlockYSize, nBlockXSize, nBlockYSize);

    reader->setClipRect(rect);
    reader->read(&img);
    if(reader->error())
    {
        qDebug("Not null error");
        qDebug()<<"Error string is: "<<reader->errorString();
    }
    return img;

}

Итак, это в основном создает экземпляр нового считывателя для каждого фрагмента и обновляет переменную "image" суперкласса, которую я могу затем нарисовать.

Это, кажется, дает мне много ошибок от читателя, которые просто говорят "Невозможно прочитать данные изображения"

Я думаю, что это, вероятно, связано со многими фрагментами, открывающими один и тот же файл, но я не знаю, как это доказать или исправить.

Я думаю, Qt использует libjpeg и libpng и все, что угодно, чтобы читать различные форматы изображений.

Ответы

Ответ 1

Проверьте исходный код QImageReader.

Вы получите "Невозможно прочитать данные изображения", когда читатель вернет InvalidDataError.

Если вы также прочитали объяснение InvalidDataError QT Doc говорит, что

Данные изображения недействительны, и QImageReader не смог прочитать изображение из него. Это может произойти, если файл изображения поврежден.

Так что, вероятно, ваш файл поврежден.

Ответ 2

Здесь я вижу две потенциальные проблемы.

  • Это не ваша настоящая проблема, но позже я буду проблемой с небольшими фрагментами. future устанавливается после запуска потока. Это может вызвать проблемы, если финишная резьба заканчивается, до future. (Не уверен на 100%, но скажем... 85%, и я считаю, что это вряд ли произойдет)
  • paint можно назвать очень часто. Я считаю, что ваша проблема в том, что она называется во второй раз, прежде чем закончится чтение. Это приведет к тому, что другой поток попытается прочитать фрагмент, пока первый читает его. Thy даже попытается использовать тот же экземпляр QImageReader в то же время...

Ответ 3

Вы можете попробовать добавить:

if (reader->canRead())
    reader->read(&img);
else
    qDebug() << "Could not read from device";

Это может не помочь, но в соответствии с документацией canRead: возвращает true, если изображение можно прочитать для устройства (т.е. поддерживается формат изображения, и устройство, похоже, содержит достоверные данные); иначе возвращает false.

Ответ 4

Вы можете попробовать другой способ создания потоков для чтения фрагментов.

Создайте myReaderObject как подкласс из QObject.

В своем конструкторе основного потока создайте объект QThread участника:

m_workerthread=new QThread();
m_workerthread->start();

Для чтения плитки do

myReaderObject *reader=new myReaderObject();
reader->moveToThread(m_workerthread);
connect ( reader, SIGNAL(myFinishSignal() , ...
QMetaObject::invokeMethod(reader,"read", Qt::AutoConnection);

Поэтому ваш myReaderObject, конечно, нуждается в методе чтения и сигнале myFinishSignal