На предыдущих уроках мы научились писать простые и более сложные эффекты для Paint.NET.
Скачать готовый эффект из этого урока, а так же посмотреть что делает этот эффект вы можете здесь.
Если вы попали на этот урок случайно, но он вас заинтересовал и вы хотите сделать подобный эффект, но не знаете как, то рекомендуем сначала прочитать на этом форуме, как пользоваться Codelab от BoltBait. А потом пройти два базовых урока как делать эффекты для Paint.NET, а именно Урок №1 и Урок №2.
На этом уроке мы разберем, что такое цвета в Paint.NET и как ими можно управлять.
Что такое RGB?
RGB – это аббревиатура из английских слов Red, Green, Blue — красный, зелёный, синий.
RGB – это аддитивная цветовая модель, описывающая способ образования цвета. Слово «аддитивная» означает, что различные цвета получаются путём добавления их (англ. addition) к черному. Т.е. цвет в модели RGB описывается тремя значениями Red, Green, Blue — красный, зелёный, синий. Т.е. для того что бы определить цвет нужно знать три числа – три цветовых канала – R, G и B, каждый из которых может изменяться от 0 до 255. Поскольку все цвета получаются добавлением к черному цвету, то вполне логично, что черный цвет имеет значения трех этих параметров R=0, G=0 и B=0. Очевидно, что противоположный ему цвет – белый, имеет максимальные значения всех трех каналов R=255, G=255 и B=255. Остальные цвета имеют какие-то промежуточные значения.
Как несложно догадаться, что если мы отключим два канала, например G и B, а оставим только R, то получим цвет R=255, G=0 и B=0 – это ярко-красный цвет. Поэкспериментировать с цветами вы можете сами в палитре Paint.NET. В верхнем правом углу можно задать значения RGB прямо с клавиатуры. Не забудьте только переключить окно палитры в расширенный режим.
Итак, мы знаем, что такое RGB, и умеем делать простые эффекты – это все что нам нужно.
Придумаем некоторую дополнительную переменную, в которая будет означать какое-нибудь придуманное нами число. Поскольку это наша переменная, то как мы захотим так её и назовем, например, V. Представьте себе, например, что V=30. На это значение мы будем увеличивать или уменьшать значения наших цветов RGB.
Итак, если мы знаем, что (0,0,0) – это черный цвет, а (255,255,255) – белый, то чем ближе значения RGB к 0, тем цвет будет темнее. И, наоборот, чем ближе значения RGB к 255 (255 – это максимум), тем цвет светлее.
Логически получаются формулы:
Осветление
Код: Выделить всё
R= R + V; G=G + V; B=B + V;
Код: Выделить всё
R= R - V; G=G - V; B=B - V;
Если вместо добавления константы, мы будем умножать на это значение, то получим эффект изменения яркости. Только обратите внимание? Что максимальное значение RGB 255, а минимальное 0, поэтому придуманное нами число V = 30 подойдет для очень небольшого количества темных цветов, большинство же из них, скорее всего, станет белым.
Код: Выделить всё
R= R*V; G=G*V; B=B*V;
Как инвертировать цвета RGB? Для этого надо просто вычесть текущее значение из максимального, которое равно 255.
Код: Выделить всё
R=255-R; G=255-G; B=255-B;
Черно-белые цвета и серые тона – это те цвета, у которых R = G = B. Значит, нам надо уравнять значения всех трех каналов. Какое поставить значение? Самый очевидный ответ среднеарифметическое значение.
Код: Выделить всё
R=(R+G+B)/3; G=R; B=R;
Огрубление, это когда в изображении используется не огромное количество цветов, а меньшее их количество. В нашем случае мы можем ограничить количество цветов нашим параметром V=30. Используем для этого остаток от деления.
Код: Выделить всё
R= R%V; G=G%V; B=B%V;
Порог – это когда цвета меньше какого-то уровня становятся черными, а выше какого-то уровня – белыми. Используем для верхнего и нижнего порога наш любимый параметр V. В этом случае мы не обойдемся одной формулой, а придется написать условия.
Код: Выделить всё
if (R<V) {R=0;}
if (R>(255-V)) {R=255;}
if (G<V) {G=0;}
if (G>(255-V)) {G=255;}
if (B<V) {B=0;}
if (B>(255-V)) {B=255;}
Код: Выделить всё
#region UICode
byte Amount1 = 0; // Тип эффекта|Осветление|Затемнение|Изменение яркости|Инвертировать цвета|Оттенки серого|Огрубление|Установка порога
int Amount2 = 0; // [0,255] Шкала настройки
#endregion
void Render(Surface dst, Surface src, Rectangle rect)
{
// Delete any of these lines you don't need
Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
long CenterX = (long)(((selection.Right - selection.Left) / 2)+selection.Left);
long CenterY = (long)(((selection.Bottom - selection.Top) / 2)+selection.Top);
ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;
int BrushWidth = (int)EnvironmentParameters.BrushWidth;
ColorBgra CurrentPixel;
for (int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
CurrentPixel = src[x,y];
int R = CurrentPixel.R;
int G = CurrentPixel.G;
int B = CurrentPixel.B;
int V = Amount2;
if (Amount1 == 0)
{
R= R + V; G=G + V; B=И + V;
}
if (Amount1 == 1)
{
R= R - V; G=G - V; B=B - V;
}
if (Amount1 == 2)
{
R= R*V; G=G*V; B=B*V;
}
if (Amount1 == 3)
{
R=255-R; G=255-G; B=255-B;
}
if (Amount1 == 4)
{
R=(R+G+B)/3; G=R; B=R;
}
if (Amount1 == 5)
{
R= R%V; G=G%V; B=B%V;
}
if (Amount1 == 6)
{
if (R<V) {R=0;}
if (R>(255-V)) {R=255;}
if (G<V) {G=0;}
if (G>(255-V)) {G=255;}
if (B<V) {B=0;}
if (B>(255-V)) {B=255;}
}
// TODO: Add pixel processing code here
// Access RGBA values this way, for example:
CurrentPixel.R = Int32Util.ClampToByte(R);
CurrentPixel.G = Int32Util.ClampToByte(G);
CurrentPixel.B = Int32Util.ClampToByte(B);
dst[x,y] = CurrentPixel;
}
}
}