Ubah ukuran gambar secara proporsional dengan batasan MaxHeight dan MaxWidth

124

Menggunakan System.Drawing.Image.

Jika lebar atau tinggi gambar melebihi maksimum, itu perlu diubah ukurannya secara proporsional. Setelah diubah ukurannya, perlu dipastikan tidak ada lebar atau tinggi yang masih melebihi batas.

Lebar dan Tinggi akan diubah ukurannya hingga tidak melebihi maksimum dan minimum secara otomatis (ukuran sebesar mungkin) dan juga mempertahankan rasionya.

Sarawut Positwinyu
sumber
@Sarawut Positwinyu - Tapi rasio aspek apa yang Anda inginkan?
Bibhu
Apa yang Anda inginkan terjadi jika gambar tidak dapat diubah ukurannya ke maksimum dan min dari tinggi dan lebar dan rasio aspek dipertahankan?
Conrad Frix
@Bibhu Apakah ada banyak jenis rasio aspek? saya tidak tahu tentang itu. Saya hanya ingin rasio gambarnya mirip dengan iklan rasio gambar aslinya.
Sarawut Positwinyu
@Sarawut Positwinyu - lihat tautan wiki ini untuk informasi lebih lanjut tentang rasio aspek. en.wikipedia.org/wiki/Aspect_ratio_%28image%29
Bibhu
1
@Sarawut Positwinyu Anda tidak menyalahgunakan istilah rasio aspek. Atau jika Anda melakukannya, Anda berada di perusahaan yang baik
Conrad Frix

Jawaban:

300

Seperti ini?

public static void Test()
{
    using (var image = Image.FromFile(@"c:\logo.png"))
    using (var newImage = ScaleImage(image, 300, 400))
    {
        newImage.Save(@"c:\test.png", ImageFormat.Png);
    }
}

public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
    var ratioX = (double)maxWidth / image.Width;
    var ratioY = (double)maxHeight / image.Height;
    var ratio = Math.Min(ratioX, ratioY);

    var newWidth = (int)(image.Width * ratio);
    var newHeight = (int)(image.Height * ratio);

    var newImage = new Bitmap(newWidth, newHeight);

    using (var graphics = Graphics.FromImage(newImage))
        graphics.DrawImage(image, 0, 0, newWidth, newHeight);

    return newImage;
}
Alex Aza
sumber
7
@Alex penggunaan yang bagus dari Math.Min (Saya selalu lupa tentang yang satu itu)
Conrad Frix
5
Saya sarankan Anda menggunakan pernyataan menggunakan pada objek Grafik setidaknya untuk menghemat beberapa sumber daya :)
Schalk
Saya hanya memikirkan sebuah kasus, saya tidak yakin apakah mungkin atau tidak setelah dikalikan dengan rasio lebar atau tinggi mungkin masih lebih besar dari lebar atau tinggi maks.
Sarawut Positwinyu
4
Pastikan juga Anda menggunakan System.Drawing.Image jika menggunakan asp.net.
Induster
1
@Smith - jangan jalankan metode Save jika Anda tidak perlu menyimpan gambar. Inilah yang dilakukan metode ScaleImage saya - mengembalikan gambar tanpa menyimpannya.
Alex Aza
5

Solusi Kerja:

Untuk Ubah ukuran gambar dengan ukuran lebih rendah dari 100Kb

WriteableBitmap bitmap = new WriteableBitmap(140,140);
bitmap.SetSource(dlg.File.OpenRead());
image1.Source = bitmap;

Image img = new Image();
img.Source = bitmap;
WriteableBitmap i;

do
{
    ScaleTransform st = new ScaleTransform();
    st.ScaleX = 0.3;
    st.ScaleY = 0.3;
    i = new WriteableBitmap(img, st);
    img.Source = i;
} while (i.Pixels.Length / 1024 > 100);

Referensi Lebih Lanjut di http://net4attack.blogspot.com/

pengguna806084
sumber
5

Solusi yang jauh lebih lama, tetapi memperhitungkan skenario berikut ini:

  1. Apakah gambar lebih kecil dari kotak pembatas?
  2. Apakah Gambar dan Kotak Bounding berbentuk persegi?
  3. Apakah gambar persegi dan kotak pembatas tidak
  4. Apakah gambar lebih lebar dan lebih tinggi dari kotak pembatas
  5. Apakah gambar lebih lebar dari kotak pembatas
  6. Apakah gambar lebih tinggi dari kotak pembatas

    private Image ResizePhoto(FileInfo sourceImage, int desiredWidth, int desiredHeight)
    {
        //throw error if bouning box is to small
        if (desiredWidth < 4 || desiredHeight < 4)
            throw new InvalidOperationException("Bounding Box of Resize Photo must be larger than 4X4 pixels.");            
        var original = Bitmap.FromFile(sourceImage.FullName);
    
        //store image widths in variable for easier use
        var oW = (decimal)original.Width;
        var oH = (decimal)original.Height;
        var dW = (decimal)desiredWidth;
        var dH = (decimal)desiredHeight;
    
        //check if image already fits
        if (oW < dW && oH < dH)
            return original; //image fits in bounding box, keep size (center with css) If we made it bigger it would stretch the image resulting in loss of quality.
    
        //check for double squares
        if (oW == oH && dW == dH)
        {
            //image and bounding box are square, no need to calculate aspects, just downsize it with the bounding box
            Bitmap square = new Bitmap(original, (int)dW, (int)dH);
            original.Dispose();
            return square;
        }
    
        //check original image is square
        if (oW == oH)
        {
            //image is square, bounding box isn't.  Get smallest side of bounding box and resize to a square of that center the image vertically and horizontally with Css there will be space on one side.
            int smallSide = (int)Math.Min(dW, dH);
            Bitmap square = new Bitmap(original, smallSide, smallSide);
            original.Dispose();
            return square;
        }
    
        //not dealing with squares, figure out resizing within aspect ratios            
        if (oW > dW && oH > dH) //image is wider and taller than bounding box
        {
            var r = Math.Min(dW, dH) / Math.Min(oW, oH); //two dimensions so figure out which bounding box dimension is the smallest and which original image dimension is the smallest, already know original image is larger than bounding box
            var nH = oH * r; //will downscale the original image by an aspect ratio to fit in the bounding box at the maximum size within aspect ratio.
            var nW = oW * r;
            var resized = new Bitmap(original, (int)nW, (int)nH);
            original.Dispose();
            return resized;
        }
        else
        {
            if (oW > dW) //image is wider than bounding box
            {
                var r = dW / oW; //one dimension (width) so calculate the aspect ratio between the bounding box width and original image width
                var nW = oW * r; //downscale image by r to fit in the bounding box...
                var nH = oH * r;
                var resized = new Bitmap(original, (int)nW, (int)nH);
                original.Dispose();
                return resized;
            }
            else
            {
                //original image is taller than bounding box
                var r = dH / oH;
                var nH = oH * r;
                var nW = oW * r;
                var resized = new Bitmap(original, (int)nW, (int)nH);
                original.Dispose();
                return resized;
            }
        }
    }
    
Ryan Mann
sumber
1
saya pikir ada beberapa kesalahan ketik di mana Anda menggunakan rasio untuk menghitung ketinggian baru untuk gambar yang diubah ukurannya. Benar var nH = oH * r; Salah: var nH = oW * r;
wloescher
Diperbaiki, hanya tidak pernah berkomentar.
Ryan Mann