I am trying to use QImageReader to read portions of an image file at a time (per Tile), so that for very large images they are not read into memory from disk until they need to be displayed.
It seems liek I am running into some thread safety issues.
This is what I currently have:
#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 = QtConcur开发者_如何学运维rent::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;
}
So this is basically instantiating a new reader for each tile, and update the "image" variable of the superclass, which I can then paint.
This seems to give me a lot of errors from the reader, which simply say "Unable to read image data"
I think this is probably something to do with many tiles accessing the same file, but I dont know how to prove that, or fix it.
I think Qt uses libjpeg and libpng and whatever else to read various image formats.
Check out the source code of QImageReader.
You will get "Unable to read image data" when the reader returns InvalidDataError.
If you also read the explanation of InvalidDataError QT Doc says that
The image data was invalid, and QImageReader was unable to read an image from it. The can happen if the image file is damaged.
So probably your file is corrupt.
I see two potential problems here.
- This is not your real problem but my be an issue with small tiles later.
future
is set after the thread is started. This may cause trouble, if the thread finishes, beforefuture
is set correctly. (Not 100% sure about this, but lets say... 85%, and I believe this is very unlikely to happen) paint
can be called really often. I believe your problem is that it is called the second time, before your reading thread finished. This would cause another thread trying to read the tile while the first one is still reading it. Thy will even try to use the same instance of QImageReader at the same time...
You could try adding in:
if (reader->canRead())
reader->read(&img);
else
qDebug() << "Could not read from device";
It may not help much but according to the documentation canRead: Returns true if an image can be read for the device (i.e., the image format is supported, and the device seems to contain valid data); otherwise returns false.
You could try another way of creating threads for reading the tiles.
Create a myReaderObject as subclass from QObject.
In your main thread constructor create a member QThread object:
m_workerthread=new QThread();
m_workerthread->start();
For reading a tile do
myReaderObject *reader=new myReaderObject();
reader->moveToThread(m_workerthread);
connect ( reader, SIGNAL(myFinishSignal() , ...
QMetaObject::invokeMethod(reader,"read", Qt::AutoConnection);
Your myReaderObject then of course needs a read method and a myFinishSignal signal
精彩评论