Вертикально объединить два изображения с разными размерами C#

178
26 октября 2018, 18:00

Есть два изображения: shapka.jpg и poster.jpg
Нужно их объединить так, чтобы шапка была сверху, а постер снизу, сразу под ней. При этом, надо учесть, что шапка первоначально имеет размер 500x71.
Постер по ширине никогда не бывает больше 500, но может быть меньше. Соответственно, если по ширине он меньше, то и ширину шапки надо пропорционально с высотой подогнать под ширину постера. Подскажите, как это правильно сделать?

В проекте есть библиотека ImageMagick, но я не разобрался, как с ее помощью можно такое сделать, поэтому нашел немного другой метод и слегка переделал его под себя:

public static Bitmap MergeTwoImages(Image firstImage, Image secondImage) // firstImage - shapka.jpg, secondImage - poster.jpg
{
    if (firstImage == null)
    {
        throw new ArgumentNullException("firstImage");
    }
    if (secondImage == null)
    {
        throw new ArgumentNullException("secondImage");
    }
    int outputImageWidth = 0;
    if (firstImage.Width > secondImage.Width)
    {
        outputImageWidth = secondImage.Width;
    }
    else
    {
        outputImageWidth = firstImage.Width;
    }
    int outputImageHeight = firstImage.Height + secondImage.Height + 1;
    Bitmap outputImage = new Bitmap(outputImageWidth, outputImageHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    using (Graphics graphics = Graphics.FromImage(outputImage))
    {
        graphics.DrawImage(firstImage, new Rectangle(new Point(), firstImage.Size),
                new Rectangle(new Point(), firstImage.Size), GraphicsUnit.Pixel);
        graphics.DrawImage(secondImage, new Rectangle(new Point(0, firstImage.Height + 1), secondImage.Size),
                new Rectangle(new Point(), secondImage.Size), GraphicsUnit.Pixel);               
    }
    return outputImage;
}

Но здесь картинка не изменяет свой размер, а просто обрезается, что не совсем есть хорошо.

Answer 1

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

В Вашем коде нигде и не указано масштабирование изображений, а метод Graphics.DrawImage, который Вы применяли,

рисует заданную часть указанного объекта Image в заданном месте, используя заданный размер.

Так что ничего удивительного в том, что изображения обрезались, нет)

Для того, чтобы изображение было отмасштабировано, а не обрезано, Вам следует использовать конструктор Bitmap(Image, Size), который

инициализирует новый экземпляр Bitmap из указанного существующего изображения, масштабированного до заданного размера.

Итак, привожу решение с комментариями:

public static Bitmap MergeTwoImages(Image firstImage, Image secondImage)
{
    // Проверяем, меньше ли ширина первого изображения, чем второго 
    // (Попутно проверяем на null)
    if ((firstImage ?? throw new ArgumentNullException("firstImage")).Width < (secondImage ?? throw new ArgumentNullException("secondImage")).Width)
        // Масштабируем второе изображение
        secondImage = ResizeImgByWidth(secondImage, firstImage.Width);
    else
        // Эта проверка на случай равенства ширины изображений
        if (firstImage.Width > secondImage.Width)
            // Масштабируем первое изображение
            firstImage = ResizeImgByWidth(firstImage, secondImage.Width);
    // Создаем Bitmap с шириной картинок (на данном шаге они уже точно равны) и их суммарной высотой
    Bitmap result = new Bitmap(firstImage.Width, firstImage.Height + secondImage.Height);
    // Создаем Graphics из заданного изображения
    using (Graphics g = Graphics.FromImage(result))
    {
        // Отрисовываем первую картинку в верхнем левом углу
        g.DrawImage(firstImage, new Point(0, 0));
        // Отрисовываем вторую картинку под первой
        g.DrawImage(secondImage, new Point(0, firstImage.Height));
    }
    return result;
}
// Пропорционально изменяем размер изображения по указанной ширине
private static Bitmap ResizeImgByWidth(Image Img, int NewWidth) => new Bitmap(Img, new Size(NewWidth, (int)(Img.Height * (NewWidth / (double)Img.Width))));

Проверим:

MergeTwoImages(Image.FromFile("test0.png"), Image.FromFile("test1.png")).Save("done.png");

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

Собственно, я не удержался от того, чтобы сделать решение адаптивным для любого числа изображений на входе)

Получилось так:

public static Bitmap MergeImages(params Image[] Images)
{
    // Проверка на пустоту упакованного массива
    if (Images == null || Images.Length == 0)
        throw new ArgumentException("`Images` can't be empty!", "Images");
    // Получаем минимальную ширину, на которую позже будем ориентироваться
    // (Попутно проверяем изображения на null)
    int minWidth = Images.OrderBy(x => (x ?? throw new NullReferenceException()).Width).First().Width;
    // Получаем коллекцию отмасштабированных изображений
    IEnumerable<Image> resized = Images.Select(x => x.Width > minWidth ? ResizeImgByWidth(x, minWidth) : x);
    // Создаем Bitmap с минимальной шириной и суммарной высотой результирующих картинок
    Bitmap result = new Bitmap(minWidth, resized.Sum(x => x.Height));
    // Создаем Graphics из заданного изображения
    using (Graphics g = Graphics.FromImage(result))
    {
        int currentHeight = 0;
        foreach (Image img in resized)
        {
            // Отрисовываем текущую картинку, увеличивая шаг на ее высоту
            g.DrawImage(img, new Point(0, currentHeight));
            currentHeight += img.Height;
        }
    }
    return result;
}
// Пропорционально изменяем размер изображения по указанной ширине
private static Bitmap ResizeImgByWidth(Image Img, int NewWidth) => new Bitmap(Img, new Size(NewWidth, (int)(Img.Height * (NewWidth / (double)Img.Width))));

Проверим:

MergeImages(Image.FromFile("test0.png"), Image.FromFile("test1.png"), Image.FromFile("test2.png")).Save("done.png");

Результат:

Надеюсь, мой ответ смог Вам помочь!
Удачи в Ваших делах)

READ ALSO
Как получить цвет ячейки? google таблицы api php

Как получить цвет ячейки? google таблицы api php

Собственно вопрос в заголовке! Нашел кучу информации как в таблице установить цвет на ячейку, отформатировать ее, и тому подобное, но как...

152
Как удалить запись массива из сессии - PHP

Как удалить запись массива из сессии - PHP

есть вот такой массив в котором лежит 3 товара и передается через $_SESSION['shopping_cart'][]:

145