CodeLab - первые шаги (Линии/Сетка)

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

CodeLab - первые шаги (Линии/Сетка)

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

Каждый пользователь, который начинает осваивать CodeLab, задается вопросом - с чего начать?
Прежде всего, начинать следует с изучения CodeLab Help от BoltBait'а.
Если вы изучили CodeLab Help и у вас пока нет никаких идей по созданию эффектов, начните с обновления старых плагинов, разработанных другими авторами.

Просматривая getpaint.net форум Plugins - Publishing ONLY!, я нашел неплохой пример для небольшого учебного пособия в разделе Simple Lines Plugin.

На рисунке представлен интерфейс эффекта Lines, автором которого является spongey437.

Изображение

Он рисует линии шириной в 1 пиксель и имеет два элемента управления: Width - интервал между линиями и X - Y - направление линий (по горизонтали и вертикали соответственно).

Итак, начнем.

Откройте раздел Simple Lines Plugin, выделите и скопируйте (Ctl+C) текст сценария.
Откройте CodeLab: Эффекты -> Advanced -> CodeLab.
Выделите в CodeLab текст сценария (Ctl+A) и вставьте скопированный сценарий (Ctl+V).
Сохраните сценарий с именем Lines для последующей работы с ним: Файл -> Сохранить

Прежде всего, откройте Конструктор интерфейса (Файл -> Конструктор интерфейса). Выделите в нем строку Width (1..10..100), в поле Имя элемента замените Width на Ширина и нажмите OK. Ваш новый сценарий приобретет следующий вид:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина
int Amount2 = 2; // [1,2] X - Y
#endregion
// int Amount1=10; //[1,100]Width
// int Amount2=2; //[1,2]X - Y

void Render(Surface dst, Surface src, Rectangle rect)
{
PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);

// 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++)
{
if (selectionRegion.IsVisible(x, y))
{
CurrentPixel = src[x,y];
// TODO: Add pixel processing code here
if(Amount2 == 1)
{
if (x % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel.R = (byte)PrimaryColor.R;
CurrentPixel.G = (byte)PrimaryColor.G;
CurrentPixel.B = (byte)PrimaryColor.B;
CurrentPixel.A = (byte)PrimaryColor.A;
}
}

if(Amount2 == 2)
{
if (y % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel.R = (byte)PrimaryColor.R;
CurrentPixel.G = (byte)PrimaryColor.G;
CurrentPixel.B = (byte)PrimaryColor.B;
CurrentPixel.A = (byte)PrimaryColor.A;
}
}

dst[x,y] = CurrentPixel;
}
}
}
}
Удалите эти две закомментированные строки:

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

// int Amount1=10; //[1,100]Width
// int Amount2=2; //[1,2]X - Y
они уже не нужны.

Следующие строки (кроме ColorBgra PrimaryColor) нам также не понадобятся:

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

// 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 SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;
int BrushWidth = (int)EnvironmentParameters.BrushWidth;
поэтому удалите их, оставив строку

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

ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
и вновь сохраните ваш сценарий с именем Lines_1.

Если вы внимательно изучили CodeLab Help, то вы, вероятно, заметили что в вашем новом сценарии нет необходимости разделять CurrentPixel на составляющие части (R, G, B и A). Поэтому следующие строки

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

CurrentPixel.R = (byte)PrimaryColor.R;
CurrentPixel.G = (byte)PrimaryColor.G;
CurrentPixel.B = (byte)PrimaryColor.B;
CurrentPixel.A = (byte)PrimaryColor.A;
замените на

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

CurrentPixel = PrimaryColor;
Если этот эффект рисует горизонтальные или вертикальные линии по отдельности, то может ли он нарисовать оба вида линий одновременно? Да, может. Для этого необходимо выполнить условие:

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

if ((x % Amount1 == 0) || (y % Amount1 == 0))
Добавьте перед dst[x,y] = CurrentPixel; следующие строки:

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

if(Amount2 == 3)
{
if ((x % Amount1 == 0) || (y % Amount1 == 0))
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}
Теперь откройте Конструктор интерфейса и выделите в нем строку X - Y (1..2..2).

В поле Максимум установите значение в 3, а в поле Имя элемента впишите X -Y - Сетка. Нажмите кнопку Обновить, затем Ok. Ваш сценарий будет выглядеть вот так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина
int Amount2 = 2; // [1,3] X - Y - Сетка
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
    
ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

ColorBgra CurrentPixel;
for(int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
if (selectionRegion.IsVisible(x, y))
{
CurrentPixel = src[x,y];
// TODO: Add pixel processing code here
if(Amount2 == 1)
{
if (x % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

if(Amount2 == 2)
{
if (y % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

if(Amount2 == 3)
{
if ((x % Amount1 == 0) || (y % Amount1 == 0))
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

dst[x,y] = CurrentPixel;
}
}
}
}
Сохраните ваш сценарий, теперь уже с именем Lines_Grid. Откройте в меню Файл -> Cохранить как DLL... и сохраните ваше первое обновление эффекта.
Закройте CodeLab и Paint.NET. Запустите на рабочем столе файл Install_Lines_Grid, который поместит файл Lines_Grid.dll в папку Эффекты (или перетащите файл Lines_Grid.dll в папку Эффекты).
Запустите Paint.NET и вы увидите свой эффект в меню Эффекты, запустите его и проверьте как он работает. Вероятно, вас не очень устраивает переключать вид линий при помощи слайдера. Возможно, вы также заметили, что работает эффект несколько замедленно. Тогда приступим к следующему шагу обновления.

Запустите CodeLab и откройте ваш сценарий Lines_Grid. Прежде всего удалите следующие строки:

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

{
if (selectionRegion.IsVisible(x, y))
и одну из закрывающих фигурных скобок (}) внизу сценария.

Строка

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

PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
нам теперь тоже не понадобится, удалите и ее.

Откройте Конструктор интерфейса и выделите в нем строку X - Y - Сетка (1..2..3). В выпадающем спискеТип элемента выберите Radio Button List. В поле Имя элемента впишите Вид, а в поле Параметры впишите виды линий, разделив их символом вертикальной черты(|): Вертикальные линии|Горизонтальные линии|Сетка. Нажмите кнопку Обновить и затем Ok. Теперь ваш сценарий выглядит так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина
byte Amount2 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{

ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

ColorBgra CurrentPixel;
for(int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
CurrentPixel = src[x,y];
// TODO: Add pixel processing code here
if(Amount2 == 0)
{
if (x % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

if(Amount2 == 1)
{
if (y % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

if(Amount2 == 2)
{
if ((x % Amount1 == 0) || (y % Amount1 == 0))
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

dst[x,y] = CurrentPixel;
}
}
}
Обратите внимание на строку

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

byte Amount2 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
Здесь начальное значение Amount2 равно 0, что соответствует вертикальным линиям. Замените в этой строке 0 на 1 и вы получите горизонтальные линии.

С точки зрения программирования наш код не очень корректен, поэтому, заглянув в CodeLab UI Elements, заменим строки

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

if(Amount2 == 0)
{
if (x % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

if(Amount2 == 1)
{
if (y % Amount1 == 0)
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}

if(Amount2 == 2)
{
if ((x % Amount1 == 0) || (y % Amount1 == 0))
{
// Access RGBA values this way, for example:
CurrentPixel = PrimaryColor;
}
}
на следующие строки

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

         switch(Amount2)
         {
            case 0: // вертикальные линии
               if (x % Amount1 == 0) {CurrentPixel = PrimaryColor;}
               break;
            case 1: // горизонтальные линии
               if (y % Amount1 == 0) {CurrentPixel = PrimaryColor;}
               break;
            case 2: // сетка
               if ((x % Amount1 == 0) || (y % Amount1 == 0)) {CurrentPixel = PrimaryColor;}
               break;
         }
Теперь наш сценарий будет выглядеть так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина
byte Amount2 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{

ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

ColorBgra CurrentPixel;
for(int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
CurrentPixel = src[x,y];
// TODO: Add pixel processing code here
         switch(Amount2)
         {
            case 0: // Vertical Lines
               if (x % Amount1 == 0) {CurrentPixel = PrimaryColor;}
               break;
            case 1: // Horizontal Lines
               if (y % Amount1 == 0) {CurrentPixel = PrimaryColor;}
               break;
            case 2: // Grid
               if ((x % Amount1 == 0) || (y % Amount1 == 0)) {CurrentPixel = PrimaryColor;}
               break;
         }

dst[x,y] = CurrentPixel;
}
}
}
Сохраните ваш сценарий с именем Lines_Grid_1 и создайте DLL с тем же именем. Проверьте ваш эффект в работе.

Цвет линий нашего эффекта зависит от Основного цвета, выбранного в окне Палитра. Если вы захотите нарисовать линии или сетку другим цветом, вам придется предварительно установить этот цвет в окне Палитра, а затем запустить ваш эффект. А можно ли выбирать цвет линий непосредственно в эффекте, не обращаясь к окну Палитра? Конечно, можно. Для этого продолжим обновлять наш эффект.

Откройте в CodeLab ваш сценарий Lines_Grid_1. Откройте Конструктор интерфейса и в выпадающем списке Тип элемента выберите элемент управления Color Wheel. В поле Имя элемента впишите Цвет, нажмите кнопку Добавить и переместите этот элемент управления при помощи кнопки Изображение вверх на одну позицию. Нажмите кнопку Ok.

Блок кода интерфейса UI выглядит теперь так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Цвет
byte Amount3 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
#endregion
Заметьте: переключатель Вид теперь называется Amount3, поэтому исправьте в строке switch Amount2 на Amount3.
Теперь у вас есть возможность выбирать цвет непосредственно в интерфейсе эффекта и мы не зависим от Основного цвета в окне Палитра! Это значит что CurrentPixel = PrimaryColor; мы можем заменить на CurrentPixel = Amount2; и удалить строку ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;.

Сохраните ваш сценарий с именем Lines_Grid_2 и создайте DLL с тем же именем. Проверьте ваш эффект в работе. Возможно, теперь вы захотите изменить ширину линий и интервал между ними. Тогда продолжим.

Откройте в CodeLab ваш сценарий Lines_Grid_2. Откройте Конструктор интерфейса, выделите строку Ширина (1..10..100), переименуйте ее в Ширина линии и нажмите кнопку Обновить. Затем в выпадающем списке Тип элемента выберите элемент управления Integer Slider, назовите его Ширина интервала. В поле Минимум впишите значение 1, в поле По умолчанию - 10. Нажмите кнопку Добавить и переместите строку при помощи кнопки Изображение на одну позицию вверх. Нажмите кнопку Ok.

Теперь блок кода интерфейса UI будет выглядеть так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина линии
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Цвет
int Amount3 = 10; // [1,100] Ширина интервала
byte Amount4 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
#endregion
Переключатель Вид теперь называется Amount4, поэтому исправьте в строке switch Amount3 на Amount4.

Теперь введем переменную Lines как сумму Amount1 и Amount3, расположив ее перед строкой ColorBgra CurrentPixel;

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

int Lines = Amount1 + Amount3;
и изменим условия

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

if (x % Amount1 == 0)
if (y % Amount1 == 0)
на следующие условия

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

if (x % Lines < Amount1)
if (y % Lines < Amount1)
Наш сценарий имеет теперь следующий вид:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина линии
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Цвет
int Amount3 = 10; // [1,100] Ширина интервала
byte Amount4 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{

int Lines = Amount1 + Amount3;
ColorBgra CurrentPixel;
for(int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
CurrentPixel = src[x,y];
// TODO: Add pixel processing code here
         switch(Amount5)
         {
            case 0: // Vertical Lines
               if (x % Lines < Amount1) {CurrentPixel = Amount2;}
               break;
            case 1: // Horizontal Lines
               if (y % Lines < Amount1) {CurrentPixel = Amount2;}
               break;
            case 2: // Grid
               if ((x % Lines < Amount1) || (y % Lines < Amount1)) {CurrentPixel = Amount2;}
               break;
         }

dst[x,y] = CurrentPixel;
}
}
}
Сохраните сценарий с именем Lines_Grid_3 и создайте DLL с тем же именем. Проверьте эффект в работе.

Вернемся к нашему последнему сценарию. A что если мы добавим еще один элемент управления.
Откройте Конструктор интерфейса и в поле выпадающего списка Тип элемента выберите элемент управления Check Box. В поле Имя элемента впишите Инвертировать, в поле По умолчанию установите 0 и нажмите кнопку Добавить. Нажмите кнопку Ok.

Теперь блок кода интерфейса выглядит так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина линии
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Цвет
int Amount3 = 10; // [1,100] Ширина интервала
byte Amount4 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
bool Amount5 = false; // [0,1] Инвертировать
#endregion
Зададим условия для флажка. Если флажок не отмечен, то цвет линий принимает значение цвета, выбранного в элементе управления Цвет. Если флажок отмечен, то цвет интервалов примет значение цвета, выбранного в элементе управления Цвет.

Окончательно наш код выглядит так:

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

#region UICode
int Amount1 = 10; // [1,100] Ширина линии
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Цвет
int Amount3 = 10; // [1,100] Ширина интервала
byte Amount4 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
bool Amount5 = false; // [0,1] Инвертировать
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
    int Lines = Amount1 + Amount3;
    ColorBgra CurrentPixel;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            CurrentPixel = src[x,y];
            // TODO: Add pixel processing code here

    if(!Amount5)
    {
         switch(Amount4)
         {
            case 0: // Vertical Lines
               if (x % Lines < Amount1) {CurrentPixel = Amount2;}
               break;
            case 1: // Horizontal Lines
               if (y % Lines < Amount1) {CurrentPixel = Amount2;}
               break;
            case 2: // Grid
               if ((x % Lines < Amount1) || (y % Lines < Amount1)) {CurrentPixel = Amount2;}
               break;
         }
              
    }
	else
    {
         switch(Amount4)
         {
            case 0: // Vertical Lines
               if (x % Lines + 1 > Amount1) {CurrentPixel = Amount2;}
               break;
            case 1: // Horizontal Lines
               if (y % Lines + 1 > Amount1) {CurrentPixel = Amount2;}
               break;
            case 2: // Grid
               if ((x % Lines + 1 > Amount1) && (y % Lines + 1 > Amount1)) {CurrentPixel = Amount2;}
               break;
         }
}
            dst[x,y] = CurrentPixel;
        }
    }
}
Сохраните ваш сценарий с именем Lines_Grid_4 и создайте DLL с тем же именем.
На этом можно было бы закончить, но... Давайте обратимся к Using CodeLab to Build a DLL BoltBait'а. В секции Default мы найдем некоторую полезную информацию и оформим аналогичную для нашего сценария:

// Submenu: Render - поместим наш эффект в подменю Узоры меню Эффекты (кстати, для CodeLab Render и Узоры - записи равнозначные)
// Name: Линии/Сетка - название эффекта в меню
// Title: Линии/Сетка - заголовок интерфейса UI эффекта
// Author: ReMake - имя автора эффекта
// Desc: Рисование прямых линий или сетки - описание эффекта
// Keywords: paint.net|эффект|рисование|линии|сетка - ключевые слова, по которым ваш эффект может быть найден в интернете
// URL: http://www.getpaint.net/redirect/plugins.html - ваш адрес в сети (или на форуме)

Вставим эту информацию над блоком кода интерфейса UI:

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

// Submenu: Render
// Name: Линии/Сетка
// Title: Линии/Сетка
// Author: ReMake
// Desc: Рисование прямых линий или сетки
// Keywords: paint.net|эффект|рисование|линии|сетка
// URL: http://www.getpaint.net/redirect/plugins.html
#region UICode
int Amount1 = 10; // [1,100] Ширина линии
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Цвет
int Amount3 = 10; // [1,100] Ширина интервала
byte Amount4 = 0; // [1] Вид|Вертикальные линии|Горизонтальные линии|Сетка
bool Amount5 = false; // [0,1] Инвертировать
#endregion
Сохраните этот сценарий с именем LinesGrid.

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

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

Сравните интерфейс вашего эффекта с рисунком, приведенным выше.

Изображение

С точки зрения программирования наш код, может быть, не очень элегантен, но это всего лишь учебное руководство. Я также не ставил перед собой цель объяснить алгоритм работы сценария - разобраться в этом задача пользователя.

Примеры работы эффекта смотрите в теме Линии/Сетка.

Надеюсь первый шаг в CodeLab оказался не очень сложным.

Ответить

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

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

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