Thư viện nhân rộng hình ảnh chất lượng cao [đóng]


141

Tôi muốn chia tỷ lệ hình ảnh trong C # với mức chất lượng tốt như Photoshop. Có thư viện xử lý ảnh C # nào để làm việc này không?


47
Đây là trong C #, câu hỏi khác là C ++, vì vậy nó hoàn toàn không phải là một bản sao.
Bác sĩ Jones

7
Các imageresizing.net thư viện cung cấp chất lượng cao nhất và hình ảnh hiệu suất cao nhất thay đổi kích thước, bạn có thể nhận được. Câu trả lời được chấp nhận trở thành nạn nhân của một trong nhiều cạm bẫy GDI + và sẽ gây ra một tạo tác viền rộng 1px xung quanh mỗi hình ảnh mà nó tạo ra. Điều đó đã được khắc phục bằng cách sử dụng một phiên bản ImageAttribution với tập hợp TileModeXY cho tham số cuối cùng cho lệnh gọi DrawImage.
Sông Lilith

2
@Computer Linguist - là TileModeXY có phải là một lỗi đánh máy không? Bạn đã sao chép dán nhận xét này qua một số câu trả lời và một tìm kiếm google cho chính xác "TileModeXY" chỉ hiển thị các bài đăng của bạn. Các liên kết sau để System.Drawing.Drawing2D.WrapMode chỉ hiển thị 5 giá trị có thể: Ngói, TileFlipX, TileFlipY, TileFlipXY, kẹp msdn.microsoft.com/en-us/library/...
JasDev

1
Vâng, nó phải là TileFlipXY, cảm ơn vì đã sửa!
Sông Lilith

Câu trả lời:


233

Dưới đây là một lớp trợ giúp Image Manipulation được nhận xét độc đáo mà bạn có thể xem và sử dụng. Tôi đã viết nó như một ví dụ về cách thực hiện các tác vụ thao tác hình ảnh nhất định trong C #. Bạn sẽ quan tâm đến chức năng ResizeImage lấy System.Drawing.Image, chiều rộng và chiều cao làm đối số.

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

Cập nhật

Một vài người đã hỏi ý kiến ​​về các mẫu về cách tiêu thụ lớp ImageUtilities, vì vậy bạn hãy vào đây.

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

Ghi chú

Hãy nhớ rằng hình ảnh là dùng một lần, vì vậy bạn cần gán kết quả thay đổi kích thước của mình cho một khai báo sử dụng (hoặc cuối cùng bạn có thể sử dụng thử và đảm bảo rằng bạn đã gọi xử lý cuối cùng).


ImageCodecInfo jpegCodec = getEncoderInfo ("hình ảnh / jpeg"); - bạn đã xác định getEncoderInfo ở đâu vì tôi không thể biên dịch nó
ilija veselica

3
Nó nên đọc GetEncoderInfo chứ không phải getEncoderInfo. Tôi đã sửa lỗi chính tả và lớp biên dịch ngay bây giờ.
Bác sĩ Jones

5
+1 này hoạt động rực rỡ! Một vấn đề bạn cần sửa trong mã này là chuyển đổi biến chất lượng thành lâu trước khi chuyển nó sang tham số bộ mã hóa hoặc bạn sẽ nhận được ngoại lệ thời gian chạy tham số không hợp lệ.
James

1
@Behzad, nếu bạn nhìn, hàm SaveJpeg có một tham số int gọi là quality. Bạn cần gọi đó và chỉ định giá trị chính xác cho tham số chất lượng (nó chấp nhận giá trị từ 0 đến 100).
Bác sĩ Jones

1
Sau một thời gian dài tìm kiếm, phần kích thước của câu trả lời này ( không sử dụng toàn bộ mã ) đã hoạt động để thay đổi kích thước qrcode mà không làm giảm chất lượng. Cài đặt đúng là rất quan trọng đối với chất lượng kết quả.
Furkan Ekinci

15

Khi bạn vẽ hình ảnh bằng GDI +, nó có tỷ lệ khá tốt theo quan điểm của tôi. Bạn có thể sử dụng điều này để tạo ra một hình ảnh tỷ lệ.

Nếu bạn muốn chia tỷ lệ hình ảnh của mình bằng GDI +, bạn có thể làm một cái gì đó như thế này:

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

Không chắc chắn nếu mã đã thay đổi, nhưng tôi đã phải bỏ qua new Sizephần khai báo scaled:new Bitmap(original.Width * 4, original.Height * 4);
Kirk Woll

10

Các thư viện đã thử nghiệm như ImagemagickGD có sẵn cho .NET

Bạn cũng có thể đọc lên những thứ như nội suy hai chiều và tự viết.




4

Hãy thử các giá trị khác nhau cho Graphics.InterpolationMode. Có một số thuật toán chia tỷ lệ điển hình có sẵn trong GDI +. Nếu một trong số này là đủ cho nhu cầu của bạn, bạn có thể đi tuyến đường này thay vì dựa vào thư viện bên ngoài.


3

Bạn có thể thử dotImage , một trong những sản phẩm của công ty tôi, bao gồm một đối tượng để lấy mẫu lại hình ảnh có 18 loại bộ lọc cho các mức chất lượng khác nhau.

Cách sử dụng điển hình là:

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

Ngoài ra, dotImage bao gồm 140 một số lệnh xử lý hình ảnh kỳ lạ bao gồm nhiều bộ lọc tương tự như các bộ lọc trong PhotoShop, nếu đó là những gì bạn đang tìm kiếm.


SDK với tính năng này hiện có sẵn miễn phí cho các định dạng ảnh phổ biến (JPEG, PNG, v.v.) atalasoft.com/photofree
Lou Franco

/ Lou Franco: phiên bản miễn phí định dạng phổ biến có thể được sử dụng trong triển khai sản xuất, cũng miễn phí không?
Oskar Austegard

Có, DotImage Photo Free được triển khai miễn phí.
Lou Franco

2

Điều này có thể giúp

    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;

    }

Lưu ý InterpolationMode.HighQualityBicubic-> đây thường là sự đánh đổi tốt giữa hiệu suất và kết quả.


2

Hãy thử đoạn mã cơ bản này:

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

Có một bài viết về Dự án mã về việc sử dụng GDI + cho .NET để thực hiện thay đổi kích thước ảnh bằng cách sử dụng phép nội suy bicubic.

Ngoài ra còn có một bài viết khác về chủ đề này trên một blog khác (nhân viên MS, tôi nghĩ vậy), nhưng tôi không thể tìm thấy liên kết ở bất cứ đâu. :( Có lẽ người khác có thể tìm thấy nó?



0

Đây là một bài viết tôi phát hiện ra được tham chiếu trong mã của Paint.NET để lấy mẫu lại hình ảnh: Các kỹ thuật xử lý hình ảnh đơn giản khác nhau của Paul Bourke.


1: Bài viết hay. Không thể truy cập vào liên kết nhưng tìm thấy liên kết này: local.wasp.uwa.edu.au/~pbourke/texture_colour/image process
Thomas Bratt

Tôi đã sửa liên kết trong bài viết gốc vì liên kết của Thomas cũng bị hỏng ... paulbourke.net/texture_colour/image Process
Oskar Austegard

Câu trả lời này sẽ tốt hơn nếu nó giải thích các phần thích hợp của câu trả lời, thay vì dựa vào liên kết.
KatieK

0

Bạn có thể thử hạt nhân ma thuật . Nó tạo ra các tạo phẩm pixel ít hơn so với mẫu lại bicubic khi nâng cấp và nó cũng cho kết quả rất tốt khi thu nhỏ. Mã nguồn có sẵn trong c # từ trang web.


0

Tôi có một số cải thiện cho câu trả lời của Doctor Jones.

Nó hoạt động cho những người muốn làm thế nào để thay đổi kích thước hình ảnh. Nó đã thử nghiệm và làm việc cho tôi.

Các phương thức của lớp tôi đã thêm:

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

và mới có sẵn bằng cách sử dụng theo mã này:

using (var resized = ImageUtilities.ResizeImage(image, ImageUtilities.GetProportionedSize(image, 50, 100)))
{
    ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.