2011-06-23 9 views
14

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; 

} 

だから、これは基本的に各タイルの新しいリーダーをインスタンス化し、私はその後、ペイントすることができ、スーパークラスの「画像」変数を、更新された:

これは私が現在持っているものです。

これは私がこれはおそらく、同じファイルにアクセスして、多くのタイルとは何かだと思うが、私はいけない

単に「画像データを読み取ることができません」と言った、私の読者からのエラーの多くを与えるように思われますそれを証明する方法を知っているか、それを修正してください。

私はQtがlibjpegとlibpngを使用していて、他にもさまざまなイメージフォーマットを読み込むと思います。

+0

「多くのタイル」はいくつですか?実際のスレッド数の制限は、通常はかなり小さいです。 – Jay

+3

単純なシングルスレッドプログラムがQImageReaderを介してタイルをロードできることを確認してください。また、LoadTilePixmap()でスタック上にQImageReaderを作成します。 LoadPixmapを自由な関数にして、すべてを引数として渡すと、同期の問題を避けることができます。なぜミューテックス?静的ですか?それは一度にロードされるタイルを1に制限します... –

+0

タイルの数は1000を超えることがありますが、一度に読み込む数はわずかです。ビューアで最初に表示されるタイルは、新しいスレッドを開始する唯一のものです。ミューテックスは静的でした。 QImageReaderに複数のファイルを一度にディスクにアクセスさせないようにしていました。 QImageReaderをスタックに配置しようとしましたが、ヒープ上にあると同じ結果が得られ、渡されました。 – Derek

答えて

2

QImageReaderのソースコードを参照してください。

読者がInvalidDataErrorを返すときに、「画像データを読み取ることができません」を取得します。

InvalidDataError QTドキュメントの説明は

画像データが無効であったと述べているあなたも読めば、と QImageReaderはそれから 画像を読み取ることができませんでした。 イメージファイルが破損している場合に発生する可能性があります。

おそらくファイルが壊れている可能性があります。それは、多くのが、ドキュメンテーションcanReadに応じて助けないかもしれない

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

::あなたがに追加してみてください可能性が

+0

私はそれについて疑問に思っていましたが、私は他の場所からファイルを読み込むことができました。このコードで並行処理を取り、各タイルを連続して読み込もうとしました。 – Derek

0

画像がすなわち、画像フォーマットがサポートされている(デバイスのために読み取ることができる場合はtrueを返し、かつデバイスは有効なデータを含んでいるようです)。それ以外の場合はfalseを返します。

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は、当然のreadメソッドとmyFinishSignal信号

2
を必要としません

私はここで2つの潜在的な問題を見る。

  1. これは実際の問題ではありませんが、後で小さいタイルで問題になることがあります。 futureはの後にに設定され、スレッドが開始されます。これにより、スレッドが終了すると、futureが正しく設定される前に問題が発生する可能性があります。 (これについては100%ではありませんが、85%と言えますが、これは起こりそうにないと信じています)
  2. paintは本当に頻繁に呼び出すことができます。あなたの問題は、あなたの読書スレッドが終了する前に、それが2回目と呼ばれるということです。これは、別のスレッドが最初のスレッドがまだそれを読み込んでいる間に、そのタイルを読み込もうとします。 QImageReaderの同じインスタンスを同時に使用しようとします...
関連する問題