views:

515

answers:

6

I need to display thumbnails of images in a given directory. I use TFileStream to read the image file before loading the image into an image component. The bitmap is then resized to the thumbnail size, and assigned to a TImage component on a TScrollBox.

It seems to work ok, but slows down quite a lot with larger images.

Is there a faster way of loading (image) files from disk and resizing them?

Thanks, Pieter

+5  A: 

Not really. What you can do is resize them in a background thread, and use a "place holder" image until the resizing is done. I would then save these resized images to some sort of cache file for later processing (windows does this, and calls the cache thumbs.db in the current directory).

You have several options on the thread architecture itself. A single thread that does all images, or a thread pool where a thread only knows how to process a single image. The AsyncCalls library is even another way and can keep things fairly simple.

skamradt
My app now uses placeholder and threads (skamradt, mghie) and it works perfectly. The thumbnails are extracted as suggested by Stijn Sanders. Thank you. Pieter.
Pieter van Wyk
+5  A: 

I'll complement the answer by skamradt with an attempt to design this for being as fast as possible. For this you should

  • optimize I/O
  • use multiple threads to make use of multiple CPU cores, and to keep even a single CPU core working while you read (or write) files

The use of multiple threads implies that using VCL classes for the resizing isn't going to work, as the VCL isn't thread-safe, and all hacks around that don't scale well. efg's Computer Lab has links for image processing code.

It's important to not cause several concurrent I/O operations when using multiple threads. If you choose to write the thumbnail images back to files, then once you have started reading a file you should read it completely, and once you have started writing a file you should also write it completely. Interleaving both operations will kill your I/O, because you potentially cause a lot of seeking operations of the hard disc head.

For best results the reading (and writing) of files should also not happen in the main (GUI) thread of your application. That would suggest the following design:

  • Have one thread read files into TGraphic objects, and put these into a thread-safe list.
  • Have a thread pool wait on the list of files in original size, and have one thread process one TGraphic object, resize it into another TGraphic object, and add this to another thread-safe list.
  • Notify the GUI thread for each thumbnail image added to the list, so it can be displayed.
  • If thumbnails are to be written to file, do this in the reading thread as well (see above for an explanation).

Edit:

On re-reading your question I notice that you maybe only need to resize one image, in which case a single background thread is of course enough. I'll leave my answer in place anyway, maybe it will be of use to someone else some time. It's what I learned from one of my latest projects, where the final program could have needed a little more speed but was only using about 75% of the quad core machine at peak times. Decoupling I/O from processing would have made the difference.

mghie
+3  A: 

I often use TJPEGImage with Scale:=jsEighth (in Delphi 7). This is really fast because the JPEG de-compression can skip a lot of the data to fill a bitmap of only an eighth of width and height.

Another option is to use the shell's method to extract a thumbnail, which is pretty fast as well

Stijn Sanders
this looks good. I was desperate to figure this out last year but now I no longer care too much. But I can still fix some of my apps using the TJPEGImage.Scale approach. Thanks
Peter Perháč
A: 

I'm in the vision business, and I simply upload the images to the GPU using OpenGL. (typically 20x 2048x2000x8bpp per second), a bmp per texture, and let the videocard scale (win32, Mike Lischke's opengl headers)

Upload of such an image costs 5-10ms depending on exact videocard (if not integrated and nvidia 7300 series or newer. Very recent integrated GPUs might be doable also). Scaling and displaying costs 300us. Which means customers can pan and zoom like crazy without touching the app. I draw an overlay (which used to be a tmetafile but is now an own format) on top of it.

My biggest picture is 4096x7000x8bpp which shows and scales in under 30ms. (GF 8600)

A limitation of this technology is max texture size. It can be resolved by fragmenting the picture into multiple textures, but I haven't bothered yet because I deliver the systems with the software.

(some typical sizes: nv6x00 series: 2k*2k but uploading is just about break even compared to GDI nv7x00 series: 4k*4k For me the baseline cards. GF7300's are like $20-40 nv8x00 series: 8k*8k )

Note that this might not be for everybody. But if you are in the lucky situation to specify hardware limits, it might work. The main problem are laptops like Thinkpads, the GPUs of which are older than the avg laptop, which are in turn often a generation behind Desktops.

I chose OpenGL over DirectX because it is more static in time, and easier to find non-game related examples.

Marco van de Voort
very informative but off-topic.
Peter Perháč
A: 

Exploit windows capacity to create thumbnails. Remember that hidden Thumbs.db files in folders that contain images.

I have implemented something like this feature but in VB. My software is able to build thumbnails of 100 files (mixed size) in around 10 seconds.

If you feel interested email me on: yogi yang 0 0 7 @ gmail . com (remove all spaces)

I am not able to convert it to Delphi though.

HTH

Yogi Yang

Yogi Yang 007
A: 

Try to look at the Graphics32 library : it's very good at drawing things and works great with Bitmaps. They are Thread - Safe with good example, and it's totally free.

Olivier Pons