Bibliothèque de mise à l'échelle d'image de haute qualité [fermé]


141

Je souhaite redimensionner une image en C # avec un niveau de qualité aussi bon que Photoshop. Existe-t-il une bibliothèque de traitement d'image C # disponible pour faire cette chose?


47
C'est en C #, cette autre question est C ++, donc ce n'est pas du tout un doublon.
Doctor Jones

7
La bibliothèque imageresizing.net offre le redimensionnement d'image de la plus haute qualité et des plus hautes performances que vous puissiez obtenir. La réponse acceptée est victime de l'un des nombreux pièges GDI + et provoquera un artefact de bordure de 1px autour de chaque image qu'elle génère. Cela est résolu en utilisant une instance ImageAttributes avec TileModeXY défini pour le dernier paramètre de l'appel DrawImage.
Lilith River

2
@Computer Linguist - TileModeXY est-il une faute de frappe? Vous avez copié-collé ce commentaire sur plusieurs réponses et une recherche Google pour exactement "TileModeXY" ne fait que remonter vos messages. Le lien suivant pour System.Drawing.Drawing2D.WrapMode n'affiche que 5 valeurs possibles: Tile, TileFlipX, TileFlipY, TileFlipXY, Clamp msdn.microsoft.com/en-us/library/…
JasDev

1
Oui, ça devrait être TileFlipXY, merci pour la correction!
Lilith River

Réponses:


233

Voici une classe d'assistance de manipulation d'image joliment commentée que vous pouvez consulter et utiliser. Je l'ai écrit comme un exemple de la façon d'effectuer certaines tâches de manipulation d'image en C #. Vous serez intéressé par la fonction ResizeImage qui prend un System.Drawing.Image, la largeur et la hauteur comme arguments.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

namespace DoctaJonez.Drawing.Imaging
{
    /// <summary>
    /// Provides various image untilities, such as high quality resizing and the ability to save a JPEG.
    /// </summary>
    public static class ImageUtilities
    {    
        /// <summary>
        /// A quick lookup for getting image encoders
        /// </summary>
        private static Dictionary<string, ImageCodecInfo> encoders = null;

        /// <summary>
        /// A lock to prevent concurrency issues loading the encoders.
        /// </summary>
        private static object encodersLock = new object();

        /// <summary>
        /// A quick lookup for getting image encoders
        /// </summary>
        public static Dictionary<string, ImageCodecInfo> Encoders
        {
            //get accessor that creates the dictionary on demand
            get
            {
                //if the quick lookup isn't initialised, initialise it
                if (encoders == null)
                {
                    //protect against concurrency issues
                    lock (encodersLock)
                    {
                        //check again, we might not have been the first person to acquire the lock (see the double checked lock pattern)
                        if (encoders == null)
                        {
                            encoders = new Dictionary<string, ImageCodecInfo>();

                            //get all the codecs
                            foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
                            {
                                //add each codec to the quick lookup
                                encoders.Add(codec.MimeType.ToLower(), codec);
                            }
                        }
                    }
                }

                //return the lookup
                return encoders;
            }
        }

        /// <summary>
        /// Resize the image to the specified width and height.
        /// </summary>
        /// <param name="image">The image to resize.</param>
        /// <param name="width">The width to resize to.</param>
        /// <param name="height">The height to resize to.</param>
        /// <returns>The resized image.</returns>
        public static System.Drawing.Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
        {
            //a holder for the result
            Bitmap result = new Bitmap(width, height);
            //set the resolutions the same to avoid cropping due to resolution differences
            result.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            //use a graphics object to draw the resized image into the bitmap
            using (Graphics graphics = Graphics.FromImage(result))
            {
                //set the resize quality modes to high quality
                graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //draw the image into the target bitmap
                graphics.DrawImage(image, 0, 0, result.Width, result.Height);
            }

            //return the resulting bitmap
            return result;
        }

        /// <summary> 
        /// Saves an image as a jpeg image, with the given quality 
        /// </summary> 
        /// <param name="path">Path to which the image would be saved.</param> 
        /// <param name="quality">An integer from 0 to 100, with 100 being the 
        /// highest quality</param> 
        /// <exception cref="ArgumentOutOfRangeException">
        /// An invalid value was entered for image quality.
        /// </exception>
        public static void SaveJpeg(string path, Image image, int quality)
        {
            //ensure the quality is within the correct range
            if ((quality < 0) || (quality > 100))
            {
                //create the error message
                string error = string.Format("Jpeg image quality must be between 0 and 100, with 100 being the highest quality.  A value of {0} was specified.", quality);
                //throw a helpful exception
                throw new ArgumentOutOfRangeException(error);
            }

            //create an encoder parameter for the image quality
            EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
            //get the jpeg codec
            ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");

            //create a collection of all parameters that we will pass to the encoder
            EncoderParameters encoderParams = new EncoderParameters(1);
            //set the quality parameter for the codec
            encoderParams.Param[0] = qualityParam;
            //save the image using the codec and the parameters
            image.Save(path, jpegCodec, encoderParams);
        }

        /// <summary> 
        /// Returns the image codec with the given mime type 
        /// </summary> 
        public static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            //do a case insensitive search for the mime type
            string lookupKey = mimeType.ToLower();

            //the codec to return, default to null
            ImageCodecInfo foundCodec = null;

            //if we have the encoder, get it to return
            if (Encoders.ContainsKey(lookupKey))
            {
                //pull the codec from the lookup
                foundCodec = Encoders[lookupKey];
            }

            return foundCodec;
        } 
    }
}

Mettre à jour

Quelques personnes ont demandé dans les commentaires des exemples de consommation de la classe ImageUtilities, alors c'est parti.

//resize the image to the specified height and width
using (var resized = ImageUtilities.ResizeImage(image, 50, 100))
{
    //save the resized image as a jpeg with a quality of 90
    ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
}

Remarque

N'oubliez pas que les images sont jetables, vous devez donc attribuer le résultat de votre redimensionnement à une déclaration using (ou vous pouvez utiliser un essai enfin et vous assurer d'appeler dispose dans votre enfin).


ImageCodecInfo jpegCodec = getEncoderInfo ("image / jpeg"); - où avez-vous défini getEncoderInfo parce que je ne peux pas le compiler
ilija veselica

3
Il doit lire GetEncoderInfo et non getEncoderInfo. J'ai corrigé la faute de frappe et la classe se compile maintenant.
Doctor Jones

5
+1 cela fonctionne à merveille! Un problème que vous devez corriger dans ce code est de convertir la variable de qualité en long avant de la transmettre au paramètre de l'encodeur, sinon vous obtiendrez une exception d'exécution de paramètre non valide.
James

1
@Behzad, si vous regardez, la fonction SaveJpeg prend un paramètre int appelé quality. Vous devez appeler cela et spécifier la valeur correcte pour le paramètre de qualité (il accepte une valeur comprise entre 0 et 100).
Doctor Jones

1
Après une longue recherche, la partie dimensionnement de cette réponse ( n'a pas utilisé le code entier ) a fonctionné pour le redimensionnement de qrcode sans perte de qualité. Les bons réglages sont importants pour la qualité des résultats.
Furkan Ekinci

15

Lorsque vous dessinez l'image en utilisant GDI +, elle s'adapte assez bien à mon avis. Vous pouvez l'utiliser pour créer une image mise à l'échelle.

Si vous souhaitez mettre à l'échelle votre image avec GDI +, vous pouvez faire quelque chose comme ceci:

Bitmap original = ...
Bitmap scaled = new Bitmap(new Size(original.Width * 4, original.Height * 4));
using (Graphics graphics = Graphics.FromImage(scaled)) {
  graphics.DrawImage(original, new Rectangle(0, 0, scaled.Width, scaled.Height));
}

Je ne sais pas si le code a changé, mais j'ai dû omettre le new Sizedans la déclaration de scaled:new Bitmap(original.Width * 4, original.Height * 4);
Kirk Woll

10

Bibliothèques testées comme Imagemagick et GD sont disponibles pour .NET

Vous pouvez également lire sur des choses comme l'interpolation bicubique et écrire le vôtre.




4

Essayez les différentes valeurs de Graphics.InterpolationMode. Il existe plusieurs algorithmes de mise à l'échelle typiques disponibles dans GDI +. Si l'un d'entre eux est suffisant pour vos besoins, vous pouvez emprunter cette voie au lieu de vous fier à une bibliothèque externe.


3

Vous pouvez essayer dotImage , l'un des produits de mon entreprise, qui comprend un objet pour rééchantillonner les images avec 18 types de filtres pour différents niveaux de qualité.

L'utilisation typique est:

// BiCubic is one technique available in PhotoShop
ResampleCommand resampler = new ResampleCommand(newSize, ResampleMethod.BiCubic);
AtalaImage newImage = resampler.Apply(oldImage).Image;

de plus, dotImage comprend 140 quelques commandes de traitement d'image étranges, y compris de nombreux filtres similaires à ceux de PhotoShop, si c'est ce que vous recherchez.


Le SDK avec cette fonctionnalité est maintenant disponible gratuitement pour les formats photo courants (JPEG, PNG, etc.) atalasoft.com/photofree
Lou Franco

/ Lou Franco: la version gratuite au format commun peut-elle être utilisée dans les déploiements de production, également gratuitement?
Oskar Austegard le

Oui, DotImage Photo Free peut être déployé gratuitement.
Lou Franco

2

Cela pourrait aider

    public Image ResizeImage(Image source, RectangleF destinationBounds)
    {
        RectangleF sourceBounds = new RectangleF(0.0f,0.0f,(float)source.Width, (float)source.Height);
        RectangleF scaleBounds = new RectangleF();

        Image destinationImage = new Bitmap((int)destinationBounds.Width, (int)destinationBounds.Height);
        Graphics graph = Graphics.FromImage(destinationImage);
        graph.InterpolationMode =
            System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

        // Fill with background color
        graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), destinationBounds);

        float resizeRatio, sourceRatio;
        float scaleWidth, scaleHeight;

        sourceRatio = (float)source.Width / (float)source.Height;

        if (sourceRatio >= 1.0f)
        {
            //landscape
            resizeRatio = destinationBounds.Width / sourceBounds.Width;
            scaleWidth = destinationBounds.Width;
            scaleHeight = sourceBounds.Height * resizeRatio;
            float trimValue = destinationBounds.Height - scaleHeight;
            graph.DrawImage(source, 0, (trimValue / 2), destinationBounds.Width, scaleHeight);
        }
        else
        {
            //portrait
            resizeRatio = destinationBounds.Height/sourceBounds.Height;
            scaleWidth = sourceBounds.Width * resizeRatio;
            scaleHeight = destinationBounds.Height;
            float trimValue = destinationBounds.Width - scaleWidth;
            graph.DrawImage(source, (trimValue / 2), 0, scaleWidth, destinationBounds.Height);
        }

        return destinationImage;

    }

Notez le InterpolationMode.HighQualityBicubic-> c'est généralement un bon compromis entre les performances et les résultats.


2

Essayez cet extrait de code de base:

private static Bitmap ResizeBitmap(Bitmap srcbmp, int width, int height )
{
    Bitmap newimage = new Bitmap(width, height);
    using (Graphics g = Graphics.FromImage(newimage))
           g.DrawImage(srcbmp, 0, 0, width, height);
    return newimage;
}

0

Il existe un article sur Code Project sur l'utilisation de GDI + pour .NET pour redimensionner des photos à l'aide, par exemple, d'une interpolation bicubique.

Il y avait aussi un autre article sur ce sujet sur un autre blog (employé MS, je pense), mais je ne trouve le lien nulle part. :( Peut-être que quelqu'un d'autre peut le trouver?



0

C'est un article que j'ai repéré référencé dans le code de Paint.NET pour le rééchantillonnage d'image: diverses techniques simples de traitement d'image par Paul Bourke.


1: Bel article. Impossible d'accéder au lien, mais en a trouvé un autre: local.wasp.uwa.edu.au/~pbourke/texture_colour/imageprocess
Thomas Bratt

J'ai corrigé le lien dans le message original car le lien de Thomas était également cassé ... paulbourke.net/texture_colour/imageprocess
Oskar Austegard

Cette réponse serait meilleure si elle expliquait les parties pertinentes de la réponse, plutôt que de s'appuyer sur le lien.
KatieK

0

Vous pouvez essayer le noyau magique . Il produit moins d'artefacts de pixellisation que le rééchantillonnage bicubique lors de la mise à l'échelle et donne également de très bons résultats lors de la réduction. Le code source est disponible en c # sur le site Web.


0

J'ai quelques améliorations pour la réponse du docteur Jones.

Cela fonctionne pour qui voulait redimensionner proportionnellement l'image. Cela a testé et a fonctionné pour moi.

Les méthodes de classe que j'ai ajoutées:

public static System.Drawing.Bitmap ResizeImage(System.Drawing.Image image, Size size)
{
    return ResizeImage(image, size.Width, size.Height);
}


public static Size GetProportionedSize(Image image, int maxWidth, int maxHeight, bool withProportion)
{
    if (withProportion)
    {
        double sourceWidth = image.Width;
        double sourceHeight = image.Height;

        if (sourceWidth < maxWidth && sourceHeight < maxHeight)
        {
            maxWidth = (int)sourceWidth;
            maxHeight = (int)sourceHeight;
        }
        else
        {
            double aspect = sourceHeight / sourceWidth;

            if (sourceWidth < sourceHeight)
            {
                maxWidth = Convert.ToInt32(Math.Round((maxHeight / aspect), 0));
            }
            else
            {
                maxHeight = Convert.ToInt32(Math.Round((maxWidth * aspect), 0));
            }
        }
    }

    return new Size(maxWidth, maxHeight);
}

et nouveau disponible en utilisant selon ces codes:

using (var resized = ImageUtilities.ResizeImage(image, ImageUtilities.GetProportionedSize(image, 50, 100)))
{
    ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.