Изменение размера изображения, но сохранение соотношения сторон

Я написал код, который изменяет размер изображения в соответствующем поле. Я думаю, что некоторые части кода не нужны (например, если это полевое изображение). Есть ли более эффективный способ сделать это? Что-то не так с моим кодом (из результатов он выглядит нормально)? Существует ли более короткая версия?

Bitmap original, resizedImage;

try
{
    using (FileStream fs = new System.IO.FileStream(imageLabel.Text, System.IO.FileMode.Open))
    {
        original = new Bitmap(fs);
    }

    int rectHeight = BOXHEIGHT;
    int rectWidth = BOXWIDTH;

    //if the image is squared set it's height and width to the smallest of the desired dimensions (our box). In the current example rectHeight<rectWidth
    if (original.Height == original.Width)
    {
        resizedImage = new Bitmap(original, rectHeight, rectHeight);
    }
    else
    {
        //calculate aspect ratio
        float aspect = original.Width / (float)original.Height;
        int newWidth, newHeight;

        //calculate new dimensions based on aspect ratio
        newWidth = (int)(rectWidth * aspect);
        newHeight = (int)(newWidth / aspect);

        //if one of the two dimensions exceed the box dimensions
        if (newWidth > rectWidth || newHeight > rectHeight)
        {
            //depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
            if (newWidth > newHeight)
            {
                newWidth = rectWidth;
                newHeight = (int)(newWidth / aspect);
            }
            else
            {
                newHeight = rectHeight;
                newWidth = (int)(newHeight * aspect);
            }
        }
        resizedImage = new Bitmap(original, newWidth, newHeight);
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}
12 голосов | спросил John Demetriou 26 32014vEurope/Moscow11bEurope/MoscowWed, 26 Nov 2014 15:26:18 +0300 2014, 15:26:18

4 ответа


9

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

В принципе, вас интересуют два измерения, высота и ширина конечного изображения. Для масштабирования возможны два возможных результата: один, где масштабирование задает высоту цели, а другое - в том месте, где оно создает целевую ширину. Используемое масштабирование - это тот, который производит наименьшее изображение. Размер конечного изображения определяется коэффициентом масштабирования, и есть два фактора:

float scaleHeight = (float)BOXHEIGHT / (float)original.Height;
float scaleWidth = (float)BOXWIDTH / (float)original.Width;

Теперь у нас есть два коэффициента масштабирования, который дает меньшее изображение? Тот, который имеет наименьший масштабный коэффициент.

float scale = Math.Min(scaleHeight, scaleWidth);

Теперь вы можете просто выполнить настройку:

resizedImage = new Bitmap(original,
         (int)(original.Width * scale), (int)(original.Height * scale));
ответил rolfl 26 32014vEurope/Moscow11bEurope/MoscowWed, 26 Nov 2014 15:55:07 +0300 2014, 15:55:07
4

Вот как вы можете немного реорганизовать свой код:

namespace ConsoleApplication1
{
    using System;
    using System.Drawing;
    using System.IO;

    public class Program
    {
        public static void Main(string[] args)
        {
        }

        private const int BOXWIDTH = 1;

        public static Bitmap Foo()
        {    
            try
            {
                Bitmap original = LoadOriginalImage(imageLabel.Text);

                if (ImageIsBox(original))
                    return new Bitmap(original, BOXWIDTH, BOXWIDTH);

                var newDimensions = CalculateNewDimensionsForImage(original);

                return new Bitmap(original, newDimensions.Width, newDimensions.Height);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private static Bitmap LoadOriginalImage(string imagePath)
        {
            using (FileStream fs = new FileStream(imagePath, FileMode.Open))
            {
                return new Bitmap(fs);
            }
        }

        private static bool ImageIsBox(Bitmap original)
        {
            return original.Height == original.Width;
        }

        private static ImageDimensions CalculateNewDimensionsForImage(Bitmap original)
        {
            //calculate aspect ratio
            float aspect = original.Width / (float)original.Height;
            int newWidth, newHeight;

            //calculate new dimensions based on aspect ratio
            newWidth = (int)(BOXWIDTH * aspect);
            newHeight = (int)(newWidth / aspect);

            //if one of the two dimensions exceed the box dimensions
            if (newWidth > BOXWIDTH || newHeight > BOXWIDTH)
            {
                //depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
                if (newWidth > newHeight)
                {
                    newWidth = BOXWIDTH;
                    newHeight = (int)(newWidth / aspect);
                }
                else
                {
                    newHeight = BOXWIDTH;
                    newWidth = (int)(newHeight * aspect);
                }
            }

            return new ImageDimensions()
            {
                Height = newHeight,
                Width = newWidth
            };
        }
    }

    public class ImageDimensions
    {
        public int Height { get; set; }
        public int Width { get; set; }
    }
}

Я написал консольное приложение, которое пытается проиллюстрировать, как вы могли бы немного упростить свой код. Конечным результатом является то, что многие переменные, которые использовались, теперь исчезли, например. resizedImage, rectHeight, rectWidth

Это может быть полезно для вас, если нет, не беспокойтесь, мне понравилось писать:)

ответил Jason Evans 26 32014vEurope/Moscow11bEurope/MoscowWed, 26 Nov 2014 15:52:37 +0300 2014, 15:52:37
3

Стиль

  • Объявление нескольких переменных на одной и той же строке следует избегать для удобства чтения

  • Использование фигурных скобок {} для одиночного if также хорошо

  • Использование значимых имен для переменных хорошо

Общие

Этот код тесно связан с Windows Forms или WPF (imageLabel), который не нужен. Также он связан с константой BOXWIDTH. Метод должен быть статическим, поскольку он не изменяет никаких переменных-членов.

Ваша подпись метода должна выглядеть как

private static Bitmap GetResizedImage(String fileName, Int32 maxWidth, Int32 maxHeight)
{

}   

и называться как

Bitmap resized = GetResizedImage(imageLabel.Text, BOXWIDTH, BOXHEIGHT);
ответил Heslacher 26 32014vEurope/Moscow11bEurope/MoscowWed, 26 Nov 2014 15:52:38 +0300 2014, 15:52:38
3

Ваш код выглядит довольно аккуратно для меня. У меня есть несколько замечаний, перечисленных ниже.

Переменные имена:

Не смешивайте имена, это путает вещи:

int rectHeight = BOXWIDTH;
int rectWidth = BOXWIDTH;

Измените его на:

int boxHeight = BOXWIDTH;
int boxWidth = BOXWIDTH;

Теперь вы знаете, что говорите о коробке и не ошибаетесь в этом для какого-либо возможного прямоугольника.

Не заглавные имена полей, используйте pascalCase. Кроме того, aspect не очень хорошее имя, выберите имя, например ratio или aspectRatio.

var ключевое слово:

Используйте var вместо того, чтобы явно объявлять ваши varibales, пусть компилятор решит тип. Ваш код также будет выглядеть более чистым:

var aspect = original.Width / (float)original.Height;
ответил Abbas 26 32014vEurope/Moscow11bEurope/MoscowWed, 26 Nov 2014 15:47:27 +0300 2014, 15:47:27

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132