9 votes

Affichage rapide de vignettes d'images à très haute résolution avec un délai minimal

J'ai besoin d'afficher les vignettes de prévisualisation des images haute résolution dans un contrôle pour la sélection de l'utilisateur. J'utilise actuellement ImageListView pour charger les images. Cela fonctionne bien pour les images de basse et moyenne résolution, mais lorsqu'il s'agit d'afficher des vignettes d'images de très haute résolution, le retard est notable. Un exemple d'image peut être téléchargé à l'adresse suivante https://drive.google.com/open?id=1Qgu_aVXBiMlbHluJFU4fBvmFC45-E81C

La taille de l'image est d'environ 5000x3000 pixels et sa taille est d'environ 12 MB. Le problème peut être reproduit en utilisant 1000 copies de cette image.

La capture d'écran du problème est téléchargée ici

https://giphy.com/gifs/ZEH3T3JTfN42OL3J1A

Les images sont chargées en utilisant un travailleur d'arrière-plan

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

1. Afin de résoudre ce problème, j'ai essayé de redimensionner des images de grande résolution et d'ajouter l'image redimensionnée à ImageListView ... mais pour le redimensionnement, il y a une forte consommation de temps et la génération de vignettes est lente.

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. J'ai également essayé Image.CreateThumbnail mais cette méthode est également très lente.

Existe-t-il une meilleure façon de résoudre ce problème ?

10voto

Je vous suggère d'utiliser une bibliothèque de traitement d'images telle que ImageMagick.

ImageMagick a optimisé cette fonctionnalité et vous avez Magick.NET une nuget pour .NET.

C'est simple et direct :

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");
    }
}

exemple que j'ai fait :

enter image description here

Voici de la documentation et des références qui pourraient vous être utiles :

5voto

Simon Mourier Points 49585

Vous pourriez utiliser Interopérabilité WPF et utiliser le Propriétés de DecodePixelWidth/Height . Ils utilisent la technologie sous-jacente de la couche d'imagerie de Windows (" Composant d'imagerie Windows ") pour créer une vignette optimisée, ce qui permet d'économiser beaucoup de mémoire (et éventuellement de CPU) : Comment faire : Utiliser une image BitmapImage (XAML)

Vous pouvez également utiliser WPF/WIC par code, avec un code comme celui-ci (adapté de cet article Le moyen le plus rapide de redimensionner des images à partir d'ASP.NET. Et il est (plus) soutenu. . Il suffit d'ajouter une référence à PresentationCore et à WindowsBase, ce qui ne devrait pas poser de problème pour une application de bureau.

    // 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);
        }
    }

Sinon, il existe de nombreux outils comme MagicScaler, FreeImage ImageSharp, ImageMagick, Imazen, etc. La plupart ont été écrits pour des scénarios ASP.NET/serveur Web (pour lesquels WPF n'est officiellement pas supporté mais fonctionne, lisez l'article) et sont également multiplateformes, ce dont vous ne semblez pas avoir besoin. Je ne suis pas sûr qu'ils soient généralement plus rapides ou qu'ils utilisent moins de mémoire que la technologie Windows intégrée, mais vous devriez tester tout cela dans votre contexte.

PS : sinon il n'y a pas de solution miracle, les grandes images prennent plus de temps.

5voto

user894763 Points 451

Il y a aussi NetVips la liaison C# pour libvips.

C'est un peu plus rapide que Magick.NET : entre 3x et 10x plus rapide en fonction de l'indice de référence.

Le thumbnailing est simple :

using NetVips;

var image = Image.Thumbnail("some-image.jpg", 128);
image.WriteToFile("x.jpg");

Il y a une introduction dans la documentation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X