Основы скриптов в Photoshop на примере выравнивания тона изображений товара

Предисловие: экшены в Photoshop школьники уже освоили, и без проблем добавляют логотипы своих пабликов на тысячи изображений, а некоторые девочки пакетно обрабатывают фото с пляжей. Пора бы выучить что-нибудь более сложное? Рынок, как видите, растет : )

В Photoshop для автоматизации работы существует ещё один, гораздо более продвинутый инструмент — язык программирования JavaScript. Для работы вам потребуется немного освоить скриптинг для автоматизации некоторых задач и избавления от рутины. Это ни в коем случае не программирование, не бойтесь. Для освоения вам потребуется лишь минимум Photoshop CS2 и максимум желания прокачать свои скилы.

Писать код мы будем в программе ExtendScript Toolkit, которая поставляется вместе с Photoshop, и большинство нормальных моушн-дизайнеров давно осведомлены об этой и ещё паре программ для написания кода. Я практик, поэтому и реализовывать скрипт будем под реальную задачу, которая передо мной стояли на работе.

Задача: в любых интернет-магазинах есть картинки товара, в крупных магазинах товар исчисляется десятками тысяч. Обычно сидят 2-3 девочки-ретушера и обрабатывают фотографии товара: обтравливают, добавляют белый фон, увеличивают контраст, добавляют отражения, ретушируют обложки… но упускают из вида очень важный момент – разная насыщенность, разный контраст, разный цветовой баланс отдельных изображений. Посмотрите на картинку ниже. Обложки явно отличаются по контрасту, цвету… если вывести средние тона, то становится понятно, откуда проблема)

64747

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

Начнем издалека. Что же такое JavaScript в Photoshop?
Я выбрал JS как язык для скриптования в продуктах Adobe, потому что он работает и на Windows, и на MAC. Если вы ярый приверженец винды, то используйте бейсик, если вы неукротимый фанат Мака, то AppleScript в помощь. А я за универсальность.

Основы:
DOM. Это та изнанка программы, которая дает нам возможность получат доступ к различным компонентам Photoshop через язык программирования. Это иерархическое представление Photoshop, каждой его части и возможности, включая работу с открытыми изображениями. Все то, что вы можете сделать мышкой, вы сможете сделать и скриптом. Например, если вы хотите получить доступ к прозрачности слоя, необходимо пройтись по пути Application> Document> Layer> Opacity, а код будет такой

app.activedocument.activeLayer.opacity = 50;

Все довольно логично, например Layer Comp class отвечает за управление просмотром нескольких версий макета в одном файле, что в общем то и делает оригинальный инструмент Photoshop.

Важно понять, что подразумевается под объектами. Сам Photoshop это объект, текст это объект, направляющие это объект, каждый канал RGB является объектом. Все, что кликается мышкой — объекты. Допустим, вы создали новый документ, а с точки зрения программы вы создали новый объект.
DOM модель в Photoshop
Основы программирования объяснять я не стану, слишком много людей с ними знакомы. Если вы не знакомы, то найдете необходимую информацию везде, начиная c Google play и заканчивая форумами школьников. Для затравки, откройте ExtendScript Toolkit и напишите: alert(«My first Hello Hell!» + app.version); Запустите через редактор скриптов, обрадуйтесь своему первому успешно скомпилированному приложению. Скрипты для Adobe Photoshop имеют расширение jsx.


Вводная информация:
Переменные обозначаются как var borderWidth = 10
var — переменная. А borderWidth — имя переменной (как думаете, что оно означает?).
Затем переменной нужно присвоить значение: = 10

В заголовке скрипта иногда имеет смысл писать строчку #target photoshop, которая будет указывать, что данный скрипт только для Photoshop.

Активный объект
Когда Вы работает в Photoshop, Вы можете рисовать только на слое, который активен в данный момент. Для скриптов тоже важно, какой объект выбран, т.к. скрипты тоже могут и будут рисовать. Ниже приведен пример создания документа и выбор слоя активным:

var doc_nmb_1 = documents.add(500, 500)
var doc_nmb_2 = documents.add(500, 500)
//Установим Document 1 как активный документ
activeDocument = doc_nmb_1
 
//Сделаем Document 2 активным
activeDocument = doc_nmb_2
 
//Добавим слоев к документам
var layer1 = doc_nmb_2.artLayers.add()
var layer2 = doc_nmb_2.artLayers.add()
 
//Сделаем 1-ой слой документа 2 активным. ActiveLayer отвечает за чтение и запись выбранного слоя.
doc_nmb_2.ActiveLayer = layer1
 
//Делаем 2-ой слой документа 2 активным
doc_nmb_2.ActiveLayer = layer2

Создание нового документа происходит благодаря следующему коду, создаются квадратные изображения в размерах 72 и 144.

var docRef = app.documents.add(72, 72)
var otherDocRef = app.documents.add (144,144)

Как видите, читать такой код не так уж и трудно. Перейдем к написанию скрипта. Первое, что мы должны сделать, это вникнуть в задачу и разработать action для применения к нужным изображениям. Сделав это, начинаем писать скрипт.

Главная фишка: конструкция If Else, которая и позволяет добавлять условия, которых не хватает в action. Уверен, многие уже, увидев зарплаты программистов, пытались освоить программирование и if else наверняка писали, поэтому по основам мы просто пробежимся:

if(!content) content =404;

Мы проверяем, есть ли у переменной content значение, и если его нет, то присваиваем значение 404. Можно расписать и более сложную обработку, например:

if ((comment == null)||(comment == “”)) {
comment = ”undefined”;
alert(“Введите комментарий, пожалуйста!);

С If мы разобрались, а что же делает else? В конструкции else мы указываем, что выполнять в том случае, если в if значение будет false.

if (name != null)
alert(“Привет ” + username +!);
else {
username = prompt(“Введите свое имя”);
alert(“Привет” + username+!);
}
 
if (doc.width > doc.height)
{ //если портрет
app.doAction('TIL320->300','2010');
} else { //если пейзаж
alert("как то так", "Error");
}

Учитывая это, мы уже может написать необходимый код с событийностью:

main()
function main()
{
if (documents.length==2480)
{ //если нет открытых документов, то
alert ("Это другой проект, его я не трогаю(", "Error"); //вот так выводятся всякие алерты
} else {
var doc = activeDocument;
if (doc.width > doc.height)
{
app.doAction('Medium Sharping','2013');
app.doAction('Correct Highlights','2013');
} else {
app.doAction('Super Sharp','2013');
app.doAction('Color neynral','2013');
}
}

Как вы видите, если изображение равняется по высоте 2480px, то просто выскакивает ругающееся на дизайнера окошко. Если изображение вертикальное, то применяется определенная группа экшенов для подготовки контента, если горизонтальная, то другая группа экшенов.

Какие ещё возможности можно добавить в скрипт, или могли бы быть просто интересны?
Создание нового документа нужного формат делается довольно просто:

var docRef = app.documents.add(297, 210, 300, "A4_gorizontal", NewDocumentMode.LAB, DocumentFill.BACKGROUNDCOLOR, 1)

Расшифруем конструкцию: (width, height, resolution, name, mode, initialFill, pixelAspectRatio)
В данном случае в конце можно добавить bitsPerChannel и colorProfileName, но думаю, для начала нам хватит и имеющейся конструкции. Единицы измерения по умолчанию пиксели, давайте поменяем. Меняем на миллиметры:

preferences.rulerUnits = Units.MM //сделать размер документа в единицах изрененияCM INCHES MM PERCENT POINTS PIXELS PICAS
preferences.typeUnits = TypeUnits.MM //задать для шрфиов единицу измерения - пиксели

Мы же не хотим сидеть около монитора и тыкать Enter? Мы хотим быстренько перекинуть все таски в баг-трекере на программиста! Давайте не дадим Photoshop’у возможность о чем либо сообщать и ждать нажатия ОК, делается это так:

displayDialogs = DialogModes.NO

Далее копирайты внутри файла. Мы должны добавить информацию о том, что файл сделан нами а не начальником. Добавим метаданные в File info.

docInfoRef = docRef.info
docInfoRef.copyrighted = CopyrightedType.COPYRIGHTEDWORK
docInfoRef.ownerUrl = "http://www.your-scorpion.ru"
docRef.info.author = "Your-scorpion"
docRef.info.country = "Russia"

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

Итоговый работающий код:

#target photoshop//только для Photoshop
// 2013. Используете на свой страх и риск.
 
var docRef = app.documents.add(297, 210, 300, "A4_gorizontal", NewDocumentMode.LAB, DocumentFill.BACKGROUNDCOLOR, 1)
var layerRef = app.activeDocument.artLayers.add()
//layerRef.name = "MyBlendLayer"//создает слой на текущем документе
layerRef.blendMode = BlendMode.NORMAL  //а этот набор команд создаст слой с именем MyBlendLayer и редимом наложения normal
 
docInfoRef = docRef.info
docInfoRef.copyrighted = CopyrightedType.COPYRIGHTEDWORK
docInfoRef.ownerUrl = "http://www.your-scorpion.ru"
docRef.info.author = "Your-scorpion"
docRef.info.country = "Russia"
preferences.rulerUnits = Units.MM //сделать размер документа в единицах изрененияCM INCHES MM PERCENT POINTS PIXELS PICAS
preferences.typeUnits = TypeUnits.MM //задать для шрфиов единицу измерения - пиксели
displayDialogs = DialogModes.NO  //позволит отключить диалоги с разными подтверждениями
 
var strokeColor = new SolidColor();
        strokeColor.cmyk.cyan = 0;
        strokeColor.cmyk.magenta = 100;
        strokeColor.cmyk.yellow = 100;
        strokeColor.cmyk.black = 0;
 
 var selRef = app.activeDocument.selection.fill(strokeColor)  
var textColor = new SolidColor;
textColor.cmyk.cyan = 0;
textColor.cmyk.magenta = 0;
textColor.cmyk.yellow = 100;
textColor.cmyk.black = 0;
 
var newTextLayer = docRef.artLayers.add();
newTextLayer.kind = LayerKind.TEXT;
newTextLayer.textItem.contents = "Letters Typography";
newTextLayer.textItem.position = Array(12.75, 47.75);
newTextLayer.textItem.size = 155;
newTextLayer.textItem.font =  "Helvetica";
newTextLayer.textItem.color = textColor;
docRef = null;
textColor = null;
newTextLayer = null;
 
main()
 
function main() 
{ 
if (documents.length==2480) 
{ //если нет открытых документов, то
alert ("Это другой проект, его я не трогаю(", "Error"); //вот так выводятся всякие алерты
} else { 
var doc = activeDocument; 
if (doc.width > doc.height)
{  
app.doAction('Medium Sharping','2013'); 
app.doAction('Correct Highlights','2013'); 
} else { 
app.doAction('Super Sharp','2013'); 
app.doAction('Color neynral','2013'); 
}
}
}

Если подытожить, то мы получили скрипт, который в зависимости от условий применяет те или иные экшены. А также, научились создавать документы и применять основные действия на JS. В общем то, для решения поставленной задачи вышеописанной техники достаточно. Примерно такое решение, сделанное как плагин, я отдавал подчиненным. Результат:

64747

Небольшая жизненная мудрость: мы можем записать действия пользователя в файл скрипта.
1. Берем файл «ScriptListener.8li» с сайта Adobe и закидываем в %ProgramFiles%Adobe\Adobe Photoshop CS5\Plug-ins\Automate\
2. Запускаем Photoshop
3. Делаем необходимые действия.
4. На рабочем столе забираем файлики ScriptListener.jsx и ScriptListener.vbs
5. (!)Удаляем ScriptListener.8li!
И мы получаем работающий говно-код, который никому нельзя показывать, но можно использовать в своих технических интересах.

И последнее. Чтобы скрипт заработал, нужно набрать текст скрипта в ExtendScript Toolkit и сохранить как <имя файла>.jsx. Затем в Photoshop перейти в меню File->Scripts->Browse и выбрать файл скрипта.
Думаю, при упоминании моушн-дизайнеров в начале статьи многие задумались, раз среда программирования и язык одни и те же, то возможно ли на скриптах автоматизировать межпрограммные действия? Да, это возможно. Также, с помощью скриптов вы также можете убрать надоедливые окна подтверждения при различных действиях. И ещё много чего интересного. Но во всем нужно знать меру, не нужно изобретать велосипед. Для автоматизации некоторых действий иногда будет лучше использовать Data Merge в inDesign, Print Merge в Corel, HTML+CSS+PHP. Но фотообработку и работу с графикой лучше Photoshop ничто не сделает.

Следующим этапом автоматизации работы в Photoshop является создание своих панелей (Adobe Configurator). Вы можете добавить в свою панель экшены и скрипты, повесить на них горячие клавиши. Важный нюанс: панели работают только при открытом документе. Все фотошопы версии CC поддерживают панели, написанные на HTML & CSS & JQUERY.

Скрипты не только экономят ваше время, но и не дают вам совершить ошибку с названиями, параметрами и прочими важными вещами. Удачи!

14 комментариев

  1. Владимир, Red Keds studio

    У меня аналогичная задача, скажи, как тебе удалось решить вопрос с ресайзом картинок и подгонкой их под нужный формат? Мне тут задачку одну подкинули по подготовке постеров, а ты вроде единственный, кто эту задачу смог грамотно автоматизировать.

    Итак, есть 1500 постеров от фильмов. И есть 5 разных форматов для телефонов, планшетов, телевизор и т.п. Там они могут быть и квадратные, и вытянутые… разные. Так вот эти постеры нужно как то кадрировать и подгонять под эти форматы.
    Подскажешь, как лучше решить такую задачу?

    • artmax2 (Author)

      Всех секретов я раскрывать не буду, трудовой договор не позволяет) Я бы на вашем месте действовал так:
      Допустим, нужны постеры размером 1000x600px.

      1. сначала нужно создать папку со всеми исходными картинками. Копируешь код скрипта в файл формата jsx, в коде увидишь размер картинки в пикселях, 500 на 500px. Меняешь на 1000x600px, сохраняешь, и запускаешь через file-script. Картинка ужмется/отмаштабируется до размеров 1000px.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      
      doc = app.activeDocument;  
      doc.changeMode(ChangeMode.RGB);  
      // тут менять размер
      var fWidth = 500;
      var fHeight = 500;
       
       
      if (doc.height > doc.width) {
          doc.resizeImage(null,UnitValue(fHeight,"px"),null,ResampleMethod.BICUBIC);
      }
      else {
          doc.resizeImage(UnitValue(fWidth,"px"),null,null,ResampleMethod.BICUBIC);
      }
       
      // а тут настройки сохранения
      var options = new ExportOptionsSaveForWeb();
      options.quality = 70;
      options.format = SaveDocumentType.JPEG;
      options.optimized = true;
       
      var newName = 'web-'+doc.name+'.jpg';
       
      doc.exportDocument(File(doc.path+'/'+newName),ExportType.SAVEFORWEB,options);

      2. Скрипт подгоняет и сразу сохраняет все картинки, поэтому не забудь сделать бэкапы фоток (параметры сохранения в скрипте тоже есть и редактируются). После того, как скрипт отработает, делаешь фотошопский экшен, который приведет картинку к пропорциям 100% на 60%. (через image —> canvas).

      Либо:
      1) взять инструмент Crop tool, установить у него пропорции нужные в опциях
      2) закинуть несколько файлов в фотошоп и сразу их обрезать в нужном соотношение, часть фото все равно пришлось бы в ручную переделывать после скрипта.
      3) и сохранять, сохранять, сохранять.

      Автоматизированное решение объединяет оба подхода, и работает через File -> Automate -> Batch.

      • alt-matveev

        А как вы выравнивали яркость изображений?

        • your-scorpion (Author)

          Это была часть экшена. Насыщенность и цветовую гамму копировал с одного постера на другие с помощью инструмента Match Color. В закладке Source нужно выбрать файл с яркостью/насыщенностью и подвигать ползунки. Любимый инструмент всех фотобашеров.

          • Анастасия Колонина

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

          • your-scorpion (Author)

            Существует готовый код для таких вещей

            // If you want to change AnchorPosition 
            // use these constants
            //BOTTOMCENTER
            //BOTTOMLEFT
            //BOTTOMRIGHT
            //MIDDLECENTER
            //MIDDLELEFT
            //MIDDLERIGHT
            //TOPCENTER
            //TOPLEFT
            //TOPRIGHT
            
            if (documents.length > 0) 
            {
                docRef = activeDocument;
            
                displayDialogs = DialogModes.NO;
            
                if (docRef.width > docRef.height)
                 {
            	docRef.resizeCanvas (docRef.width, docRef.width, AnchorPosition.MIDDLECENTER);
                 }
                 else
                 {
            	docRef.resizeCanvas (docRef.height, docRef.height, AnchorPosition.MIDDLECENTER);
                 }    
              
            }
            else
            {
            	alert("There must be at least one open document.");
            }

            Хотя, вы не указали формат изображений. Если речь о jpeg, то также можно воспользоваться Adobe Lightroom. В параметрах экспорта выставляете ограничение по ширине и высоте в нужное количество px, и имена для файлов. Из дополнительных вариантов решения задачи, посмотрите программу XnView. Не лишним будет почитать про ImageProcessor и Picture Processor.

  2. aexisting_mind

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

    • your-scorpion (Author)

      Я сам не могу похвастаться хорошими навыками программирования. Но я и не программист, а для решения дизайнерских задач моих навыков пока что хватает).
      Посоветую практиковаться, практиковаться, практиковаться, решать задачи, читать статьи, книги, брать простенький фриланс.

    • Грамотный код на JavaScript… есть определенные стандарты, они легко гуглятся. Базовые идеи такие:

      • Для улучшения читаемости кода, рекомендую выставлять размер отступа в вашей среде разработки на 4 символа пробела, которые представляют собой знак табуляции;
      if/else/for/while/try разделяются пробелом также для улучшения читаемости;

      1
      2
      3
      
      for(var i = 0; i < 100; i++) {
      // statements
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      // Неправильно
      var tea = "";
      var mia = "";
      var qoo;
       
      // Правильно
      var tea = "",
          mia = "",
          qoo;

      • Предпочтение лучше отдать `===`, а не `==`. Оператор == сравнивает на равенство, а оператор === сначала проверяет тип (typeof), а потом проверяет значение. Оператор === может похвастаться тем, что не приводит два значения к одному типу.
      • «Ранние возвраты» способствуют читабельности кода почти без потери в производительности (то бишь, для фотошопа сгодится)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      
      // Неправильно:
      function returnLate(chanse) {
          var kat;
          if (chanse) {
              kat = "chanse";
          } else {
              kat = "quux";
          }
          return kat;
      }
       
      // Правильно:
      function returnEarly(chanse) {
          if (chanse) {
              return "chanse";
          }
          return "quux";
      }

      • Имена переменных не короче трех букв. Исключение — счетчики циклов;
      • По минимуму использовать глобальные переменные;
      • Файл не более 1000 строк;

      1
      2
      3
      4
      
      // Объявление Конструктора
      function ChinChan( options ) {
          this.options = options;
      }

      И еще несколько сотен критериев, которые вам помогут писать более качественный код.