Этот пост — продолжение первой части, где был представлен скрипт Expand Clipping Mask и детально описано, что и как он делает, а также попутно рассмотрены основные принципы создания подобных программ в целом. В этой части я продолжу рассказ о том, как добавить в программу новый функционал, чтобы из "заготовки" получить на выходе "готовое изделие". Здесь не обойтись без более глубокого погружения в предметную область, что является одним из необходимых условий создания полноценного продукта. Итак, начинаем погружение! В качестве контура маски в Adobe Illustrator могут быть использованы следующие графические примитивы: простой контур (Path), составной контур (Compound Path), составная форма (Compound Shape) и текстовые объекты (Point Text и Text on the Path). На данный момент скрипт работает только с простыми контурами, что видно из приведенного ниже кода, где PathItem — это обращение к элементу Path. Перед этим мы объявили переменную clipPath, но не присваили ей значение. Это значит, что ее значение пока не определено, т.е. оно undefined. Если сейчас выделить маску, контуром которой будет, скажем, Compound Path и запустить скрипт, то программа выдаст ошибку на последней строчке функциональной части скрипта, так как условие в цикле не будет выполнено, переменная clipPath так и останется undefined, а применить метод remove() к чему-то неопределенному невозможно. Чтобы не допустить такой ситуации, мы сделаем следующее — присвоим clipPath значение null, которое, в отличии от undefined, уже что-то более определенное, что можно хотя-бы проверить. Теперь можно превратить наши размышления/поиски в код. Первым делом проверяем, что clipPath в предыдущей итерации не был определен, а дальше копируем уже написанный блок кода и вносим в него небольшие изменения. Собственно, изменения коснутся только одной строки. Как мы здесь видим, 'PathItem' поменялся на 'CompoundPathItem', а также добавилась новая конструкция 'pathItems[0]', с помощью который мы обращаемся к элементу составного контура. Ниже приведен функциональный блок кода, созданный на данный момент. Следующий на очереди "пациент" — это Compound Shape (составная форма). Вот здесь становиться совсем интересно! В документации мы вообще не находим такого объекта. Что делать? Для начала давайте определим к какому классу объектов он относится. Чтобы выяснить это, напишем небольшой вспомогательный код, который потом выкинем. Как было сказано в первой части, мы не касаемся вопроса используемых инструментов для написания/отладки кода. Поэтому предположим, что это будет отдельный файл, которой потом просто отправится в корзину. Код будет следующим: В первой строке мы создаем ссылку на выделенный объект, во второй — выводим сообщение о том, каким типом он является. Выделяем в Adobe Illustrator контур маски, т.е. тот самый объект Compound Shape и запускаем скрипт. В окне сообщения мы видим, что Compound Shape представляет из себя PluginItem. Избавляемся от вспомогательного кода, снова возвращаемся к документации, но не находим у PluginItem ни свойства clipping, ни pathItems. Вообще ничего, что помогло бы нам однозначно указать, что этот объект является контуром маски. Из скрипта даже нельзя определить, что это за plugin. Какой-то внешний модуль и всё тут! Алгоритм определения контура маски, представленный объектом Compound Shape, тогда будет следующим: перебираем в цикле все объекты маски и, когда обнаруживаем PluginItem, то удаляем его и проверяем изменилось ли свойство clipped у контейнера маски. Если оно стало false, значит это и есть наш контур. Единственное, чтобы этот hack сработал, надо после удаления объекта обновить DOM Illustrator, что можно сделать методом app.redraw(). Потом еще надо не забыть вернуть удаленный объект, что делается методом app.undo(). Ниже приведен код для контура Compound Shape: Теперь из всех возможных вариантов типа объектов, которые могут быть контуром маски, остался только текст (или TextFrameItem, в терминологии illustrator scripting references). Снова обращаемся к документации и опять не находим там свойства clipping. Но на этот раз мы уже не переживаем так сильно по этому поводу и спокойно выясняем, что у TextFrameItem есть свойство kind, которое определяет тип текстового объекта (TextType). Выясняем, что таких типов может быть три: AREATEXT, POINTTEXT и PATHTEXT. Первый тип нам не интересен, так как его нельзя использовать в качестве контура маски, а другие два еще как интересны. Остается только найти hack, который поможет нам определить теперь уже не контур, а текстовый объект, являющийся контуром маски. И этим hack-ом станет команда, Convert To Area Type, которая конвертирует POINTTEXT в AREATEXT. Как и в случае с Compound Shape, при этом происходит неявное изменение свойства clipped. Соответственно, код для TextFrameItem типа POINTTEXT будет следующим: Остался только TextFrameItem типа PATHTEXT. К сожалению, при конвертировании PATHTEXT в AREATEXT, свойство clipped не изменяется. Но так как это последний из возможных претендентов на звание "контур маски", то можно использовать именно такое его поведение. То есть проверяем, что после выполнения команды Convert To Area Type свойство clipped осталось true. Ниже приведен код для TextFrameItem типа PATHTEXT. Таким образом, если собрать вместе последовательно написанные части кода, включая блок проверок, то мы получим такой код, выполнение которого, как было заявлено еще в первой части поста, будет реализовывать действие новой команды Expand Clipping Mask в Adobe Illustrator. Здесь можно поставить точку. Нет, лучше точку с запятой. Надеюсь, этими постами я помог вам стать немного ближе к своей цели — начать программировать в Adobe Illustrator. Спасибо за внимание!