Question

Je redimensionne certaines images à la résolution de l'écran de l'utilisateur. si le format d'image est incorrect, l'image doit être coupée. Mon code ressemble à ceci:

protected void ConvertToBitmap(string filename)
    {
        var origImg = System.Drawing.Image.FromFile(filename);
        var widthDivisor = (double)origImg.Width / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
        var heightDivisor = (double)origImg.Height / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
        int newWidth, newHeight;

        if (widthDivisor < heightDivisor)
        {
            newWidth = (int)((double)origImg.Width / widthDivisor);
            newHeight = (int)((double)origImg.Height / widthDivisor);
        }
        else
        {
            newWidth = (int)((double)origImg.Width / heightDivisor);
            newHeight = (int)((double)origImg.Height / heightDivisor);
        }

         var newImg = origImg.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
        newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
    }

Dans la plupart des cas, cela fonctionne bien. Mais pour certaines images, le résultat est de qualité extrêmement médiocre. Il semblerait que l’image aurait été redimensionnée à une taille très petite (taille de la vignette) puis agrandie à nouveau. Mais la résolution de l’image est correcte. Que puis-je faire?

Exemple d'image orig: texte de remplacement http://img523.imageshack.us/img523/1430/naturaerowoods.jpg

Exemple d'image redimensionnée: alt text

Remarque: j'ai une application WPF mais j'utilise la fonction WinForms pour le redimensionnement, car c'est plus facile et j'ai déjà besoin d'une référence à System.Windows.Forms pour une icône dans la barre d'état.

Était-ce utile?

La solution

Modifiez les deux dernières lignes de votre méthode en ceci:

var newImg = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(newImg);
g.DrawImage(origImg, new Rectangle(0,0,newWidth,newHeight));
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();

Autres conseils

Je ne peux pas consulter la source .NET pour le moment, mais le problème provient probablement de la méthode Image.GetThumbnailImage . Même MSDN indique que "cela fonctionne bien lorsque la vignette demandée a une taille d’environ 120 x 120 pixels, mais si vous demandez une grande vignette (par exemple, 300 x 300) à une image comportant une vignette intégrée, il y pourrait être une perte de qualité notable dans la vignette ". Pour un véritable redimensionnement (c’est-à-dire sans vignette), vous devez utiliser la méthode Graphics.DrawImage . Vous devrez peut-être aussi jouer avec Graphics.InterpolationMode pour obtenir une meilleure qualité si nécessaire.

Si vous ne créez pas de vignette, l'utilisation d'une méthode appelée GetThumbnailImage n'est probablement pas une bonne idée ...

Pour d'autres options, consultez cet article de CodeProject . . En particulier, il crée une nouvelle image, crée un Graphics pour cette image, définit le mode d'interpolation sur HighQualityBicubic et dessine l'image d'origine sur les graphiques. La peine d'essayer, au moins.

Comme indiqué sur la MSDN , GetThumbnailImage () n'est pas conçu pour effectuer un redimensionnement d'image arbitraire. Tout ce qui dépasse 120x120 doit être mis à l'échelle manuellement. Essayez ceci à la place:

using(var newImg = new Bitmap(origImg, newWidth, newHeight))
{
    newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}

Modifier

À titre d'éclaircissement, cette surcharge du constructeur Bitmap appelle Graphics.DrawImage , bien que vous n'ayez aucun contrôle sur l'interpolation.

au lieu de ce code:

newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);

utilisez celui-ci:

System.Drawing.Imaging.ImageCodecInfo[] info = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.EncoderParameters param = new System.Drawing.Imaging.EncoderParameters(1);
param.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
newImg.Save(dest_img, info[1], param);

Par exemple, l’image originale est JPG et l’image redimensionnée est PNG. Êtes-vous la conversion entre les formats à dessein? La commutation entre différents schémas de compression Lossey peut entraîner une perte de qualité.

Augmentez ou diminuez-vous la taille de l'image lorsque vous la redimensionnez? Si vous créez une image plus grande à partir d’une image plus petite, ce type de dégradation est à prévoir.

Les images seront définitivement dégradées si vous les agrandissez.

Certaines caméras ont inséré une vignette redimensionnée dans le fichier même, probablement à des fins de prévisualisation sur le périphérique lui-même.

La méthode GetThumbnail obtient réellement cette image miniature qui est incorporée dans le fichier image au lieu de la méthode de résolution supérieure.

La solution la plus simple consiste à tromper .Net pour qu'il jette ces informations miniatures avant d'effectuer votre redimensionnement ou toute autre opération. comme si ....

img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);

Si vous essayez de redimensionner des proportions contraignantes, j’ai écrit une méthode d’extension sur System.Drawing.Image que vous pourriez trouver utile.

/// <summary>
/// 
/// </summary>
/// <param name="img"></param>
/// <param name="size">Size of the constraining proportion</param>
/// <param name="constrainOnWidth"></param>
/// <returns></returns>
public static System.Drawing.Image ResizeConstrainProportions(this System.Drawing.Image img,
    int size, bool constrainOnWidth, bool dontResizeIfSmaller)
{
    if (dontResizeIfSmaller && (img.Width < size))
        return img;
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
    float ratio = 0;
    ratio = (float)img.Width / (float)img.Height;

    int height, width = 0;
    if (constrainOnWidth)
    {
        height = (int)(size / ratio);
        width = size;
    }
    else
    {
        width = (int)(size * ratio);
        height = size;
    }
    return img.GetThumbnailImage(width, height, null, (new System.IntPtr(0)));
}

Cela va varier considérablement en fonction des facteurs suivants:

  1. Dans quelle mesure la résolution de la destination correspond-elle à un " naturel " échelle de la résolution d'origine
  2. La profondeur de couleur de l'image source
  3. Le (s) type (s) d'image - certains ont plus de pertes que d'autres
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top