На главную
Назад | Содержание | Вперед

Пишем плагин

Создаем библиотеку Flip.dpr. Напишем сначала основную процедуру плагина:

procedure ENTRYPOINT(selector  : smallint;
                     var param : FilterRecord;
                     var data  : integer;
                     var result: smallint); cdecl;
begin
   resultCode := noErr;
   case selector of
      filterSelectorAbout:       DoAbout;
      filterSelectorParameters:  DoParameters(param);
      filterSelectorPrepare:     DoPrepare(param);
      filterSelectorStart:       DoStart(param);
      filterSelectorContinue:    DoContinue(param);
      filterSelectorFinish:      DoFinish(param);
      else
         resultCode := filterBadParameters;
   end;
   { Нужно не забывать инициализировать переменную result при каждом
     вызове плагина }
   result := resultCode;
end;

В переменной selector нам передается код запрашиваемого действия. Каждое действие будет обрабатывать отдельная процедура. В записи param передаются параметры изображения и всякая другая информация. Переменную data мы никак не будем использовать. Для хранения значения параметра result будем использовать глобальную переменную resultCode. Это удобней и быстрей, чем все время передавать ссылку в параметрах процедур. Только нужно не забывать всегда инициализировать переменную (первая строчка процедуры) и возвращать значение редактору (последняя строчка).

Теперь реализуем процедуры, обрабатывающие разные действия (по значению selector).

DoAbout. Действие на запрос вывода диалога About плагина. Забудем пока про рекомендации по оформлению этого диалога и обойдемся просто процедурой MessageBox.

procedure DoAbout;
begin
   MessageBox(0, 'Мой первый фильтр.', 'Flip', MB_OK);
end;

DoParameters. Выводим пользователю диалог задания параметров. Обойдемся простым MessageBox с двумя кнопками: YES и NO. Если пользователь отменит обработку изображения, то вернем редактору код userCanceledErr.

procedure DoParameters(var param : FilterRecord);
var
   ans   : integer;
begin
   ans := MessageBox(0, 'Развернуть картинку?', 'Flip', MB_YESNO);
   case ans of
      0: begin
         MessageBox(0, 'Невозможно загрузить диалог.',
                       'Ошибка', MB_OK);
         resultCode := userCanceledErr;
         end;
      IDYES:
         resultCode := noErr;
      else
         resultCode := userCanceledErr;
   end;
end;

При вызове плагина на этом этапе пользователь увидит такое окно:

Развернуть картинку? [Yes] [No]

DoPrepare. Здесь нужно вычислить необходимый плагину размер памяти, но мы ничего делать не будем.

procedure DoPrepare(var param : FilterRecord);
begin
end;

DoStart. Вообще, в целях экономии ресурсов нужно обрабатывать изображение кусками, но для простоты запросим сразу все изображение. Запишем в поля param.inRect (исходное изображение) и param.outRect (результат) размеры всего изображения. Обратите внимание, что у каждого угла сначала указывается координата Y, а потом X. Если выделить прямоугольную часть изображения, то правый край выделения будет проходить по правым границам выделенных пикселей и правая координата выделения будет на 1 больше, чем максимальная координата выделенных пикселей. Аналогично с нижним краем. Т.е. горизонтальные координаты пикселей изменяются в диапазоне от 0 до param.imageSize.h - 1, но координаты соответствующего выделения будут 0 и param.imageSize.h.

procedure DoStart(var param : FilterRecord);
begin
   SetRect(param.inRect, 0, 0, param.imageSize.v, param.imageSize.h);
   param.outRect := param.inRect;
   param.inLoPlane := 0;
   param.inHiPlane := param.planes - 1;
   param.outLoPlane := 0;
   param.outHiPlane := param.planes - 1;
end;

Мы использовали процедуру SetRect. Напишем ее. Еще раз обращаю внимание на порядок задания параметров (сначала Y, а потом X - именно в таком порядке задаются поля записи Rect, будем следовать принятым в Photoshop соглашениям).

procedure SetRect(var r : Rect; top, left, bottom, right : smallint);
begin
   r.top := top;
   r.left := left;
   r.bottom := bottom;
   r.right := right;
end;

DoContinue. Редактор может несколько раз вызывать эту операцию, пока хотя бы одно из полей inRect, outRect или maskRect указывает на непустую часть изображения. Мы обрабатываем изображение сразу целиком и процедура вызовется всего один раз.

procedure DoContinue(var param : FilterRecord);
type
   DataBuffer  = array [0..1000000000] of byte;
var
   x, y, p  : integer;
   inData   : ^DataBuffer;
   outData  : ^DataBuffer;
begin
   inData := param.inData;
   outData := param.outData;

   { Переворачиваем изображение }
   for y := 0 to param.imageSize.v - 1 do
      for x := 0 to param.imageSize.h - 1 do
         for p := 0 to param.planes - 1 do
            outData[param.outRowBytes*y + param.planes*x + p] :=
               inData[param.inRowBytes*y +
                      param.planes*(param.imageSize.h - x - 1) + p];

   SetRect(param.inRect, 0, 0, 0, 0);
   param.outRect := param.inRect;
   param.maskRect := param.inRect;
end;

DoFinish. Здесь можно произвести какие-нибудь завершающие действия для своих нужд.

procedure DoFinish(var param : FilterRecord);
begin
end;

Теперь укажем компилятору расширение библиотеки 8bf, присоединим ресурсы, подключим модули, объявим переменную resultCode и экспортируем процедуру ENTRYPOINT:

library Flip;

{$E 8bf}
{$R Flip_prop.res}

uses
   Windows,
   PITypes,
   PIFilter;

var
   resultCode  : smallint;


   { ... здесь должны быть описанные выше процедуры }


exports
   ENTRYPOINT;

end.

Для компиляции плагина понадобятся модули PITypes.pas, PIGeneral.pas и PIFilter.pas. Эти модули я написал на основе аналогичных заголовочных файлов PITypes.h, PIGeneral.h и PIFilter.h из Adobe Photoshop 6.0 SDK.

Назад | Содержание | Вперед


© Ярослав Музыкантов muzykantov@mail.ru
При использовании материалов обязательна ссылка на сайт
students.pm.vogu35.ru/pages/pm03/mya