По роду своей деятельности мне периодически приходится автоматизировать свою работу в фотошопе. Точнее я мог бы этого не делать, но природная лень не оставляет шансов в борьбе с рутиной, как говориться «лучше час потерять, зато потом за 5 минут долететь». Все бы наверное так и оставалось на уровне отдельных разрозненных скриптов если бы не пост от enotus. Благодаря ему я узнал, что к фотошопу (как впрочем и другим продуктам от Adobe) можно писать расширения на HTML+JS. И пошло, поехало.
Как-то так сложилось, что изучение всего нового я обычно начинаю с написания простенькой игрушки на этом самом новом. Для фотошопа я выбрал Сапера. В этом примере я бы хотел рассказать о создании интерфейса расширения, взаимодействии с фотошопом и обработкой событий. Так что кому все еще интересно, прошу подкат.
Как уже описано в статье моего предшественника нам понадобится Brackets с установленным расширением ну и собственно сам Photoshop.
Также рекомендую сразу запастись документацией со страницы Adobe: наиболее вероятно что потребуется Photoshop CC JavaScript Reference и возможно Photoshop CC Scripting Guide. Они не имеют прямого отношения к написанию расширений, но потребуются для взаимодействия с фотошопом.
Приступаем. Создадим проект в Brackets при помощи расширения:
У нас появится папка с полным набором файлов для работы расширения:
![](http://habrastorage.org/files/34f/35a/0f2/34f35a0f2c104d4493f3aaad22e94800.png)
В папку CSS я закинул дополнительно файл для светлой темы topcoat т.к. предпочитаю работать со светлым интерфейсом, но это не обязательно. Кстати о Topcoat, скачать и почитать документацию можно тут.
Manifest можно и не трогать, для последней версии фотошопа там все настроено. Если потребуется изменить иконку расширения или разрешить работу в фотошопе более ранней версии, уточните эти моменты в документации от производителя.
В папке js нас интересует main.js, собственно основной файл нашего проекта. Но прежде чем переходить к нему нам нужно создать интерфейс нашего расширения. Это делается с помощью HTML в файле index.html.
И остался еще один важный файл о котором я не упомянул: hostscript.jsx. JSX скрипт это как раз то что использовали уже довольно давно для автоматизации различных процессов в фотошопе и других проектах от Adobe. У них даже есть специальная утилитка ExtendScript Toolkit, она тоже может пригодится, например для отладки скриптов jsx.
index.html
В этом файле тоже уже все подготовлено, подключена темная тема topcoat, добавлены все необходимые скрипты. Собственно все что требуется, это заполнить div#content:
<div id="content"> <div> Поле:<br> <input type="text" id="w" class="topcoat-text-input" placeholder="width" value="6"> x <input type="text" id="h" class="topcoat-text-input" placeholder="height" value="6"><br> Количество мин:<br> <input type="text" id="m" class="topcoat-text-input" placeholder="width" value="8"><br> <button id="btn_start" class="topcoat-button--large hostFontSize">New game</button> </div> <hr> <div> <h2>Осталось открыть: <span id="res">-</span></h2> <h3><span id="timer">0</span> sec.</h3> <button id="btn_check" class="topcoat-button--large hostFontSize" disabled>Check cell</button> </div> <div> <button id="btn_mark" class="topcoat-button--large hostFontSize" disabled>Mark</button> <button id="btn_unmark" class="topcoat-button--large hostFontSize" disabled>UnMark</button> </div> </div>
В результате мы получим следующую картину:
![](http://habrastorage.org/files/d20/35b/df5/d2035bdf53684d0a8326552f87eca5c7.png)
Можно переходить к JS.
main.js
По сути тут уже есть пример самого простого использования:
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ /*global $, window, location, CSInterface, SystemPath, themeManager*/ (function () { 'use strict'; var csInterface = new CSInterface(); function init() { themeManager.init(); $("#btn_test").click(function () { csInterface.evalScript('sayHello()'); }); } init(); }());
Самая главная тут строчка это csInterface.evalScript(‘sayHello()’);, именно таким образом происходит взаимодействие с приложением. Дело в том, что механизм расширений универсальный и не зависит от приложения в котором выполняется, но по этой же причине ни чего не знает от функционале — ему все равно фотошоп это иллюстратор. Именно для этого и используются скрипты JSX. А sayHello() лишь один из методов реализованных в hostscript.jsx.
Но, нам же нужно не только передавать данные в jsx, но и получать результаты. Поэтому можно использовать callBack функцию, в том числе анонимную:
csInterface.evalScript('checkCell()', function(result){ if(result<=0) { stopGame(); } else { $("#res").html(result); //вывод количества закрытых клеток без мин } });
Вот примерно так я проверяю клетки на мины: result содержит количество клеток которые еще нужно открыть для победы. Мина соответствует -1. Если вы обратили внимание среди скриптов сразу подключен jQuery. Так что взаимодействовать с интерфейсом проще простого.
Единственный момент требующий отдельного упоминания в рамках main.js это реакция на события происходящие в приложении за пределами нашего расширения. С одной стороны тут все просто, с другой хуже чем хотелось бы. Первым делом с попытался поймать клик мышкой в документе — не тут то было, такого события просто нет. Как выяснилось позже события относятся скорее ко всему приложению, а не к документу и имеют характер «использован фильтр», «отменено последнее действие» и тому подобное. Помимо этого у всех событий есть 4-х буквенный идентификатор и длинный цифровой и в нашем случае нужен именно длинный цифровой, а в документации указаны лишь короткие коды. Благо у каждого приложения есть метод конвертации одного идентификатор в другой, но он работает в рамках jsx-скрипта.
В общем я не буду сейчас вас грузить деталями, воспользуемся примером из документации:
function registerPhotoshopEvent(in_eventId) { var event = new CSEvent("com.adobe.PhotoshopRegisterEvent", "APPLICATION"); event.extensionId = csInterface.getExtensionID(); event.appId = csInterface.getApplicationID(); event.data = in_eventId csInterface.dispatchEvent(event); } csInterface.addEventListener("PhotoshopCallback" , function(event) { csInterface.evalScript("return (app.documents.length > 0)", stopGame) }); var closeEventid = "1131180832"; //идентификатор события закрытия документа registerPhotoshopEvent(closeEventid);
hostscript.jsx
Как я уже писал ранее, это основной способ взаимодействия с приложением, в данном случае с Photoshop CC. Вот тут то и пригодится скаченная в самом начале Photoshop CC JavaScript Reference. Там содержится описание свойств и методов различных объектов фотошопа.
Я приведу здесь лишь пару примеров. Начнем с создания документа:
var startRulerUnits = app.preferences.rulerUnits; // сохраняем текущие единицы измерения preferences.rulerUnits = Units.PIXELS; //Заменяем единицы измерения на пикселы //создаем документ mainDoc = app.documents.add(width, height, dpi, "Game", NewDocumentMode.RGB);
Вы прекрасно знаете, что размеры в фотошопе можно задавать в разных системах измерения. Соответственно и результат измерения вы будете получать в тех-же единицах. Поэтому за этим нужно внимательно следить. Чтобы не получить неприятный сюрприз лучше подстраховаться и перевести единицы измерения к нужному значению.
Обращаю внимание, что есть исключения. Например, выделенная область всегда задается и измеряется только в PIXELS. А например все векторные объекты меряются исключительно в POINTS.
Для конвертации единиц измерения я использовал небольшой метод подсмотренный где-то на просторах интернета:
function convertValue(value, from, to) { output = new UnitValue(value, from); return output.as(to); }
Но и тут вас ждет сюрприз. Конвертация из мм и дюймов в пикселы всегда происходит из расчета 72 точки на дюйм и если у вас другое разрешение изображения, следует произвести пересчет самостоятельно.
Ну и пожалуй последний пример. Очень многие вещи которые мы привыкли в фотошопе делать как одно действие программно нужно реализовывать множеством команд. Например для склеивания слоев разными способами (склеить все, только видимые, связанные) нужно реализовывать самостоятельно. Из доступных есть только вариант склеить с предыдущим слоем, а дальше уже ваше дело (проверять видимость, связанность, менять местами слои). Похожая ситуация с выделением области. Вы не можете выделить круг или столбец в один пиксел. Все что вам предлагают засунуть массив координат точек, а уж какая это будет фигура лишь от вас зависит:
function DrawBomb(layer, x, y, colorHEX) { var startRulerUnits = app.preferences.rulerUnits; // сохраняем единицы измерения preferences.rulerUnits = Units.PIXELS; //Заменяем единицы измерения на пикселы mainDoc.activeLayer = layer; mainDoc.selection.select([ [(x+0.2)*cellSize+padding, (y+0.2)*cellSize+padding], [(x+0.8)*cellSize+padding, (y+0.2)*cellSize+padding], [(x+0.8)*cellSize+padding, (y+0.8)*cellSize+padding], [(x+0.2)*cellSize+padding, (y+0.8)*cellSize+padding], [(x+0.2)*cellSize+padding, (y+0.2)*cellSize+padding] ]); var color = new SolidColor; color.rgb.hexValue = colorHEX; mainDoc.selection.fill(color); mainDoc.selection.deselect(); preferences.rulerUnits = startRulerUnits; //восстанавливаем единицы измерения }
Можно и поиграть
Ну вот, интерфейс нарисован, обработчики в js написаны, логика в jsx реализована, можно и поиграть.
Не забываем включить Debug Mode, чтобы мы увидели свое не подписанное расширение в фотошопе.
Теперь можно запускать Photoshop и активировать наше расширение:
Ну теперь можно и поиграть. Правда из-за того, что клики по картинке не отлавливаются, нужно двигать красный прямоугольник и нажимать кнопки действий на панели расширения.
Ну и видео процесса:
Напоследок скажу пару слов про подписывание ваших расширений.
Не забываейте удалять все скрытые файлы перед подписыванием.
В Windows путь к папке с расширением нужно начинать с точки, примерно так:
ZXPSignCmd.exe -sign ./ru.mobak.habrasample ru.mobak.habrasample.zxp cert.p12 pass
И прошу, не судите строго мой код, все таки я не программист.
Файлы
Исходники расширения можно скачать тут.
Готовое расширение которое можно установить через Adobe Extension Manager лежит тут. Подписано самодельным сертификатом, так что матюкается маленько.
ссылка на оригинал статьи http://habrahabr.ru/post/253337/
Добавить комментарий