PDA

View Full Version : how to browse images in thumbnail view?



zl2k
2nd September 2008, 16:22
hi, there
My application needs to browse thousands of images in thumbnail view. I tried QListWidget with icon mode but found it's extremely slow and memory consuming. Many image browser software like GWinView, which is using qt3, handles the problem nicely. How can I do this in qt4? The images are jpg or png format (I won't try other format at this time.) Here is the piece of code:



while (myIterator.hasNext())
{
QString myFileName = myIterator.next();
QFileInfo myFileInfo(myFileName);
if (!myFileInfo.isFile()) continue;
QPixmap myPixmap(myFileName);
QListWidgetItem * mypItem = new QListWidgetItem(myFileInfo.baseName());
mypItem->setIcon(myPixmap);
mypItem->setData(Qt::UserRole,myFileName);
listWgt1->addItem(mypItem);
}
listWgt1->sortItems(Qt::AscendingOrder);


The listWgt1 is a QListWidget set to icon mode. Comparing to Gwenview, the loading time is about twice longer and the scrolling is noticeably delayed (but tolerable). The scaling of thumbnails are fast. The memory consuming is much much larger than Gwenview.

Is there any other approach that I can do the thumbview in qt4 fast and memory efficient? (for several thousands of images). Thanks for help.

zl2k

wysota
3rd September 2008, 02:07
Load and scale images in the background, for instance using worker thread(s).

chezifresh
24th March 2009, 00:42
whats the best algorithm to use for a background thread since you can't create a QPixmap outside the main thread?

chezifresh
24th March 2009, 00:47
I love answering my own question. For those of you who are lazy like me, the simple answer is that you can use QImage outside of the main thread. So instead of using QPixmap use a QImage

See the following thread for more info:

http://www.qtcentre.org/forum/f-newbie-4/t-basic-multithreading-question-2-threads-11994.html/?highlight=thumbnail

wysota
24th March 2009, 00:48
You can create QImages in worker threads. Currently the best solution is to use QtConcurrent.

aamer4yu
24th March 2009, 05:19
You can also try using simply QLabels in grid layout...

or you can also give a thought to graphicsview framework,,, zooming will be faster in graphics view since you can scale the whole view, and not just single items...

chezifresh
24th March 2009, 18:10
Yeah, I'm actually using a QGraphicsView and a QGraphicsPixmapItem

Because I know there are others out there with the same problem I'll post the code I have so far (still haven't implemented it using QImage though)

In PyQt


import PyQt4
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt
from PyQt4.QtCore import SIGNAL

class QdGraphicsPixmapItem(QtGui.QGraphicsPixmapItem):
def __init__(self, image, parent=None):
QtGui.QGraphicsPixmapItem.__init__(self, parent)
self._image = image
self._loaded = False
self.setFlags(self.flags() | QtGui.QGraphicsItem.ItemIsSelectable | QtGui.QGraphicsItem.ItemIsMovable )

def paint(self, painter, styleopt, widget):
if not self._loaded:
self._loaded = True
pixmap = QtGui.QPixmap(self._image)
thumb = pixmap.scaled(200, 200, Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.setPixmap(QtGui.QPixmap(self._image).scaled(2 00, 200))
QtGui.QGraphicsPixmapItem.paint(self, painter, styleopt, widget)

class QdThumbnailView(QtGui.QGraphicsView):
def __init__(self, images, parent=None):
QtGui.QGraphicsView.__init__(self, parent)
self._scene = QtGui.QGraphicsScene()

total = len(images)
current = 0
for image in images:
#print current, 'of', total, os.path.basename(image)
if os.path.isdir(image) or os.path.basename(image).startswith('.'):
continue
current += 1

item = QdGraphicsPixmapItem(image, current)
item.setPos(0, 200*current)
self._scene.addItem(item)

self._scene.setSceneRect(0, 0, 200, 200*current)
self.setScene(self._scene)


You can imagine using a pool of background threads to load the thumbnails instead of loading them on demand. Thats where the QImage comes into play

drhex
24th March 2009, 20:00
I'm writing an application that displays many thumbnails (as QLabels in a grid layout).
Some more hints for the background loading + scaling is to


Use exiv2 (http://www.exiv2.org/) to extract embedded thumbnails in e.g. digital camera files
store computed thumbnails in a database (http://jens.triq.net/thumbnail-spec/index.htm) that can be shared with other applications

wysota
24th March 2009, 20:45
Using QLabels to display many thumbnails is a big resource hog. All the images have to be kept in the server memory all the time and layouts need to be recalculated every time you add a new image. Using Item Views or Graphics View is much more resource efficient.

drhex
24th March 2009, 21:59
Does Graphics View then store its data somewhere else and transfer it over to the server when needed? Won't that make it slower?

chezifresh
24th March 2009, 23:27
I'm using a graphics view however I want to use a flow layout which I dont believe exists for QGraphicsPixmapItems so I'm thinking I'm going to have to implement that myself... which seems like a daunting task.

And so we're all on the same page I want the GraphicsView thumbnail viewer to have vertical scrollbars but no horizontal ones. The thumbnails would show up in rows, say 4 to a row and as you zoom in the icons would resize and eventually you'd have 3 to a row... etc

I'm pretty sure there are other people out there looking to do the same exact thing since thats exactly how it works in thumbnail view in nautilus, konqueror, finder, etc. Basically any file browser that supports thumbnail views.

Since konqueror is a Qt app its probably the best example... though unfortunately no one else can use it because its so KDE specific. I was hoping that we could find a Qt example of something like this in the 4.5 examples but no dice.

In general it seems like it would be an awesome widget to have in say source forge or something with SIP bindings and all. Too bad Qt doesn't support a community of user made widgets in their git repos. The Qt labs examples are a great start but only the guys at Qt seem to be able to contribute.

chezifresh
25th March 2009, 02:24
Just an update...

I did some digging into the replacement for Konqueror, "Dolphin", and it appears to be using an item view for its thumbnail view (a KCategorizedView (http://api.kde.org/4.x-api/kdelibs-apidocs/kdeui/html/classKCategorizedView.html) which is derived from a QListView). At least as far as I can tell it doesnt appear to be taking advantage of the QGraphicsView.

I'm assuming they're using that because they have a QDirModel driving it.

It sure would be nice to have an open source thumbnail viewer that takes advantage of the QGraphicsView. Not that my code is all that fantastic, but if I make some headway on one I'll post some stuff back here at the very least.

chezifresh
23rd April 2009, 03:20
Ok, as promised I have some code that will hopefully get some people started, its attached as a PyQt example

I apologize for the lack of comments and docstrings but this was more of a mockup than anything else

Here's how to use:


app = QtGui.QApplication([])
widget = QdContactSheet()
images = # list of images you want to view as thumbnails
images.sort()
widget.load(images)

widget.setWindowTitle("Contact Sheet")
widget.resize(1000, 800)
widget.show()
app.exec_()