Perpustakaan Penskalaan Gambar Kualitas Tinggi [ditutup]


141

Saya ingin skala gambar di C # dengan tingkat kualitas sebagus Photoshop. Apakah ada pustaka pemrosesan gambar C # yang tersedia untuk melakukan hal ini?


47
Ini di C #, pertanyaan lain adalah C ++, jadi itu bukan duplikat sama sekali.
Dokter Jones

7
The imageresizing.net menawarkan perpustakaan-kualitas tertinggi dan citra kinerja tertinggi Resize Anda bisa mendapatkan. Jawaban yang diterima menjadi korban salah satu dari banyak perangkap GDI + dan akan menyebabkan artefak perbatasan lebar 1px di sekitar setiap gambar yang dihasilkannya. Itu diperbaiki dengan menggunakan instance ImageAttributes dengan TileModeXY yang ditetapkan untuk parameter terakhir ke panggilan DrawImage.
Sungai Lilith

2
@Komputer Linguist - apakah TileModeXY salah ketik? Anda telah menyalin komentar ini di beberapa jawaban dan pencarian google untuk "TileModeXY" persisnya hanya memunculkan posting Anda. Tautan berikut untuk System.Drawing.Drawing2D.WrapMode hanya menunjukkan 5 nilai yang mungkin: Tile, TileFlipX, TileFlipY, TileFlipXY, Clamp msdn.microsoft.com/en-us/library/…
JasDev

1
Ya, itu pasti TileFlipXY, terima kasih atas koreksinya!
Sungai Lilith

Jawaban:


233

Inilah kelas pembantu Image Manipulasi yang baik yang dapat Anda lihat dan gunakan. Saya menulisnya sebagai contoh bagaimana melakukan tugas manipulasi gambar tertentu dalam C #. Anda akan tertarik dengan fungsi ResizeImage yang menggunakan System.Drawing.Image, lebar dan tinggi sebagai argumen.

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

Memperbarui

Beberapa orang telah meminta di komentar untuk sampel tentang bagaimana cara mengkonsumsi kelas ImageUtilities, jadi begini.

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

Catatan

Ingatlah bahwa gambar dapat dibuang, jadi Anda harus menetapkan hasil pengubahan ukuran Anda ke deklarasi menggunakan (atau Anda bisa menggunakan percobaan terakhir dan pastikan Anda memanggil buang akhirnya).


ImageCodecInfo jpegCodec = getEncoderInfo ("image / jpeg"); - di mana Anda mendefinisikan getEncoderInfo karena saya tidak dapat mengompilasinya
ilija veselica

3
Seharusnya membaca GetEncoderInfo dan bukan getEncoderInfo. Saya memperbaiki kesalahan ketik dan mengkompilasi kelas sekarang.
Dokter Jones

5
+1 ini bekerja dengan sangat baik! Salah satu masalah yang perlu Anda perbaiki dalam kode ini adalah mengubah variabel kualitas menjadi lama sebelum meneruskannya ke param enkoder atau Anda akan mendapatkan pengecualian runtime parameter yang tidak valid.
James

1
@Behzad, jika Anda melihat, fungsi SaveJpeg mengambil parameter int yang disebut kualitas. Anda perlu memanggil itu dan menentukan nilai yang benar untuk parameter kualitas (itu menerima nilai antara 0 dan 100).
Dokter Jones

1
Setelah pencarian yang panjang, bagian ukuran jawaban ini ( tidak menggunakan seluruh kode ) berfungsi untuk mengubah ukuran qrcode tanpa kehilangan kualitas. Pengaturan yang tepat penting untuk kualitas hasil.
Furkan Ekinci

15

Ketika Anda menggambar gambar menggunakan GDI + itu cukup baik menurut pendapat saya. Anda dapat menggunakan ini untuk membuat gambar yang diskalakan.

Jika Anda ingin skala gambar Anda dengan GDI + Anda dapat melakukan sesuatu seperti ini:

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

Tidak yakin apakah kode telah berubah, tetapi saya harus menghilangkannya new Sizedalam deklarasi scaled:new Bitmap(original.Width * 4, original.Height * 4);
Kirk Woll

10

Pustaka yang diuji seperti Imagemagick dan GD tersedia untuk .NET

Anda juga bisa membaca tentang hal-hal seperti interpolasi bikubik dan menulis sendiri.




4

Coba nilai yang berbeda untuk Graphics.InterpolationMode. Ada beberapa algoritma penskalaan khas yang tersedia di GDI +. Jika salah satu dari ini cukup untuk kebutuhan Anda, Anda bisa menggunakan rute ini alih-alih mengandalkan perpustakaan eksternal.


3

Anda dapat mencoba dotImage , salah satu produk perusahaan saya, yang mencakup objek untuk resampling gambar yang memiliki 18 jenis filter untuk berbagai tingkat kualitas.

Penggunaan umum adalah:

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

selain itu, dotImage menyertakan 140 beberapa perintah pemrosesan gambar aneh termasuk banyak filter yang mirip dengan yang ada di PhotoShop, jika itu yang Anda cari.


SDK dengan fitur ini sekarang tersedia secara gratis untuk format foto umum (JPEG, PNG, dll) atalasoft.com/photofree
Lou Franco

/ Lou Franco: dapatkah versi gratis format umum digunakan dalam penyebaran produksi, juga gratis?
Oskar Austegard

Ya, DotImage Photo Free gratis untuk digunakan.
Lou Franco

2

Ini mungkin bisa membantu

    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;

    }

Perhatikan InterpolationMode.HighQualityBicubic-> ini umumnya merupakan tradeoff yang baik antara kinerja dan hasil.


2

Coba cuplikan kode dasar ini:

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

Ada artikel tentang Proyek Kode tentang menggunakan GDI + untuk .NET untuk melakukan pengubahan ukuran foto menggunakan, katakanlah, interpolasi Bicubic.

Ada juga artikel lain tentang topik ini di blog lain (karyawan MS, saya pikir), tetapi saya tidak dapat menemukan tautan di mana pun. :( Mungkin orang lain bisa menemukannya?



0

Ini adalah artikel yang saya lihat dirujuk dalam kode Paint.NET untuk resampling gambar: Berbagai Teknik Pemrosesan Gambar Sederhana oleh Paul Bourke.


1: Artikel yang bagus. Tidak dapat mengakses tautan tetapi menemukan ini yang lain: local.wasp.uwa.edu.au/~paintke/texture_colour/imageprocess
Thomas Bratt

Saya mengoreksi tautan dalam pos asli karena tautan Thomas juga rusak ... paulbourke.net/texture_colour/imageprocess
Oskar Austegard

Jawaban ini akan lebih baik jika menjelaskan bagian-bagian terkait dari jawaban itu, daripada mengandalkan tautannya.
KatieK

0

Anda dapat mencoba kernel ajaib . Ini menghasilkan artefak pixelation lebih sedikit dari bicubic resample ketika upscaling dan juga memberikan hasil yang sangat baik ketika downscaling. Kode sumber tersedia dalam c # dari situs web.


0

Saya memiliki beberapa perbaikan untuk jawaban Dokter Jones.

Ini bekerja untuk siapa yang ingin bagaimana mengubah ukuran gambar secara proporsional. Ini diuji dan bekerja untuk saya.

Metode kelas I menambahkan:

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

dan baru tersedia menggunakan sesuai dengan kode ini:

using (var resized = ImageUtilities.ResizeImage(image, ImageUtilities.GetProportionedSize(image, 50, 100)))
{
    ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.