Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying Thumbnails of very high resolution images Fast with Minimal Delay

I need to show the preview thumbnails of high resolution images in a control for user selection. I currently use ImageListView to load images. This works fine for low to medium resolution images.But when it comes to showing thumbnails of very high resolution images there is a noticeable delay.Sample image can be downloaded from https://drive.google.com/open?id=1Qgu_aVXBiMlbHluJFU4fBvmFC45-E81C

The image size is around 5000x3000 pixels and size is around 12 MB.The issue can be replicated by using 1000 copies of this image.

The issue screen capture is uploaded here

https://giphy.com/gifs/ZEH3T3JTfN42OL3J1A

The images are loaded using a background worker

foreach (var f in filepaths)
{
    imageListView1.Items.Add(f);              
}

1. In order to solve this issue I tried resizing large resolution images and adding the resized image to ImageListView ... but for resizing there is a heavy time consumption and thumbnail generation is slow.

Bitmap x = UpdatedResizeImage2(new Bitmap(f), new Size(1000, 1000));
string q = Path.GetTempPath() + Path.GetFileName(f);
x.Save(Path.GetTempPath() + Path.GetFileName(f));
x.Dispose();
imageListView1.Items.Add(Path.GetTempPath() + Path.GetFileName(f));

2. I have also tried Image.CreateThumbnail Method but this is also quite slow.

Is there a better way to solve this issue?

like image 481
techno Avatar asked Sep 10 '19 16:09

techno


2 Answers

I would suggest using image processing library such ImageMagick.

ImageMagick has optimized this feature and you have Magick.NET a nuget package for .NET.

It is simple and straight forward:

var file = new FileInfo(@"c:\temp\input.jpg");

using (MagickImage image = new MagickImage(file))
{
    {
        image.Thumbnail(new MagickGeometry(100, 100));
        image.Write(@"C:\temp\thumbnail.jpg");
    }
}

example I made:

enter image description here

Here is some documentation and references that might be useful:

  • https://imagemagick.org/Usage/thumbnails/#creation
  • http://www.imagemagick.org/Usage/thumbnails/
  • https://github.com/dlemstra/Magick.NET
  • https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/

  • https://devblogs.microsoft.com/dotnet/net-core-image-processing/

  • https://weblogs.asp.net/bleroy/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi
  • Alternatives to System.Drawing for use with ASP.NET?
like image 118
Maytham Avatar answered Oct 11 '22 14:10

Maytham


You could use WPF interop and use the DecodePixelWidth/Height properties. They use underlying Windows imaging layer technology ("Windows Imaging Component") to create an optimized thumbnail, saving lots of memory (and possibly CPU): How to: Use a BitmapImage (XAML)

You can also use WPF/WIC by code, with a code like this (adapted from this article The fastest way to resize images from ASP.NET. And it’s (more) supported-ish.. You just need to add a reference to PresentationCore and WindowsBase which shouldn't be an issue for a desktop app.

    // needs System.Windows.Media & System.Windows.Media.Imaging (PresentationCore & WindowsBase)
    public static void SaveThumbnail(string absoluteFilePath, int thumbnailSize)
    {
        if (absoluteFilePath == null)
            throw new ArgumentNullException(absoluteFilePath);

        var bitmap = BitmapDecoder.Create(new Uri(absoluteFilePath), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None).Frames[0];
        int width;
        int height;
        if (bitmap.Width > bitmap.Height)
        {
            width = thumbnailSize;
            height = (int)(bitmap.Height * thumbnailSize / bitmap.Width);
        }
        else
        {
            width = (int)(bitmap.Width * thumbnailSize / bitmap.Height);
            height = thumbnailSize;
        }

        var resized = BitmapFrame.Create(new TransformedBitmap(bitmap, new ScaleTransform(width / bitmap.Width * 96 / bitmap.DpiX, height / bitmap.Height * 96 / bitmap.DpiY, 0, 0)));
        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(resized);
        var thumbnailFilePath = Path.ChangeExtension(absoluteFilePath, thumbnailSize + Path.GetExtension(absoluteFilePath));
        using (var stream = File.OpenWrite(thumbnailFilePath))
        {
            encoder.Save(stream);
        }
    }

Otherwise there are lots of tools out there like MagicScaler, FreeImage ImageSharp, ImageMagick, Imazen, etc. Most were written for ASP.NET/Web server scenarios (for which WPF is officially not supported but works, read the article) and are also cross-platform which you don't seem to need. I'm not sure they're generally faster or use less memory than builtin Windows technology, but you should test all this in your context.

PS: otherwise there's no magic bullet, bigger images take more time.

like image 24
Simon Mourier Avatar answered Oct 11 '22 13:10

Simon Mourier