proportionally net imagesharp change c# image image-processing image-manipulation image-scaling

c# - net - Biblioteca de escalamiento de imágenes de alta calidad



resize image c# (14)

Quiero escalar una imagen en C # con un nivel de calidad tan bueno como Photoshop. ¿Hay alguna biblioteca de procesamiento de imágenes C # disponible para hacer esto?


Aquí hay una clase de ayuda de manipulación de imágenes muy bien comentada que puedes ver y usar. Lo escribí como un ejemplo de cómo realizar ciertas tareas de manipulación de imágenes en C #. Le interesará la función ResizeImage que toma un System.Drawing.Image, el ancho y el alto como argumentos.

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

Actualizar

Algunas personas han estado preguntando en los comentarios sobre ejemplos de cómo consumir la clase ImageUtilities, así que aquí tienes.

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

Nota

Recuerde que las imágenes son desechables, por lo que debe asignar el resultado de su cambio de tamaño a una declaración de uso (o puede usar una prueba finalmente y asegurarse de que llame finalmente a deshacerse de ella).



Bibliotecas Imagemagick como Imagemagick y GD están disponibles para .NET

También puede leer cosas como la interpolación bicúbica y escribir la suya propia.


Cuando dibujas la imagen usando GDI +, se escala bastante bien en mi opinión. Puede usar esto para crear una imagen escalada.

Si quieres escalar tu imagen con GDI +, puedes hacer algo como esto:

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



Esto podría ayudar

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

Tenga en cuenta el InterpolationMode.HighQualityBicubic -> esto es generalmente una buena compensación entre el rendimiento y los resultados.


Hay un artículo sobre Code Project sobre el uso de GDI + para .NET para hacer el cambio de tamaño de las fotos usando, digamos, la interpolación Bicubic.

También hubo otro artículo sobre este tema en otro blog (empleado de MS, creo), pero no puedo encontrar el enlace en ninguna parte. :( Tal vez alguien más puede encontrarlo?


Podrías probar el kernel mágico . Produce menos artefactos de pixelación que remuestreo bicúbico cuando se realiza una ampliación y también da muy buenos resultados cuando se realiza una reducción a escala. El código fuente está disponible en c # desde el sitio web.


Pruebe este fragmento de código básico:

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


Pruebe los diferentes valores para Graphics.InterpolationMode. Hay varios algoritmos de escalado típicos disponibles en GDI +. Si uno de estos es suficiente para su necesidad, puede seguir esta ruta en lugar de confiar en una biblioteca externa.


Puede probar dotImage , uno de los productos de mi compañía, que incluye un objeto para remuestrear imágenes que tiene 18 tipos de filtro para varios niveles de calidad.

El uso típico es:

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

Además, dotImage incluye 140 comandos de procesamiento de imágenes extrañas que incluyen muchos filtros similares a los de PhotoShop, si eso es lo que estás buscando.


Tengo algunas mejoras para la respuesta del Doctor Jones.

Funciona para quién quería cómo cambiar el tamaño proporcional de la imagen. Me probó y trabajó para mí.

Los métodos de la clase I añadieron:

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

y nuevo disponible usando según estos códigos:

using (var resized = ImageUtilities.ResizeImage(image, ImageUtilities.GetProportionedSize(image, 50, 100))) { ImageUtilities.SaveJpeg(@"C:/myimage.jpeg", resized, 90); }