Прежде чем создавать наш новый эффект давайте поэксперементируем с изображением.
Загрузите какое-нибудь изображение.
Примените к изображению эффект Эскиз (Эффекты -> Стилизация -> Эскиз). Установите толщину в 8, интенсивность в 60. Теперь наше изображение выглядит так:
Примените к изображению эффект Инвертировать цвета (Коррекция -> Инвертировать цвета). Взгляните на изображение.
Мы получили эффект, имитирующий неоновое свечение. Пока не закрывайте получившееся изображение.
Теперь давайте будем создавать наш эффект. Откройте ваше исходное изображение в новом окне.
Запустите CodeLab (Эффекты -> Advanced -> CodeLab). Выберите в меню Файл -> Новый. Нажмите Нет на запрос о сохранении текущего сценария. Вам будет представлено диалоговое окно Новый код (шаблон). Выберите в выпадающем списке Эскиз и Инвертировать цвета в одном из двух выпадающих списков Операция с пикселями. Нажмите кнопку Генерировать код.
Мы получим следующий сценарий эффекта:
Код: Выделить всё
#region UICode
int Amount1 = 3; // [1,200] Толщина
int Amount2 = 50; // [1,100] Интенсивность
// Настройки использования операций с пикселями
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();
// Это основной цикл функции обработки
void Render(Surface dst, Surface src, Rectangle rect)
{
// Настройки вызова эффекта Эскиз
OutlineEffect outlineEffect = new OutlineEffect();
PropertyCollection outlineProps = outlineEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken outlineParameters = new PropertyBasedEffectConfigToken(outlineProps);
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Thickness, Amount1);
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2);
outlineEffect.SetRenderInfo(outlineParameters, new RenderArgs(dst), new RenderArgs(src));
// Вызов функции Эскиз
outlineEffect.Render(new Rectangle[1] { rect }, 0, 1);
// Теперь в основном цикле обработки холст назначения (dst) имеет эскизную версию холста источника (src)
for (int y = rect.Top; y < rect.Bottom; y++)
{
if (IsCancelRequested) return;
for (int x = rect.Left; x < rect.Right; x++)
{
ColorBgra CurrentPixel = dst[x,y];
CurrentPixel = invertOp.Apply(CurrentPixel);
// ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
dst[x,y] = CurrentPixel;
}
}
}
Измените в строке outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2); переменную Amount2 на Amount2+14 (вспомните, что эффективное значение переменной Интенсивность начинается с 15, а минимальное значение мы установили в 1).
Код: Выделить всё
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2+14);
Мы достигли желаемого результата. Но, возможно вы захотите изменить цвет получившихся контуров.
Вернитесь к первому изображению. Примените к нему эффект Оттенок и насыщенность (Коррекция -> Оттенок и насыщенность) с различными параметрами оттенка и насыщенности. Заметьте, что наиболее эффективно насыщенность изменяется в диапазоне от 100 до 200. Запомним это.
А можно ли добавить эти два параметра в наш эффект? Конечно, можно.
И вновь обратимся к замечательному учебнику CodeLab Help (part 3) от BoltBait'а. В секции Unary Pixel Operations мы найдем операции по обработке оттенка и насыщенности.
Скопируйте оттуда строку:
Код: Выделить всё
private UnaryPixelOps.HueSaturationLightness saturationOp;
Код: Выделить всё
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();
Код: Выделить всё
// create a saturation operation based on a UI slider
saturationOp = new UnaryPixelOps.HueSaturationLightness(0, Amount1, 0); // fix
CurrentPixel = saturationOp(CurrentPixel);
Код: Выделить всё
CurrentPixel = invertOp.Apply(CurrentPixel);
Откройте Конструктор интерфейса. В выпадающем списке Тип элемента управления выберите Integer Slider. В поле Имя элемента впишите Оттенок. В поле Минимум впишите -180, в поле Максимум впишите 180 и в поле По умолчанию - 0. Нажмите кнопку Добавить. Вновь выберите Integer Slider в выпадающем списке Тип элемента управления. В поле Имя элемента впишите Насыщенность. В поле По умолчанию впишите 25. Нажмите кнопку Добавить и кнопку Ok.
Теперь блок кода интерфейса выглядит так:
Код: Выделить всё
#region UICode
int Amount1 = 8; // [1,25] Толщина
int Amount2 = 45; // [1,50] Интенсивность свечения
int Amount3 = 0; // [-180,180] Оттенок
int Amount4 = 0; // [0,100] Насыщенность
#endregion
Теперь наш сценарий выглядит так:
Код: Выделить всё
#region UICode
int Amount1 = 8; // [1,25] Толщина
int Amount2 = 45; // [1,50] Интенсивность свечения
int Amount3 = 0; // [-180,180] Оттенок
int Amount4 = 0; // [0,100] Насыщенность
#endregion
// Настройки использования операций с пикселями
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();
private UnaryPixelOps.HueSaturationLightness saturationOp;
// Это основной цикл функции обработки
void Render(Surface dst, Surface src, Rectangle rect)
{
// Настройки вызова эффекта Эскиз
OutlineEffect outlineEffect = new OutlineEffect();
PropertyCollection outlineProps = outlineEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken outlineParameters = new PropertyBasedEffectConfigToken(outlineProps);
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Thickness, Amount1);
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2 + 14);
outlineEffect.SetRenderInfo(outlineParameters, new RenderArgs(dst), new RenderArgs(src));
// Вызов функции Эскиз
outlineEffect.Render(new Rectangle[1] { rect }, 0, 1);
// Теперь в основном цикле обработки холст назначения (dst) имеет эскизную версию холста источника (src)
for (int y = rect.Top; y < rect.Bottom; y++)
{
if (IsCancelRequested) return;
for (int x = rect.Left; x < rect.Right; x++)
{
ColorBgra CurrentPixel = dst[x,y];
CurrentPixel = invertOp.Apply(CurrentPixel);
// create a hue & saturation operation based on a UI slider
saturationOp = new UnaryPixelOps.HueSaturationLightness(Amount3, (Amount4 + 100)*2, 0); // fix
CurrentPixel = saturationOp.Apply(CurrentPixel);
// ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
dst[x,y] = CurrentPixel;
}
}
}
Возможно вы захотите исключить темные участки изображения, чтобы использовать его на другом фоне. Для этого необходимо в каждом пикселе установить максимальное значение одной из трех компонент R, G или B.
Нам потребуются целочисленные переменные R, G, B и A, а также еще один элемент управления.
Откройте Конструктор интерфейса и в выпадающем списке Тип элемента управления выберите Check Box. В поле Имя элемента впишите Устранить темные участки. Нажмите кнопку Добавить и кнопку Ok.
Блок кода интерфейса будет выглядеть так:
Код: Выделить всё
#region UICode
int Amount1 = 8; // [1,25] Толщина
int Amount2 = 45; // [1,50] Интенсивность свечения
int Amount3 = 0; // [-180,180] Оттенок
int Amount4 = 0; // [0,100] Насыщенность
bool Amount5 = false; // [0,1] Устранить темные участки
#endregion
Код: Выделить всё
// ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
int R = CurrentPixel.R;
int G = CurrentPixel.G;
int B = CurrentPixel.B;
int A = CurrentPixel.A;
if (Amount5)
{A = Math.Max(Math.Max(R,G),B);}
CurrentPixel.A = Int32Util.ClampToByte(A);
// Author: ReMake
// Submenu: Stylize
// Name: Неоновые контуры
// Title: Неоновые контуры
// Desc: Paint.Net эффект, имитирующий неоновые контуры изображения
// Keywords: paint.net|effect|неоновый|контур|неоновый контур
// URL: http://www.getpaint.net/redirect/plugins.html
и наш окончательный сценарий будет выглядеть так:
Код: Выделить всё
// Author: ReMake
// Submenu: Stylize
// Name: Неоновые контуры
// Title: Неоновые контуры
// Desc: Paint.Net эффект, имитирующий неоновые контуры изображения
// Keywords: paint.net|эффект|неоновый|контур|неоновый контур
// URL: http://www.getpaint.net/redirect/plugins.html
#region UICode
int Amount1 = 8; // [1,25] Толщина
int Amount2 = 45; // [1,50] Интенсивность свечения
int Amount3 = 0; // [-180,180] Оттенок
int Amount4 = 25; // [0,100] Насыщенность
bool Amount5 = false; // [0,1] Устранить темные участки
#endregion
// Настройки использования операций с пикселями
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();
private UnaryPixelOps.HueSaturationLightness saturationOp;
// Это основной цикл функции обработки
void Render(Surface dst, Surface src, Rectangle rect)
{
// Настройки вызова эффекта Эскиз
OutlineEffect outlineEffect = new OutlineEffect();
PropertyCollection outlineProps = outlineEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken outlineParameters = new PropertyBasedEffectConfigToken(outlineProps);
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Thickness, Amount1);
outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2 + 14);
outlineEffect.SetRenderInfo(outlineParameters, new RenderArgs(dst), new RenderArgs(src));
// Вызов функции Эскиз
outlineEffect.Render(new Rectangle[1] { rect }, 0, 1);
// Теперь в основном цикле обработки холст назначения (dst) имеет эскизную версию холста источника (src)
for (int y = rect.Top; y < rect.Bottom; y++)
{
if (IsCancelRequested) return;
for (int x = rect.Left; x < rect.Right; x++)
{
ColorBgra CurrentPixel = dst[x,y];
CurrentPixel = invertOp.Apply(CurrentPixel);
// Создание оттенка и насыщенности на основе слайдеров интерфейса UI
saturationOp = new UnaryPixelOps.HueSaturationLightness(Amount3, (Amount4 + 100)*2, 0); // fix
CurrentPixel = saturationOp.Apply(CurrentPixel);
// ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
int R = CurrentPixel.R;
int G = CurrentPixel.G;
int B = CurrentPixel.B;
int A = CurrentPixel.A;
if (Amount5)
// Определяем наибольшее значение для альфа-канала
{A = Math.Max(Math.Max(R,G),B);}
CurrentPixel.A = Int32Util.ClampToByte(A);
dst[x,y] = CurrentPixel;
}
}
}
Осталось оформить значок для интерфейса нашего эффекта в виде файла PNG размером 16 на 16 пикселей. Я создал вот такой значок:
Теперь давайте сохраним наш эффект как DLL файл: Файл -> Сохранить как DLL... В представленном вам диалоге сборки DLL есть почти вся необходимая информация. Щелкните по ссылке Выбор значка и выберите ваш значок. Нажмите кнопку Создать - ваш новый эффект готов!
Так выглядит интерфейс пользователя нашего нового эффекта.
А так выглядит результат работы эффекта с подложенным под него темно-синим фоном.
Я думаю, что создание этого эффекта не вызвало у вас затруднений.