Измените размер изображения пропорционально с помощью ограничений MaxHeight и MaxWidth

124

Использование System.Drawing.Image.

Если ширина или высота изображения превышают максимальную, его необходимо пропорционально изменить размер. После изменения размера необходимо убедиться, что ни ширина, ни высота не превышают лимит.

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

Саравут Позитвинью
источник
@Sarawut Positwinyu - Но какое соотношение сторон вы хотите?
Bibhu
Что вы хотите сделать, если изображение не может быть изменено на максимальные и минимальные значения высоты и ширины, а соотношение сторон сохраняется?
Конрад Фрикс
@Bibhu Есть много типов соотношений сторон? я не знаю об этом. Я просто хочу, чтобы соотношение сторон изображения было таким же, как у оригинального объявления с соотношением сторон изображения.
Sarawut Positwinyu
@Sarawut Positwinyu - посмотрите эту ссылку в вики, чтобы узнать больше о соотношении сторон. en.wikipedia.org/wiki/Aspect_ratio_%28image%29
Bibhu
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
@Alex хорошо использует Math.Min (я всегда забываю об этом)
Конрад Фрикс
5
Я бы посоветовал вам использовать оператор using для объекта Graphics, по крайней мере, для экономии ресурсов :)
Schalk
Я просто думаю о случае, я не уверен, возможно ли это или нет, что после умножения на коэффициент ширина или высота может все еще больше, чем максимальная ширина или максимальная высота.
Sarawut Positwinyu
4
Также убедитесь, что вы используете System.Drawing.Image, если используете asp.net.
Induster
1
@Smith - не запускайте метод Save, если вам не нужно сохранять изображение. Это именно то, что делает мой метод ScaleImage - возвращает изображение, не сохраняя его.
Alex Aza
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/

user806084
источник
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
Исправлено, просто не комментировалось.
Райан Манн