Зміна розміру пропорційно з обмеженнями MaxHeight та MaxWidth


124

Використання System.Drawing.Image.

Якщо ширина або висота зображення перевищують максимальну, його потрібно змінити пропорційно. Після зміни розміру потрібно переконатися, що ні ширина, ні висота все ще не перевищують межу.

Ширина та висота будуть змінені до тих пір, поки вони не перевищуватимуть максимальний та мінімум автоматично (можливий найбільший розмір), а також підтримують відношення.


@Sarawut Positwinyu - Але яке співвідношення сторін ви хочете?
Бібху

Що ви хочете, якщо зображення не може бути змінено на максимум та хв висоти та ширини та збережене співвідношення сторін?
Конрад Фрікс

@Bibhu Чи існує багато типів співвідношення сторін? я не знаю про це. Я просто хочу, щоб співвідношення зображень було схожим на можливе оригінальне оголошення зі співвідношенням зображень.
Sarawut Positwinyu

@Sarawut Positwinyu - перегляньте посилання на вікі, щоб дізнатися більше про співвідношення сторін. en.wikipedia.org/wiki/Aspect_ratio_%28image%29
Бібху

1
@Sarawut Positwinyu Ви не зловживали співвідношенням сторін терміна. Або якщо ви зробили хорошу компанію
Конрад Фрікс

Відповіді:


300

Подобається це?

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

7
@ Алекс приємно використовувати Math.Min (я завжди про це забуваю)
Конрад Фрікс,

5
Я б запропонував вам використати оператор з використанням об’єкта Graphics принаймні, щоб зберегти деякі ресурси :)
Schalk

Я просто замислююсь про випадок, я не знаю, чи можливо це чи ні після множення на співвідношення ширина або висота може все-таки перевищувати максимальну ширину або максимальну висоту.
Sarawut Positwinyu

4
Також переконайтеся, що ви використовуєте System.Drawing.Image, якщо використовуєте asp.net.
Індустр

1
@Smith - не запускайте метод Save, якщо вам не потрібно зберегти зображення. Саме це робить мій метод ScaleImage - повертає зображення без збереження.
Алекс Аза

5

Робоче рішення:

Для розміру зображення розмір нижче 100 Кб

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

Більше посилання на http://net4attack.blogspot.com/


5

Набагато довше рішення, але враховуються такі сценарії:

  1. Чи зображення менше, ніж обмежувальне поле?
  2. Чи зображення та рамка обмежувального поля?
  3. Чи квадрат зображення, а обмежувальне поле - ні
  4. Чи ширше і вище зображення, ніж обмежувальне поле
  5. Чи більше зображення, ніж обмежувальне поле
  6. Чи зображення вище, ніж обмежувальна рамка

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

1
Я думаю, що є кілька помилок, де ви використовуєте відношення для обчислення нової висоти для розміру зображення. Правильний var nH = oH * r; Неправильно: var nH = oW * r;
wloescher

Виправлено, просто ніколи не коментується.
Ryan Mann
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.