Чтение файлов изображений с помощью QImageReader с использованием QtConcurrent - PullRequest
14 голосов
/ 23 июня 2011

Я пытаюсь использовать 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 и все остальное для чтения различных форматов изображений.

Ответы [ 4 ]

2 голосов
/ 30 июля 2012

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

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

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

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

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

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

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

0 голосов
/ 20 августа 2011

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

Создать myReaderObject в качестве подкласса из QObject.

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

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

Для чтения тайла выполните

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

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

0 голосов
/ 04 июля 2011

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

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

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

...