Толик Панков
hex_laden
............ .................. ................

November 2020
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

Толик Панков [userpic]
C#, WindowsForms, наложение изображений, изменение размеров изображения.

Задали вопрос, а можно ли в C# программными средствами наложить 2 изображения друг на друга. И даже сами потом предложили какое-то жуткое решение с привлечением WinAPI, и чуть ли не ассемблера со злыми духами.

На самом деле, задача вполне себе решается стандартными средствами.

Наложение изображений


Итак, предположим, что у нас есть 2 изображения, оба они PNG с прозрачностью, и лежат в ресурсах нашего приложения. Например, флаг:



и герб:



под именами, соответственно Properties.Resources.flag и Properties.Resources.trizub_small

Сначала сделаем из изображений два объекта Bitmap:

//Берем целевое изображение
Bitmap TargetBitmap = Properties.Resources.flag;

//Берем накладываемое изображение
Bitmap OverlayBitmap = Properties.Resources.trizub_small;


Теперь надо создать результирующее изображение (оно будет пока пустым) нужного размера:

//Создаем результирующее изображение (пока пустое)
Bitmap ResultBitmap = new Bitmap(TargetBitmap.Width, TargetBitmap.Height,
            PixelFormat.Format32bppArgb);


Откуда взяли высоту и ширину - понятно, третий параметр PixelFormat берется в зависимости от исходных изображений. Желательно, чтоб они совпадали по глубине цвета, иначе получится некрасиво, может потеряться прозрачность или произойти еще какая-нибудь бяка. Я сделал 2 изображения с прозрачностью (ARGB) и глубиной цвета 32 бита.

Теперь нужно создать объект Graphics, который и будет заниматься совмещением изображений. Раз мы будем рисовать в пустом Bitmap ResultBitmap, то и объект Graphics создаем из него, воспользовавшись методом Graphics.FromImage():

//Создаем объект Graphics из результирующего изображения
Graphics graph = Graphics.FromImage(ResultBitmap);


Далее объект graph надо настроить:

//настраиваем метод совмещения изображений
graph.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;


Если вместо SourceOver установить SourceCopy, то потеряется вся прозрачность у накладываемого изображения, и будет некрасиво:



Далее, производим отрисовку:

//рисуем основное изображение
graph.DrawImage(TargetBitmap, 0, 0);

//рисуем накладываемое изображение
graph.DrawImage(OverlayBitmap, (TargetBitmap.Width-OverlayBitmap.Width)/2,
(TargetBitmap.Height-OverlayBitmap.Height)/2,
OverlayBitmap.Width,OverlayBitmap.Height);

Думаю, откуда взяты все координаты и размеры, понятно.

Осталось только присвоить Bitmap'ы PictureBox'ам

Изменение размеров изображения


Тут тоже ничего сложного и сверхъестественного нет.

Чтоб два раза не вставать, возьмем полученное выше изображение и уменьшим его:

//задаем новые размеры
int NewWidth = ResultBitmap.Width / 2;
int NewHeight = ResultBitmap.Height / 2;
//Настраиваем PictureBox для вывода уменьшенного изображения
pbResize.Size = new Size(NewWidth, NewHeight);


Создадим новый Bitmap для будущего уменьшенного изображения:

//создаем новый Bitmap для измененного изображения
Bitmap ResizeBitmap = new Bitmap(NewWidth,
NewHeight);


Опять создадим объект Graphics, который будет заниматься отрисовкой:

//создаем объект Graphics, который будет изменять размер
Graphics ResizeGraph = Graphics.FromImage(ResizeBitmap);


Поставим повыше качество изображения:

//ставим высокое качество
ResizeGraph.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.High;


И делаем отрисовку:

//рисуем изображение с измененным размером
ResizeGraph.DrawImage(ResultBitmap, 0, 0, NewWidth, NewHeight);


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

Вот, что получилось:


Исходник примера на GitHub

Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2018/06/30/c-windowsforms-nalozhenie-izobrazhenij-izmenenie-razmerov-izobrazheniya/

Tags: ,
Comments

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

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

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

Ого, под виндой совсем все грустно.

А код возврата процесса в винде не возвращается?

Почему, возвращается. Но "код возврата" и "конечный результат" могут с друг-другом не всегда коррелировать. И вообще, когда пишешь на C# лучше все что можно делать средствами C#, надо было бы написать батник - ну тут уж понятно, другое дело. А так еще экзешники за собой таскай...

Это если что-то простое. А если сложное -- зачем изобретать велосипед?