CodeLab - первые шаги (Неоновые контуры)

Эта ветка форума посвящена инструкции по работе с лабораторией скриптов CodeLab от BoltBait. С её помощью можно делать свои плагины для Paint.NET. Все вопросы по CodeLab размещаются здесь.
Ответить
ReMake
Сообщения: 244
Зарегистрирован: 10 сен 2014, 01:25
Репутация: 69
Пол: Мужской
Откуда: Брест, Беларусь

CodeLab - первые шаги (Неоновые контуры)

Сообщение ReMake » 22 мар 2015, 17:38

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

Прежде чем создавать наш новый эффект давайте поэксперементируем с изображением.
Загрузите какое-нибудь изображение.

Изображение

Примените к изображению эффект Эскиз (Эффекты -> Стилизация -> Эскиз). Установите толщину в 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;
        }
    }
}
Экспериментально установлено, что для переменной Толщина наиболее приемлемый диапазон от 1 до 25, а для переменной Интенсивность - от 15 до 65. Давайте изменим эти переменные. Откройте Конструктор интерфейса (Файл -> Конструктор интерфейса), выделите в нем строку Толщина и в поле Максимум впишите 25. Нажмите кнопку Обновить. Выделите строку Интенсивность. В поле Минимум впишите 1, в поле максимум - 50 и в поле По умолчанию 25. Переименуйте эту переменную в Интенсивность свечения. Нажмите кнопку Обновить и кнопку Ok.

Измените в строке outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2); переменную Amount2 на Amount2+14 (вспомните, что эффективное значение переменной Интенсивность начинается с 15, а минимальное значение мы установили в 1).

Код: Выделить всё

    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2+14);
Сохраните наш сценарий с именем NeonEdges_1 (Файл -> Сохранить...). Создайте DLL файл с тем же именем. Проверьте ваш эффект в работе с параметрами Толщина 8 и Интенсивность свечения 45. Сравните результат с предыдущим изображением. Они абсолютно идентичны.

Мы достигли желаемого результата. Но, возможно вы захотите изменить цвет получившихся контуров.

Вернитесь к первому изображению. Примените к нему эффект Оттенок и насыщенность (Коррекция -> Оттенок и насыщенность) с различными параметрами оттенка и насыщенности. Заметьте, что наиболее эффективно насыщенность изменяется в диапазоне от 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);
Не забудьте исправить строку CurrentPixel = saturationOp(CurrentPixel); на CurrentPixel = saturationOp.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
Изменим в строке saturationOp = new UnaryPixelOps.HueSaturationLightness(0, Amount1, 0); значения в скобках. Вместо первого значения, равного 0, впишите Amount3, а вместо Amount1 - (Amount4+100)*2.

Теперь наш сценарий выглядит так:

Код: Выделить всё

#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;
        }
    }
}
Сохраните его с именем NeonEdges_2 и создайте файл DLL с тем же именем. Проверьте ваш эффект в работе.

Возможно вы захотите исключить темные участки изображения, чтобы использовать его на другом фоне. Для этого необходимо в каждом пикселе установить максимальное значение одной из трех компонент 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;
        }
    }
}
Сохраните этот сценарий с именем NeonEdges.

Осталось оформить значок для интерфейса нашего эффекта в виде файла PNG размером 16 на 16 пикселей. Я создал вот такой значок: Изображение

Теперь давайте сохраним наш эффект как DLL файл: Файл -> Сохранить как DLL... В представленном вам диалоге сборки DLL есть почти вся необходимая информация. Щелкните по ссылке Выбор значка и выберите ваш значок. Нажмите кнопку Создать - ваш новый эффект готов!

Так выглядит интерфейс пользователя нашего нового эффекта.

Изображение

А так выглядит результат работы эффекта с подложенным под него темно-синим фоном.

Изображение

Я думаю, что создание этого эффекта не вызвало у вас затруднений.

Ответить

Вернуться в «CodeLab от BoltBait»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость