4

I am populating a list (in my electron app), each item showing a hi-res image from disk. Now, since the list is getting longer, I am running into performance issues: Electron is occupying a whole lot of RAM, so I guess I will need to render thumbnails somehow.

Electron provides an API for downscaling images. But this is a synchronous process and so downscaling on render of the UI is not an option, since it would freeze the UI. So it would need to be done when new images are added by the user. However, I don't like this idea much, since I would need to take care of managing those additional thumbnail image files.

What is a good solution here? My idea was to run a http server (express) which takes care of delivering downscaled version of the images, similar to this API:

http://localhost:30948/imageshrinker?image=imagedir/myimg.jpg&size=medium

This seems like a whole lot to implement (especially because I think I would need to run this in another worker window right?) and I didn't find any library which I could use.

Any ideas how to best approach this issue?

stoefln
  • 14,498
  • 18
  • 79
  • 138

1 Answers1

2

How about using nativeImage.createThumbnailFromPath? It returns Promise, so you could display some loading/dummy/shimmer image on init and show thumbnail when particular promise resolves. With proper cache management (like render Chunks known for ex. from facebook wall) loading even 100 000 images should be a breeze.

Other than that, when I was faced with similar issue, I made some research and for me the best and (actually) the fastest library was Sharp, I was loading JPG images from Hasselblad that has more than 100MB in size and creating a set of thumbnails for Sharp was like 0.4s. This is a bit of troublesome, because you'll have to implement thumbnail management by your own, but in long run you'll benefit from that. In your case I would follow an algorithm such as:

  1. On open file

  2. Create md5 checksum

  3. Compare md5 with database entry, if entry exist jump to 7

  4. Open image within Sharp constructor, resize to desired value

  5. Save to File within temp/thumbnails folder

      sharp(input)
      .resize(200, 300)
      .toFile(`thumbnails/${md5}.png`)
      .then(() => {
        // update list item with proper image source
      });
    
    
  6. Write database entry with thumbnail source path under original md5 checksum

  7. Insert thumbnail as an image source

  8. If Image.onError rises which means thumbnail file does not exists, jump to 4

So you wouldn't have to generate thumbnails everytime someone opens an app, just remember to clean thumbnails directory from times to times, or just dump the idea of keeping thumbnails local, just keep them in-memory, display on request and check if performance is good- might be, like:

sharp(input)
  .resize({ width: 100, height: 100 })
  .toBuffer()
  .then(data => {
    tempImages[itemID] = nativeImage.createFromBuffer(data, {width: 100, height: 100})
  });
Maciej Kwas
  • 6,169
  • 2
  • 27
  • 51