Открыть список
Как стать автором
Обновить

Добавляем watermark к изображению

.NET
Привет, Хабрахабр!
Вчера, прочитав статью SergeyVoyteshonok, посвященную отрисовке логотипа сайта или компании (проще говоря, «водяного знака») на загружаемых пользователями изображениях, я был удивлен некоторой тяжеловесностью предложенного автором решения.
Тогда я пообещал немного поэкспериментировать и предложить более рациональный вариант.


В моей версии метод отрисовки выглядит так:

public void DrawWatermark(Image original, Bitmap watermark,
WatermarkPosition position, Color transparentColor, float opacity)
{
if (original == null)
throw new ArgumentNullException("original");
if (watermark == null)
throw new ArgumentNullException("watermark");
if (opacity < 0 || opacity > 1)
throw new ArgumentOutOfRangeException("Watermark opacity value is out of range");

Rectangle dest = new Rectangle(
GetDestination(original.Size, watermark.Size, position), watermark.Size);

using (Graphics g = Graphics.FromImage(original))
{
ImageAttributes attr = new ImageAttributes();
ColorMatrix matrix = new ColorMatrix(new float[][] {
new float[] { opacity, 0f, 0f, 0f, 0f },
new float[] { 0f, opacity, 0f, 0f, 0f },
new float[] { 0f, 0f, opacity, 0f, 0f },
new float[] { 0f, 0f, 0f, opacity, 0f },
new float[] { 0f, 0f, 0f, 0f, opacity } });
attr.SetColorMatrix(matrix);
watermark.MakeTransparent(transparentColor);

g.DrawImage(watermark, dest, 0, 0, watermark.Width, watermark.Height,
GraphicsUnit.Pixel, attr, null, IntPtr.Zero);
g.Save();
}
}


* This source code was highlighted with Source Code Highlighter.

Дополнительно, мы используем также две вещи:
public enum WatermarkPosition
{
TopLeft = 0,
TopRight,
BottomLeft,
BottomRight,
Middle
}


* This source code was highlighted with Source Code Highlighter.

для указания точки привязки, и метод, возвращающий нам конкретную точку расположения водяного знака в зависимости от размеров изображений и точки привязки:
private static Point GetDestination(Size originalSize, Size watermarkSize, WatermarkPosition position)
{
Point destination = new Point(0, 0);
switch (position)
{
case WatermarkPosition.TopRight:
destination.X = originalSize.Width - watermarkSize.Width;
break;
case WatermarkPosition.BottomLeft:
destination.Y = originalSize.Height - watermarkSize.Height;
break;
case WatermarkPosition.BottomRight:
destination.X = originalSize.Width - watermarkSize.Width;
destination.Y = originalSize.Height - watermarkSize.Height;
break;
case WatermarkPosition.Middle:
destination.X = (originalSize.Width - watermarkSize.Width) / 2;
destination.Y = (originalSize.Height - watermarkSize.Height) / 2;
break;
}
return destination;
}

* This source code was highlighted with Source Code Highlighter.

На мой взгляд, все достаточно прозрачно. Собственно отрисовка логотипа заняла всего 15 строк, учитывая все навороты форматирования, а без них — и того меньше! Такого результата позволило достичь применение для решения задачи возможностей .NET-класса ColorMatrix.
Вообще, класс ColorMatrix обладает очень широкими возможностями манипуляции настройками изображения. С помощью него можно не только задавать прозрачность, но и изменять контрастность, насыщенность картинки, делать из нее негатив и многое другое.

В заключение нужно отметить две вещи. Первая — логотип, используемый в качестве водяного знака, лучше сохранять в PNG. GIF-формат для простых логотипов также допустим. В этом случае мы можем не задавать transparentColor (точнее, вообще убрать строчку watermark.MakeTransparent(transparentColor);) и расширить тип watermark до Image.

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

UPD: Если вы загружали исходное изображение из файла и хотите сохранить его под тем же именем, вам также нужно будет создать копию и сохранить ее вне блока using.

UPD2: По просьбе Sergeyev добавил демонстрацию результата (слева — исходная картинка, справа — она же с известным всем логотипом. Не фотошоп! :)


Ну вот, собственно, и все!

P.S.: Вот так, совершенно незаметно, появился мой первый топик на Хабре :)

Теги:.Netизображениелоготипводяной знакGDI
Хабы: .NET
Всего голосов 53: ↑46 и ↓7 +39
Просмотры5.8K

Похожие публикации

Специализация Data Science
12 мая 2021114 000 ₽SkillFactory
SMM-менеджер
13 мая 2021Цена по запросуGeekBrains
Профессия Project Manager
13 мая 2021112 000 ₽Нетология
UX/UI дизайнер
14 мая 202183 940 ₽Нетология
Python для веб-разработки
14 мая 202159 400 ₽SkillFactory

Лучшие публикации за сутки