Page MenuHome

Windows: request the OS for a thumbnail or icon
Changes PlannedPublic

Authored by Germano Cavalcante (mano-wii) on Apr 27 2021, 7:01 PM.

Details

Summary

On Windows the thumbnails of the files in a folder are cached in an internal
file called Thumbs.db.

Blender does not read the thumbs from this file, instead (for supported files
with images, videos and .blend files), it loads, generates a thumb and saves
he image in a cache located in:
C:\Users\%user%\.thumbnails\large

This is inefficient as it forces the loading of the files and causing a huge
slowness at times.

In addition to taking up HD space.


This patch uses the Win 32 API to obtain an address that points to a bitmap
in Thumbs.db generated for the file.

Thus, it is no longer necessary to load the file.

Ref T87621


Unresolved problems:

  • SHCreateItemFromParsingName and IShellItemImageFactory::GetImage do not work well in multithreaded (frequent crashes)

Diff Detail

Repository
rB Blender
Branch
master
Build Status
Buildable 14263
Build 14263: arc lint + arc unit

Event Timeline

Germano Cavalcante (mano-wii) requested review of this revision.Apr 27 2021, 7:01 PM
Germano Cavalcante (mano-wii) created this revision.
Germano Cavalcante (mano-wii) planned changes to this revision.Apr 27 2021, 7:03 PM
Germano Cavalcante (mano-wii) planned changes to this revision.Apr 30 2021, 3:32 PM
Germano Cavalcante (mano-wii) edited the summary of this revision. (Show Details)
Germano Cavalcante (mano-wii) retitled this revision from Attempt to fix T87621: Blender File Open dialog triggers OneDrive Files downloads to Windows: read thumbnails from the 'Thumbs.db' file.Apr 5 2022, 4:07 PM
Germano Cavalcante (mano-wii) edited the summary of this revision. (Show Details)

The title of this diff is not quite right, it's not just merely reading from thumbs.db it's requesting the OS for a thumbnail or icon for a file, if no cached thumbnail is found, the file is still loaded (by the OS in a separate process) and a thumbnail extracted, the same work is still being done, just by someone else, i'm not convinced having this additional codepath is worth it, if dealing with thumbnails is slow, we ought to improve that in a way that benefits all platforms.

Germano Cavalcante (mano-wii) retitled this revision from Windows: read thumbnails from the 'Thumbs.db' file to Windows: request the OS for a thumbnail or icon if no cached thumbnail is found.Apr 5 2022, 4:37 PM
Germano Cavalcante (mano-wii) retitled this revision from Windows: request the OS for a thumbnail or icon if no cached thumbnail is found to Windows: request the OS for a thumbnail or icon.Apr 5 2022, 4:44 PM

Since the thumbnails of a file are generated and cached when requested by Blender or not, for me, using this cache would still be an advantage.

If not cached, Blender requests the thumbnail and then OS creates and caches it in a way that can be used by other file explorers.

I'm not sure if the work the OS does to create thumbnails is equivalent to Blender, for OneDrive for example we can see the thumbnails even though the file is not loaded.

Another approach would be to use IThumbnailCache::GetThumbnail, but called with WTS_INCACHEONLY. This can be called from a UI thread since this returns immediately with an image if it is already in the cache, but does not make one if not.

Then this could be a tool as part of the thumbnail extraction chain rather than replace it. So used first, or only in the case of offline files. Would certainly come in handy when the user has software installed that provides a custom thumbnail provider. And would also get around our current self-imposed limitation of not thumbnailing images that have file size greater than 100MB. If the OS has already thumbnailed it - whatever it is - just show it.

HBITMAP GetThumbnailFromCache(const WCHAR *path, const size_t width, const size_t height)
{
  HRESULT hr = CoInitialize(nullptr);

  IShellItem *item = nullptr;
  hr = SHCreateItemFromParsingName(path, nullptr, IID_PPV_ARGS(&item));

  IThumbnailCache *cache = nullptr;
  hr = CoCreateInstance(CLSID_LocalThumbnailCache, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&cache));

  ISharedBitmap *shared_bitmap;
  hr = cache->GetThumbnail(
      item, width * height, WTS_INCACHEONLY, &shared_bitmap, nullptr, nullptr);

  HBITMAP hbitmap = NULL;
  hr = shared_bitmap->GetSharedBitmap(&hbitmap);

  CoUninitialize();

  return hbitmap;
}