고품질 이미지 스케일링 라이브러리 [닫기]


141

Photoshop만큼 품질 수준이 높은 C #으로 이미지의 크기를 조정하고 싶습니다. 이 작업을 수행하는 데 사용할 수있는 C # 이미지 처리 라이브러리가 있습니까?


47
이것은 C #에 있으며 다른 질문은 C ++이므로 전혀 중복되지 않습니다.
Doctor Jones

7
imageresizing.net의 당신이 얻을 수있는 크기 조정 최고 품질과 최고 성능의 이미지 라이브러리 제공. 허용되는 답변 은 많은 GDI + 함정 중 하나에 희생 되며 생성되는 각 이미지 주위에 1px 너비의 경계 아티팩트를 유발합니다. TileModeXY가 DrawImage 호출에 대한 마지막 매개 변수로 설정된 ImageAttributes 인스턴스를 사용하여 수정되었습니다.
Lilith River

2
@Computer Linguist-TileModeXY는 오타입니까? 귀하는이 답변을 여러 답변에 붙여 넣었으며 Google 검색에서 정확히 "TileModeXY"를 검색하면 게시물이 표시됩니다. System.Drawing.Drawing2D.WrapMode에 대한 다음 링크는 5 가지 가능한 값만 보여줍니다. Tile, TileFlipX, TileFlipY, TileFlipXY, 클램프 msdn.microsoft.com/en-us/library/…
JasDev

1
예, TileFlipXY 여야합니다. 수정 해 주셔서 감사합니다.
Lilith River

답변:


233

다음은 살펴보고 사용할 수있는 잘 설명 된 이미지 조작 도우미 클래스입니다. C #에서 특정 이미지 조작 작업을 수행하는 방법에 대한 예제로 작성했습니다. System.Drawing.Image, 너비 및 높이를 인수로 사용하는 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);
}

노트

이미지는 일회용이므로, 크기 조정 결과를 사용 선언에 할당해야합니다. 또는 마지막으로 try를 사용하여 마지막에 dispose를 호출 할 수 있습니다.


ImageCodecInfo jpegCodec = getEncoderInfo ( "image / jpeg"); -컴파일 할 수없는 getEncoderInfo 원인을 어디에 정의 했습니까?
ilija veselica

3
getEncoderInfo가 아니라 GetEncoderInfo를 읽어야합니다. 오타를 수정하고 클래스가 컴파일됩니다.
닥터 존스

5
+1 훌륭하게 작동합니다! 이 코드에서 수정해야 할 한 가지 문제는 품질 변수를 엔코더 매개 변수에 전달하기 전에 오랫동안 변수로 변환하는 것입니다. 그렇지 않으면 잘못된 매개 변수 런타임 예외가 발생합니다.
제임스

1
@Behzad, 보시면 SaveJpeg 함수는 quality라는 int 매개 변수를 사용합니다. 이를 호출하고 품질 매개 변수에 올바른 값을 지정해야합니다 (0에서 100 사이의 값을 허용 함).
닥터 존스

1
긴 검색 후이 답변의 크기 조정 부분 ( 전체 코드를 사용하지 않음 )은 품질 손실없이 qrcode 크기 조정에 효과적이었습니다. 올바른 설정은 결과 품질에 중요합니다.
Furkan Ekinci

15

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

코드가 변경되었는지 확실하지 않지만 new Size다음 선언에서 생략해야 했습니다 scaled.new Bitmap(original.Width * 4, original.Height * 4);
Kirk Woll

10

ImagemagickGD 와 같은 테스트 된 라이브러리 는 .NET에서 사용 가능

쌍 입방 보간과 같은 것을 읽고 자신의 글을 쓸 수도 있습니다.




4

Graphics.InterpolationMode에 대해 다른 값을 사용해보십시오. GDI +에는 몇 가지 일반적인 스케일링 알고리즘이 있습니다. 이 중 하나가 필요한 경우 외부 라이브러리에 의존하는 대신이 경로를 사용할 수 있습니다.


3

회사 제품 중 하나 인 dotImage 를 사용해보십시오 . 여기에는 다양한 품질 수준의 18 가지 필터 유형 이있는 이미지 를 리샘플링하기위한 개체 가 포함되어 있습니다.

일반적인 사용법은 다음과 같습니다.

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

또한 dotImage에는 PhotoShop의 필터와 유사한 많은 필터를 포함하여 140 개의 이상한 이미지 처리 명령이 포함되어 있습니다.


이 기능이 포함 된 SDK는 이제 일반적인 사진 형식 (JPEG, PNG 등) atalasoft.com/photofree에서 무료로 제공됩니다.
Lou Franco

/ Lu Franco : 일반 형식의 무료 버전을 프로덕션 배포에서도 무료로 사용할 수 있습니까?
Oskar Austegard 2016 년

예, DotImage Photo Free는 무료로 배포 할 수 있습니다.
Lou Franco

2

이것은 도움이 될 수 있습니다

    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->이 성능과 결과 사이의 균형이 적절히 일반적이다.


2

이 기본 코드 스 니펫을 사용해보십시오.

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

코드 프로젝트 에 .NET 용 GDI +를 사용하여 Bicubic 보간법을 사용하여 사진 크기 조정을 수행 하는 방법에 대한 기사 가 있습니다 .

다른 블로그 (MS 직원, 제 생각에는) 에이 주제에 관한 또 다른 기사가 있지만 링크를 찾을 수 없습니다. :( 아마 다른 사람이 찾을 수 있습니까?



0

이 글은 이미지 리샘플링을위한 Paint.NET의 코드 : Paul Bourke의 다양한 간단한 이미지 처리 기술 에서 참조한 기사 입니다.


1 : 좋은 기사. 링크에 액세스하지만 다른 찾을 수 없습니다 : local.wasp.uwa.edu.au/~pbourke/texture_colour/imageprocess
토마스 브랫

나는 ... 토마스 '링크로 원래의 게시물의 링크도 부서졌다 수정 paulbourke.net/texture_colour/imageprocess
오스카 Austegard

이 답변은 링크에 의존하기보다는 답변의 관련 부분을 설명하면 더 좋습니다.
KatieK

0

매직 커널을 사용해 볼 수 있습니다. 업 스케일링시 바이 큐빅 리샘플링보다 픽셀 화 아티팩트가 적고 다운 스케일링시 매우 좋은 결과를 제공합니다. 소스 코드는 웹 사이트에서 C #으로 제공됩니다.


0

닥터 존스의 대답이 약간 개선되었습니다.

이미지의 비례 크기를 조정하는 방법을 원하는 사람에게 효과적입니다. 그것은 테스트하고 나를 위해 일했습니다.

내가 추가 한 클래스의 메소드 :

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);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.