我正在尝试使用QImageReader一次读取部分图像文件(每个Tile),这样对于非常大的图像,它们不会从磁盘读入内存,直到需要显示它们为止。
似乎谎言我遇到了一些线程安全问题。
这就是我目前所拥有的:
#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;
}
所以这基本上是为每个图块实例化一个新的阅读器,并更新超类的“图像”变量,然后我可以绘制它。
这似乎给了我很多读者的错误,只是说“无法读取图像数据”
我认为这可能与访问同一文件的许多磁贴有关,但我不知道如何证明或修复它。
我认为Qt使用libjpeg和libpng以及其他任何方式来阅读各种图像格式。
答案 0 :(得分:2)
查看QImageReader的源代码。
当阅读器返回 InvalidDataError 时,您将获得“无法读取图像数据”。
如果您还阅读InvalidDataError QT Doc说明
的说明图像数据无效,并且 QImageReader无法读取 从它的图像。如果是,可能会发生 图像文件已损坏。
所以你的文件可能已损坏了。
答案 1 :(得分:2)
我在这里看到两个潜在的问题。
future
设置正确之前,这可能会导致问题。 (不是100%肯定这个,但是让我们说... 85%,我相信这不太可能发生)future
可以经常被调用。我相信你的问题是它在你的阅读线程结束之前第二次被调用。这将导致另一个线程尝试读取磁贴,而第一个仍在读取磁贴。你甚至会尝试同时使用同一个QImageReader实例...... 答案 2 :(得分:0)
您可以尝试添加:
if (reader->canRead())
reader->read(&img);
else
qDebug() << "Could not read from device";
它可能没什么用,但根据文档中的canRead:如果可以为设备读取图像,则返回true(即,支持图像格式,并且设备似乎包含有效数据);否则返回false。
答案 3 :(得分:0)
你可以尝试另一种创建线程来阅读瓷砖的方法。
从QObject创建myReaderObject作为子类。
在主线程构造函数中创建一个成员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信号