Think.JS №19

  • Для начинающих: Работа со слоями
  • Учим матчасть: Кто знает, что ждет нас
  • Полевые испытания: Печать. Списки и объекты
  • Полезный скрипт: Теперь я знаю, что и сколько весит

Содержание

Для начинающих: Работа со слоями

Учим матчасть: Кто знает, что ждет нас

Полевые испытания: Печать. Списки и объекты

Полезный скрипт: Теперь я знаю, что и сколько весит

Для начинающих

Работа со слоями

Слои – они полезные. С помощью слоев можно организовать публикацию наиболее правильным образом, например, перенести всю тяжелую графику на отдельно выделенный для нее слой, который отключать при работе с текстом. Скорость работы InDesign при этом существенно возрастает.

Новый слой создается при помощи метода layers.add(). Родительским объектом, относительно которого вызывается этот метод, является объект типа документ. При создании слоя он, что естественно, становится доступным на всех страницах документа, как добавленных после создания, так и существовавших ранее.

addLayer.jsx
Скрипт демонстрирует создание слоя
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
// Создаем новый слой
  var myLayer = myDoc.layers.add({name: "Новый слой"});
// В активном окне делаем активным созданный слой  
  activeWindow.activeLayer = myLayer;
// Создаем прямоугольник
  var myRectangle = myDoc.rectangles.add({geometricBounds: [10,10,50,50]});
}

При создании нового слоя можно не указывать его имя, задав его позже. Если имя не задано, то слою присваивается имя LayerN, где N – порядковый номер слоя.

Объекты типа pageItems и guides можно перемещать со слоя на слой. На самом деле перемещения нет – просто изменяется «принадлежность» объекта, которая определяется свойством itemLayer. Для перемещения объекта со слоя на слой нужно в это свойство передать передать ссылку на целевой слой.

moveToLayer.jsx
Скрипт демонстрирует «перемещение» объекта со слоя на слой
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
// Создаем новый слой
  var myLayer = myDoc.layers.add({name: "Новый слой"});
// В активном окне делаем активным созданный слой  
  activeWindow.activeLayer = myLayer;
// Создаем прямоугольник
  var myRectangle = myDoc.rectangles.add({geometricBounds: [10,10,50,50]});
// "Перемещаем" прямоугольник на первый слой документа
  myRectangle.itemLayer = myDoc.layers.lastItem();
}

Свойство visible определяет, будет ли указанный слой видимым. При значении true слой будет отображаться, при значении false – нет. При этом, естественно, все объекты, находящиеся на этом слое, будут видимы, когда отображение слоя будет включено, и невидимы, если отображение будет отключено.

invisibleLayer.jsx
Скрипт демонстрирует возможность отключения отображения слоя.
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
// Создаем новый слой
  var myLayer = myDoc.layers.add({name: "Новый слой"});
// В активном окне делаем активным созданный слой  
  activeWindow.activeLayer = myLayer;
// Создаем прямоугольник
  var myRectangle = myDoc.rectangles.add({geometricBounds: [10,10,50,50]});
// Делаем слой невидимым
  myLayer.visible = false;
}

Иногда бывает полезным оставить слой видимым, но отключить возможность редактирования объектов, которые расположены на нем. Это полезно в том случае, если на отдельный слой вынесены постоянные элементы макета, которые нужно учитывать, но крайне нежелательно редактировать. Чтобы сделать слой «закрытым» нужно воспользоваться логическим свойством locked. При значении true слой будет недоступен для редактирования, при значении false – доступен.

lockedLayer.jsx
Скрипт демонстрирует возможность «закрывания» слоя
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
// Создаем новый слой
  var myLayer = myDoc.layers.add({name: "Новый слой"});
// В активном окне делаем активным созданный слой  
  activeWindow.activeLayer = myLayer;
// Создаем прямоугольник
  var myRectangle = myDoc.rectangles.add({geometricBounds: [10,10,50,50]});
// Делаем слой закрытым
  myLayer.locked = true;
}

В изданиях, которые используют несколько видов модульной сетки можно применять следующее решение. Каждая модульная сетка формируется на отдельном слое, которые попеременно включаются или отключаются. Для этого можно написать несложный скрипт, раз и навсегда решив проблему переключения макета с одной модульной сетки на другую. Кроме свойства visible в этом скрипте могут быть использованы свойства lockGuides и showGuides. Это логические свойства, которые определяют, будут ли направляющие закреплены и будут ли они отображаться соответственно.

lockGuides.jsx
Скрипт демонстрирует возможность закрепления направляющей на отдельном слое
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
// Создаем новый слой
  var myLayer = myDoc.layers.add({name: "Новый слой"});
// В активном окне делаем активным созданный слой  
  activeWindow.activeLayer = myLayer;
// Создаем направляющую и задаем ее параметры
  var myGuide = myDoc.pages[0].guides.add(myLayer);
  myGuide.orientation = HorizontalOrVertical.horizontal;
  myGuide.location = 100;
// Делаем слой закрытым
  myLayer.lockGuides = true;
}

Заметим, что после выполнения скрипта направляющие, которые принадлежат другим слоям можно перемещать или удалять, если в слое, к которому они принадлежат, не установлена соответствующая опция.

Слои можно перемещать относительно друг друга при помощи метода move(), дублировать при помощи метода duplicate(), склеивать при помощи метода merge() и удалять при помощи remove().

Метод move() принимает два параметра. Первый из них должен быть одним из значений нумератора LocationOptions, а второй – ссылкой на объект, относительно которого проводится перемещение. Например, myLayer.move(LocationOptions.before, myDoc.layers.firstItem() переместит слой myLayer так, что он окажется впереди самого первого слоя документа.

Метод duplicate() не имеет параметров. Этот метод создает слой, полностью идентичный тому, для которого был вызван. Новый слой возвращается как результат выполнения метода, и содержит те же объекты, что и исходный слой.

Метод merge() позволяет склеить два и более слоев в один. В качестве параметра этому методу передается массив (даже если дополнительный слой для склеивания всего один) слоев. Результат склеивания сохраняется в слое, для которого был вызван метод. В него перемещаются все объекты со склеиваемых слоев.

duplicateAndMerge.jsx
Скрипт демонстрирует использование методов duplicate() и merge() применительно к слоям
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
// Создаем новый слой
  var myLayer = myDoc.layers.add({name: "Новый слой"});
// Активизируем новый слой
  activeWindow.activeLayer = myLayer;
// Создаем прямоугольник
  var myRectangle = myDoc.rectangles.add({geometricBounds: [10,10,50,50]});
// Создаем три копии слоя
  var myL1 = myLayer.duplicate();
  var myL2 = myLayer.duplicate();
  var myL3 = myLayer.duplicate();
// Соединяем копии с исходным слоем
  myLayer.merge([myL1, myL2, myL3]);
}

Следующий скрипт демонстрирует практическое применение слоев. Вся «свободная» (несгруппированная) графика переносится на специальный слой, который можно потом сделать невидимым, закрыть от редактирования, переместить – в общем любое действие.

moveGraphicsToLayer.jsx
Скрипт перемещает всю свободную графику на специальный слой
with (app) {
// Получаем активный документ
  try {
    var myDoc = activeDocument;
  } catch (error) {
    exit();
  }
  try {
// Пробуем создать слой
    var myLayer = myDoc.layers.add({name: "All Graphics"});
  } catch (error) {
// Если слой с таким именем существует, то получаем ссылку на него
    var myLayer = myDoc.layers.item("All Graphics")
  }
// Обрабатываем все графические объекты
  for (var counter = 0; counter < myDoc.allGraphics.length; counter++) {
    try {
// Пробуем перенести графический объект на слой для графики      
      myDoc.allGraphics[counter].parent.itemLayer = myLayer;
    } catch (error) {
// Если не получается, например, если объект входит в состав группы, пропускаем его обработку
      continue;
    }
  }
}

Учим матчасть

Кто знает, что ждет нас

На месте этой статьи должна быть другая. Но в процессе написания я посмотрел документацию по скриптам для InDesign CS3 и был повергнут в состояние эйфории от предвкушения и в черную зависть к счастливым обладателям MacOS, которые уже сейчас могут пользоваться новой версией. Итак, что нас ждет в самом ближайшем будущем?

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

Второе по важности нововведение – возможность запуска скрипта в фоновом режиме на время сессии (пока InDesign не завершит работу). Совместно с возможностью автозапуска скриптов эта возможность создает условия для написания скриптов, которые работают вообще без активного участия пользователя. Для того чтобы скрипт не просто висел в фоновом режиме, а мог принимать некоторое участие в работе, используется специальный объект eventListiner. Когда пользователь выполняет определенное действие, например, сохраняет документ, скрипт получает сообщение и может на него отреагировать запланированным образом. Например, при сохранении можно сделать многоуровневый backup документа для того, чтобы потом при необходимости можно было восстановить копию. Большинство из выполняемых пользователем событий (event), которые отслеживаются объектом eventListiner, имеют два варианта реакции: до события и после события. Как это может быть использовано? Например, если в InDesign CS3 опять будет проблема с помещением документов MS Word с кириллическими символами в имени или пути к файлу, то для решения этой проблемы достаточно написать скрипт, который отслеживал бы событие beforeImport и, по крайней мере, предупреждал бы пользователя о проблеме. В идеале, конечно, желательно реализовать замену помещаемого файла на его копию, но без кириллических символов в названии. Но на этом полезность скрипта не заканчивается. Если помещаемый файл является текстовым, то по получении события afterImport текст можно будет сразу же автоматически обработать, начиная от простой зачистки текста и заканчивая автоматическим форматированием по потребности.

Третье нововведение порадует тех авторов, которым не хватало полнофункциональных виджетов для создания красивых пользовательских диалогов. Вы хотите прогрессбар? Теперь их есть в InDesign. По косвенным данным, функциональность диалогов будет идентична функциональности диалогов в Photoshop. Для их реализации был введен новый объект app.window, который в соответствии с переданными настройками будет реализовывать разнообразные виджеты. При этом старый добрый объект app.dialog тоже будет сохранен, как для поддержки скриптов, написанных для предыдущих версий, так и для быстрой разработки интерфейсов, поскольку сложные интерфейсы потребуют больших трудозатрат и, соответственно, больше кода. Кроме продвинутых диалогов можно будет создавать контекстные меню, причем каждому пункту может быть сопоставлен свой персональный скрипт. Очень удобно: кликаешь правой кнопкой на фото и выбираешь «Обрезать», в результате чего запускается скрипт, который в Photoshop обрежет картинку по размеру контейнера. Для текстовых объектов – свое контекстное меню, например с пунктом «Обработать текст», соответственно, для обработки. Дешево, надежно и доступно.

И последнее по списку, но не последнее по значению. Теперь InDesign может совсем полноценно работать c xml, поскольку в новой версии были введены правила обработки – XML Rules. Как они реализованы для пользователя сказать пока сложно, но для автора скриптов они могут послужить заменой XPath (с определенными ограничениями в работе). Для тех, кто не знаком с технологиями xml поясняю вкратце. XPath позволяет искать, сортировать и обрабатывать xml-элементы в соответствии с потребностями текущего скрипта. Например, из xml-файла, содержащего описание некоей группы товаров можно при помощи скрипта сгенерировать таблицу нужного формата, которая будет содержать любые доступные поля в том порядке, в котором указал автор скрипта (а не исходного документа). Соответственно, форматирование таблицы также происходит во время работы скрипта. Для автоматической верстки XPath создает очень интересные возможности, позволяя генерировать документы нужного формата из сложных xml-файлов.

С выходом новой версии InDesign возникает вопрос, будут ли работать скрипты, написанные для предыдущих версий. В большинстве случаев, скрипты работать будут. По крайней мере Adobe это обещает. Главное, не забывать указывать препроцессору версию InDesign, для которой был написан конкретный скрипт (#target indesign-4). В этом случае InDesign будет обрабатывать скрипт с учетом возможностей предыдущей версии.

И для особо интересующихся защитой интеллектуальной собственности. По неподтвержденным данным скрипты jsx можно будет компилировать. Как это будет реализовано – пока неизвестно, но слух такой уже прошел. Эта возможность – серьезный плюс при разработке коммерческих скриптов.

Полевые испытания

Печать. Списки и объекты

Как уже было сказано, печать документа из InDesign – это довольно сложный процесс. Очень многое в нем зависит от конкретной системы, например, список доступных принтеров. Мало того, каждый принтер предоставляет свои возможности печати – PCL принтеры поддерживают ограниченное количество опций печати, хотя работают несколько быстрее. В общем, неопределенность едет на неопределенности и неопределенностью погоняет.

В реальности, однако, все оказывается проще, чем кажется на первый взгляд. Все настройки печати, которые целиком зависят от системы, всегда доступны из скрипта. В основном это наборы – списки допустимых значений, которые следует передавать определенным свойствам объекта printPreferences. И, что характерно, эти наборы сами являются свойствами этого объекта, что вполне разумно.

Например, чтобы получить список доступных принтеров, достаточно обревизовать свойство printPreferences.printerList.

printerList.jsx
Скрипт демонстрирует использование свойства printerList
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
  with (myDoc.printPreferences) {
// Выводим список принтеров, объединив массив в строку с разделителями - знаками абзаца
    alert(printerList.join("\n"));
  }
  myDoc.print();
}

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

Для того чтобы установить выбранный принтер в качестве текущего, достаточно передать его имя свойству printPreferences.printer. Имеется, правда, и специальное значение на тот случай, если принтеров в системе вообще нет. В таком случае из InDesign можно распечатать документ на специальный принтер PostScript File. Для этого нужно в качестве свойства printPreferences.printer установить единственное значение нумератора Printer – Printer.postscriptFile.

setPrinter.jsx
Скрипт демонстрирует процедуру установки текущего принтера
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
  with (myDoc.printPreferences) {
// Устанавливаем в качестве текущего принтера последний из списка
    printer = printerList[printerList.length - 1];
  }
  myDoc.print();
}

Как уже было сказано, многие опции печати могут быть использованы только в том случае, если принтер поддерживает PostScript. Каким образом можно определить, является ли выбранный принтер таковым? Это очень просто – если принтер поддерживает PostScript, то свойство printPreferences.ppd имеет определенное значение, которое устанавливается автоматически после выбора принтера.

checkPostScript.jsx
Скрипт демонстрирует проверку принтера на поддержку PostScript
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
  with (myDoc.printPreferences) {
// Устанавливаем в качестве текущего принтера последний из списка
    printer = printerList[printerList.length - 1];
    try {
// Если свойство ppd  для выбранного принтера определено, значит, он поддерживает PostScript, иначе - нет
      var myPPD = ppd;
      alert("Принтер поддерживает PostScript");
    } catch (error) {
      alert("Принтер не поддерживает PostScript");
    }
  }
}

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

setPPD.jsx
Скрипт демонстрирует возможность выбора произвольного ppd при использовании принтера PostScript File
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
  with (myDoc.printPreferences) {
// Выводим список ppd
    alert(ppdList.join("\n"))
// Устанавливаем принтер PostScript File
    printer = Printer.postscriptFile;
// Устанавливаем последний ppd из списка
    ppd = ppdList[ppdList.length - 1];
  }
  myDoc.print();
}

Еще одним крайне полезным списком для каждого принтера является список размеров бумаги, который он поддерживает. При необходимости можно проверить, входит ли в этот список определенный формат. После выбора принтера этот список хранится в свойстве printPreferences.paperSizeList

pageFormat.jsx
Скрипт демонстрирует возможность получения списка форматов страницы, доступных для принтера
with (app) {
// Создаем новый документ
  var myDoc = documents.add();
  with (myDoc.printPreferences) {
// Устанавливаем принтер 
    printer = printerList[printerList.length - 1];
    alert(paperSizeList.join("\n"));
  }
}

Полезный скрипт

Теперь я знаю, что и сколько весит

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

У скрипта есть своя специфика. Во-первых, он игнорирует картинки, которые расположены не на странице, а, допустим, на рабочем столе разворота. Во-вторых, скрипт игнорирует картинки, контейнер которых повернут на любой угол кроме нулевого – обсчитывать размеры трудно. В-третьих, размеры выдаются в текущих единицах измерения и округляются до сотых. Зато обрабатываются все графические форматы.

graphicsReport.jsx
Скрипт предназначен для подсчета линейных размеров и площади графики в документе
// Функция округления до сотых
function smartRound (myNum) {
  return Math.round(myNum * 100) / 100;
}
// Стандартная функция получения родительского объекта
function getParent (myObject, myType) {
  while (myObject.constructor.name != "Application") {
    if (myObject.constructor.name == myType) {
      return myObject;
    } else {
      try {
        myObject = myObject.parent;
      } catch (error) {
        return null;
      }
    }
  }
  return null;
}
// Функция для получения размеров объекта
function getInfo(myObject) {
  try {
    with (myObject) {
      var myHeight = smartRound(visibleBounds[2] - visibleBounds[0]);
      var myWidth = smartRound(visibleBounds[3] - visibleBounds[1]);
      var mySquare = smartRound(myHeight * myWidth);
      return "высота: " + myHeight + ", ширина: " + myWidth + ", площадь: " + mySquare;
    }
  } catch (error) {
    return "";
  }
}
with (app) {
// Получаем активный документ  
  try {
    var myDoc = activeDocument;
  } catch (error) {
    alert("Нет открытых документов!");
    exit();
  }
// Создаем текстовую переменную для хранения статистики  
  var myString = "";
// Обрабатываем все графические файлы  
  for (var counter = 0; counter < myDoc.allGraphics.length; counter++) {
// Получаем родительскую страницу картинки, если она не на странице, то пропускаем обработку
    var myPage = getParent(myDoc.allGraphics[counter], "Page");
    if (myPage != null) {
      var myObject = myDoc.allGraphics[counter].parent;
    } else {
      continue;
    }
// Пробуем получить декодированное имя файла. Если имени файла нет, то используем спецзначение    
    try {
      var myName = decodeURI(File(myDoc.allGraphics[counter].itemLink.filePath).name);
    } catch (error) {
      var myName = "UNDEFINED";
    }
// Проверяем, повернут ли контейнер. Если да, то игнорируем картинку    
    if (myObject.rotationAngle == 0) {
// Если нет, то добавляем строку в статистику
      myString += myName + "\t" + getInfo(myObject) + "\n";
    } else {
      continue;
    }
  }
// Создаем файл для хранения статистики  
  var myFile = File(activeScript.path + "/graphicsReport.txt");
// Сохраняем файл и запускаем его
  try {
    myFile.open("w");
    myFile.write(myString);
    myFile.close();
    myFile.execute();
  } catch (error) {
    alert(myString)
  }
}

Олег Бутрин
THINK.JS выпуск № 19 от 2007-04-09

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s