10
votes

Performances de redimensionnement de l'image: système.Drawing vs system.windows.media

J'ai une situation où j'ai besoin de redimensionner un grand nombre d'images. Ces images sont stockées sous forme de fichiers .jpg sur le système de fichiers actuellement, mais je m'attends à avoir d'octets [] en mémoire plus tard dans le projet. La taille de l'image source est variable, mais la sortie doit être de 3 tailles prédéterminées différentes. Les rapports d'aspect doivent être préservés, le remplissage de l'image d'origine avec un espace blanc (c'est-à-dire une image très haute serait redimensionnée de la taille de l'image cible carrée, avec de grandes zones de blanc à gauche et à droite).

i initialement construite Le projet ciblant Cibling .NET 2.0 et utilise des classes système.Drawing pour effectuer la charge / redimensionner / sauvegarder. Le code pertinent comprend: p> xxx pré>

Je voulais porter ce projet à .NET 3.5, alors essayé d'utiliser les classes System.Windows.Media pour effectuer la même fonction. Je l'ai travaillé, mais la performance est terrible; Le temps de traitement par image est d'environ 50 fois plus longtemps. La grande majorité du temps est consacrée à charger l'image. Le code pertinent comprend: P>

BitmapImage original = new BitmapImage(); //Again, reused for each of the 3 target sizes
original.BeginInit();
original.StreamSource = new MemoryStream(imageData); //imageData is a byte[] of the data loaded from a FileStream
original.CreateOptions = BitmapCreateOptions.None;
original.CacheOption = BitmapCacheOption.Default;
original.EndInit(); //Here's where the vast majority of the time is spent
original.Freeze();

// Target Rect for the resize operation
Rect rect = new Rect(center - width / 2d, center - height / 2d, width, height);

// Create a DrawingVisual/Context to render with
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
    drawingContext.DrawImage(original, rect);
}

// Use RenderTargetBitmap to resize the original image
RenderTargetBitmap resizedImage = new RenderTargetBitmap(
    size, size,                         // Resized dimensions
    96, 96,                             // Default DPI values
    PixelFormats.Default);              // Default pixel format
resizedImage.Render(drawingVisual);

// Encode the image using the original format and save the modified image
SaveImageData(resizedImage, outputFile);


0 commentaires

4 Réponses :


10
votes

Et après avoir tapé tout cela, il m'est arrivé que je pouvais charger les symboles de la SM pour les classes System.Windows.Media et passer à travers l'endroit où elle était lente. Immédiatement trouvé la cause et la solution. Les images d'entrée ont été enregistrées avec un profil de couleur, et il tentait de charger ce profil de couleur (du système de fichiers) de chaque image. En passant de bitmapcreateOptionOptions.none à bitmapcreateOptionS.ignorecolorProfile dans le code ci-dessus, cela ne le fait plus et fonctionne aussi vite que System.Drawing.

J'espère que cela aide toute autre personne qui traverse ce problème!


0 commentaires

0
votes

Je pense que cela du System.Drawing page sur MSDN pourrait être pertinent:

L'espace de noms System.Drawing donne accès à la fonctionnalité graphique de base GDI +. Une fonctionnalité plus avancée est fournie dans le système.Drawing.Drawing2D, System.Drawing.Maging et System.Drawing.Text Names. La classe graphique fournit des procédés de dessin sur le dispositif d'affichage. Les classes telles que le rectangle et le point encapsulent GDI + Primitives. La classe de stylos est utilisée pour dessiner des lignes et des courbes, tandis que les classes dérivées de la brosse de classe abstraite sont utilisées pour remplir les intérieurs des formes.

En utilisant System.Drawing Vous êtes plus proche de la fonctionnalité graphique de base réelle que si vous allez via System.Windows.Media qui:

Définit des objets permettant d'intégrer des supports riches, y compris des dessins, du texte et du contenu audio / vidéo dans Windows Presentation Foundation (WPF).

system.Drawing est toujours pris en charge, alors je m'en tenir à cela.


0 commentaires

0
votes

J'ai trouvé une situation intéressante dans votre code. Supprimer em> à l'aide de code> à partir de la ligne suivante:

using(DrawingContext drawingContext = drawingVisual.RenderOpen())


1 commentaires

Cela accélère le code parce que lorsque vous faites cela, cela ne ralentit pas. Le contexte de dessin ne dessine pas réellement ce que vous le disez, au visuel de sous-couche, jusqu'à ce que vous appeliez DrawingContext.close (), ou le DratringContext sort de la portée (qui est ce que l'utilisation utilise).



5
votes

Vous semblez faire cela la solution difficile. Vous pouvez laisser WPF faire le travail pour vous en définissant simplement décodépixelheight et décodépixelwidth. Cela provoquera que le redimensionnement se produise pendant la charge de l'image:

BitmapImage resizedImage = new BitmapImage
{
  StreamSource = new MemoryStream(imageData),
  CreateOptions = BitmapCreateOptions.IgnoreColorProfile,
  DecodePixelHeight = height,
  DecodePixelWidth = width,
}
resizedImage.BeginInit();  // Needed only so we can call EndInit()
resizedImage.EndInit();    // This does the actual loading and resizing

imageSaveImageData(resizedImage, outputFile);


0 commentaires