Библиотека масштабирования изображений высокого качества [закрыто]


Я хочу масштабировать изображение в C# с уровнем качества так же хорошо, как Photoshop. Есть ли библиотека обработки изображений C#, доступная для этого?

14 142

14 ответов:

вот красиво прокомментированный вспомогательный класс обработки изображений, который вы можете посмотреть и использовать. Я написал его в качестве примера того, как выполнять определенные задачи обработки изображений в C#. Вы будете заинтересованы в ResizeImage функция, которая принимает система.Рисунок.Изображения, ширина и высота в качестве аргументов.

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

обновление

несколько человек спрашивали в комментариях образцы того, как использовать класс ImageUtilities, поэтому здесь вы идете.

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

Примечание

помните, что изображения являются одноразовыми, поэтому вам нужно назначить результат вашего изменения размера для объявления using (или вы можете использовать try finally и убедитесь, что вы вызываете dispose в своем finally).

когда вы рисуете изображение с помощью GDI+ он масштабируется довольно хорошо, на мой взгляд. Вы можете использовать это для создания масштабированного изображения.

Если вы хотите масштабировать изображение с GDI+ вы можете сделать что-то вроде этого:

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

проверенные библиотеки типа Imagemagick и GD доступны для .NET

вы также можете прочитать о таких вещах, как бикубическая интерполяция и написать свой собственный.

используйте эту библиотеку:http://imageresizing.net

прочтите эту статью автора библиотеки: 20 подводных камней размера изображения с .NET

попробуйте различные значения для графики.InterpolationMode. Существует несколько типичных алгоритмов масштабирования, доступных в GDI+. Если одного из них достаточно для вашей потребности, вы можете пойти по этому маршруту вместо того, чтобы полагаться на внешнюю библиотеку.

вы можете попробовать dotImage, один из продуктов моей компании, который включает в себя

Это может помочь

    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;

    }

Примечание InterpolationMode.HighQualityBicubic -> это, как правило, хороший компромисс между производительностью и результатами.

попробуйте этот основной фрагмент кода:

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

здесь статья о проекте кода об использовании GDI+ для .NET для изменения размера фотографий с использованием, скажем, Бикубической интерполяции.

была также еще одна статья на эту тему в другом блоге (MS employee, я думаю), но я не могу найти ссылку нигде. (Возможно, кто-то еще может найти его?

вы можете попробовать это, если это lowres cgi 2D фильтр изображений

Это статья, на которую я заметил ссылку Paint.NET код для пересчета изображений: Различные Простые Методы Обработки Изображений Пол Бурк.

вы могли бы попробовать магические ядра. Он производит меньше артефактов пикселизации, чем бикубическая повторная выборка при увеличении масштаба, а также дает очень хорошие результаты при уменьшении масштаба. Исходный код доступен на языке c# с веб-сайта.

у меня есть некоторые улучшения для ответа доктора Джонса.

он работает для тех, кто хотел, как пропорционально изменить размер изображения. Он проверил и работал для меня.

методы класса I добавил:

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

и новое доступное использование согласно этим кодам:

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