101 СПОСОБ  ЗАРАБОТАТЬ   НА ПЕЧАТИ

Максимум объявлений с минимумом затрат

  • Михаил Борисов
  • 19 апреля 2012 г.
  • 5585
Макет до работы скрипта и после него (результат в сочетании со скриптом из первой статьи) В прошлой статье (Publish № 12, 2011; http://www.publish.ru/publish/2011/12/19814095/) затрагивались азы управления InDesign скриптами. Даже освоив только их, можно существенно сократить количество ручной работы, которой и так с головой хватает при вёрстке. Описанный тогда скрипт значительно экономит время и силы, хотя занимает буквально пару строк. Главное в написании сценариев — понимать подчинённость объектов, тогда не будет никаких проблем (по крайней мере, не должно возникать — описание объектной модели практически не содержит неточностей) ни с адаптацией наших скриптов, ни в написании собственных.

На этот раз возьмёмся за более интересную задачу. Скрипт будет чуть сложнее, но не по управлению InDesign, а по логике — куда, что, как и в какой последовательности ставить. Он на 90% заменяет труд верстальщика по оформлению рекламных объявлений, причём чем издание крупнее, тем выгода ощутимее.

Скрипт расставляет рамки вокруг рекламных блоков в газетах бесплатных объявлений. Такое оформление привлекает к блокам читателей и является одним из финансовых источников существования издания. Допустим, в газете два вида оформления блоков: рамки со скруглёнными краями и разным цветом фона — без заливки, но с чёрной окантовкой, и полностью чёрный фон (текст вывороткой), а окантовки нет.

Выбор способа реализации

Два варианта оформления платных объявлений. На выносках— названия стилей форматирования текста: основной текст — Body, дополнительные — имеют приставки Foto- и Txt-соответственноТакой стиль оформления встречается часто, поэтому скрипт имеет большое практическое значение. Если же в издании принят другой стиль, буквально пара изменений — и он заработает так, как нужно именно вам.

Сначала, как всегда, проведём анализ способов реализовать такое оформление средствами InDesign. Первое, что приходит в голову, — использовать «Линии абзаца» (Rule above / Rule below): подбирая ширину линий так, чтобы между ними не было зазоров, можно добиться полной имитации рамки. Но как получить скруглённые углы и как быть, если нужна только тонкая рамка (когда фоновой заливки не требуется)? Вариант отпадает, рассмотрим другой: прямоугольники со скруглёнными углами, благо, InDesign их поддерживает. Можно даже задать нужный радиус скругления как стиль оформления и элементарно внести изменения.

Продумаем размещение прямоугольников на полосе. Если бы в газете использовались только рамки без чёрного фона, то простейшим вариантом стало бы внедрение прямоугольников в текст как заякоренных (anchored) объектов, у которых отключено обтекание текста Ignore Text Wrap (в таком случае рамка располагается над текстом, но не выталкивает его). Среди преимуществ — при редактировании текста все рамки будут двигаться вместе с ним. Но в нашем случае подход не применим: один тип контейнера для рекламного блока имеет чёрную заливку и при расположении над текстом просто его закроет.

Остаётся только создавать рамки, никак к тексту не привязанные. Естественно, скрипт должен запускаться в самом конце вёрстки, когда любые изменения в тексте исключаются. Но будем реалистами — иногда случаются форс-мажоры, и, если изменения в тексте значительны, подгонка его к ранее расстановленным рамкам будет слишком трудоёмка. Быстрее и проще запустить скрипт заново. Поэтому рамки удобно размещать на отдельном слое — в экстренной ситуации просто удаляем его и готовы к повторному запуску скрипта. Как показали полевые испытания, расстановка рамок в документе из 20 тыс. абзацев без каких-либо ухищрений по оптимизации быстродействия занимает 10-15 минут, что вполне приемлемо (33 абзаца в секунду — не так уж быстро для системы с процессором на 2 ГГц, но всё же лучше, чем вручную).

Для удобства желательно использовать стили — InDesign поддерживает Object Style (<Window/Styles/Object Styles> — полная аналогия с традиционными стилями для текста, но с параметрами, специфическими для геометрических объектов). Соответственно стили объектов назовём WhiteRect (блок без заливки) и BlackRect (чёрный блок). Будем размещать их на разных слоях под текстом — WhiteFramesLayer и BlackFramesLayer. Их положение относительно других слоёв можно свободно менять (например, если основной текст вёрстки располагается на нескольких слоях), что даёт дополнительную гибкость в работе.

Определимся с расположением рамки относительно рекламного объявления. В целях удобочитаемости она должна начинаться чуть выше первой строки объявления, а заканчиваться чуть ниже последней (величину отступов можно задать жёстко в самом скрипте, или вынести в файл настроек, или вводить через окно пользовательского интерфейса). Простейший способ разграничить объявления — назначить разные стили абзацу, начинающему и заканчивающему объявление. Перебирая абзацы и наткнувшись, например, на стиль NachaloBloka, скрипт поймёт, что нужно начинать рисовать рамку, а дойдя до стиля KonetzBloka — закончить рисование.

В связи с этим выдвигается требование к ПО, из которого текст с объявлениями выгружается (после заноса их в базу данных наборщицами): программа должна проставлять все необходимые маркеры, чтобы потом в InDesign не возникло путаницы. Каждый блок должен иметь только одно начало и только один конец, вложение не допускается (подряд несколько NachaloBloka или KonetzBloka). Это единственное условие корректной работы скрипта. Соблюсти его совсем не сложно: как правило, объявление логически форматируется ещё при наборе (в отдельные поля заносятся заглавие, текст, картинка), а выводя информацию в файл, программа автоматически добавляет нужный тэг (маркер), следя, чтобы обязательно присутствовал конечный.

Нам осталось лишь определить правила, по которым скрипт должен то начинать рисовать рамку, то заканчивать. Ведь для выделения объявлений может использоваться множество стилей, поэтому нужно придумать механизм, исключающий неопределённость. В качестве примера приведу реальную ситуацию: один тип рекламного блока в газете образован тремя абзацами — со стилями «header», «body», «picture»; другой всего двумя — «body», «picture»; а третий — вообще «header», «body». Следовательно, для принятия решения о том, начинать рамку или нет, придётся оглядываться на соседние абзацы: ведь если нам встретился стиль «body», ещё не факт, что рамка должна начинаться именно в этом месте. С ростом количества стилей ситуация становится более запутанной… Но, как правило, в газетах используются лишь пара-другая стилей оформления.

Предлагаемый скрипт применяется в газете, где для платных объявлений есть три варианта оформления: для выделения текстовых объявлений (TxtHeader, Txt), для объявлений с фото (Body, Foto) и плюс заголовок (FotoHeader, Body, Foto). В прошлом скрипте от нас фактически требовалось только вставить в нужное место изображение, тут же дело сложнее. Но пролог уже закончен, перейдём к реализации.

Подготовка к основной части

Вначале определяем необходимые объекты: текущий документ, стили абзацев, объектов, создаём отсутствующие слои (layers.add()), проверяем наличие стилей для графических объектов и абзацев. Если чего-то недостаёт (свойство isValid), экстренно завершаем работу и выводим сообщение о причине остановки.

aD = app.activeDocument;
pS = aD.paragraphStyles, oS = aD.objectStyles, layers = aD.layers;

if(!pS.item(“TxtHeader”).isValid || !pS.item(“Txt”).isValid || !pS.item(“Foto”).isValid || !pS.item(“Body”).isValid || !pS.item(“FotoHeader”).isValid)
return alert(“Required paragraph style(s) missed.”);

WhiteRectStyle = oS.itemByName(“WhiteRect”);
BlackRectStyle = oS.itemByName(“BlackRect”);
if(!WhiteRectStyle.isValid || !BlackRectStyle.isValid)
return alert(“Required frame style(s) missed.”);

LayerBlack = (!layers.itemByName(“BlackFrames”).isValid) ? layers.add({name:”BlackFrames”}) : layers.itemByName(“BlackFrames”);

LayerWhite = (!layers.itemByName(“WhiteFrames”).isValid) ? layers.add({name:”WhiteFrames”}) : layers.itemByName(“WhiteFrames”);

Поскольку от заякоренных объектов мы были вынуждены отказаться, вся забота о вычислении координат каждого блока перекладывается на наши плечи (в случае с заякоренными можно задавать относительное смещение). Поскольку InDesign в своём внутреннем представлении использует типографские пункты (point), установим их для простоты текущими единицами измерения. Разумеется, сохраним исходные, чтобы по окончании работы скрипта всё восстановить. Несколько необычно название родительского объекта для единиц измерения, но если вдуматься, логика станет ясна:

viewPrefs = aD.viewPreferences;
viewPrefsOld = [viewPrefs.horizontalMeasurementUnits, viewPrefs.verticalMeasurementUnits];
viewPrefs.horizontalMeasurementUnits = MeasurementUnits.points, viewPrefs.verticalMeasurementUnits = MeasurementUnits.points;

Следующие строчки нам уже знакомы. Как и раньше, для корректной работы сценария необходимо поместить курсор в любой текстовый блок основного материала (story):

app.scriptPreferences.enableRedraw = false;
myStory = app.selection[0].parentStory;
if( !myStory.isValid ) return alert(‘Place cursor into text frame’);
var paras = myStory.paragraphs;
var columnWidth = paras[0].parentTextFrames[0].textFramePreferences.textColumnFixedWidth;

Основная часть

Параметры абзацев, которые мы должны учестьПереходим к самому «вкусному». Просматриваем все абзацы выбранного материала (Story) и проверяем их стиль: если его название совпадает с соответствующими началу объявления с рамкой, высчитываем положение её верхней границы. В первом приближении его можно получить, исходя из положения базовой линии первой строки абзаца (baseline) и высоты символов (ascent). Если же заголовка нет (сразу идёт фото), вместо текстовых используем параметры, свойственные изображению. Для удобства восприятия рамка должна отстоять от верхней границы текста на некотором расстоянии (extra), кроме того, учтём интервалы между абзацами SpaceBefore и SpaceAfter, которые задаются в свойствах абзаца (в присвоенном стиле или же переопределены локально).

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

Уточняем действия в случае, если попался стиль «Foto»: если до него стиль «FotoHeader» уже встретился, то ничего не предпринимаем; в противном случае узнаём, что начинается новое платное объявление и получаем значения, необходимые для начала рисования рамки.

Если попадаются стили «Txt» или «Body», отмечаем положение низа рамки (рассчитывается как положение базовой линии последней строки — endBaseline + выступ текста вниз — descent), к которому добавляем значение отступа после абзаца (spaceAfter) плюс уже упоминавшийся дополнительный отступ extra.

Опишем этот механизм:

var baseline, before, after, ascent, descent, fotoHeaderFlag, currPara;
for(var i=0; i<P.length; i++){ 
 currPara = P[i];
var paraStyleName = currPara.appliedParagraphStyle.name;
if(paraStyleName==“FotoHeader”) fotoHeaderFlag = true; 
 switch(paraStyleName){ 
   
case “TxtHeader”: //начало объявления 
    case “FotoHeader”: 
       baseline = currPara.lines[0].baseline; 
       before = currPara.spaceBefore/2; 
       ascent = currPara.ascent; 
         break; 

    case “Foto”:       
if( !fotoHeaderFlag ) {     
baseline = currPara.allGraphics[0].geometricBounds[0]; 
       before = currPara.spaceBefore/2; 
       ascent = extra; } 
      break; 

    case “Txt”: //конец объявления 
    case “Body”: 
       var top = baseline — ascent — before — extra; 
       var btm = currPara.endBaseline + currPara.descent + after + extra;

Определяем положение левого края

Используемые стилиНа данный момент у нас есть практически всё для создания рамки: положение верхней и нижней границы, её ширина (равна ширине текстового блока). Осталось узнать положение её левого края. Тут всё зависит от вёрстки макета: если материал перетекает по многоколоночным текстовым контейнерам, то вариантов несколько. Например, каждый раз узнавать номер текущей колонки, после чего учитывать ширину колонок плюс расстояние между ними (gutter). Если же материал перетекает по независимым контейнерам, то задача предельно упрощается: достаточно узнать левую границу текущей колонки. Для наших целей ограничимся последним вариантом, чтобы не распыляться на второстепенные вопросы.

Проще всего воспользоваться для определения положения левого края колонки её свойством parentTextFrames. Это вся цепочка текстовых колонок, в которых размещён текущий материал Story, и где-то среди них находится нужный абзац. Поскольку считаем, что перед запуском скрипта текст полностью свёрстан, ситуация, когда объявление начинается в одной колонке, а заканчивается в другой, исключается. Чтобы не перегружать статью непринципиальными моментами, будем считать, что имеем дело с одноколоночным вариантом текста (т. е. существует только parentTextFrames[0]). Свойства графического блока (размеры и стиль) задаём сразу же в момент его создания (значения top и btm были получены чуть ранее, а columnWidth — практически в самом начале).

currTextFrame = currPara.parentTextFrames[0];
leftBorder = currTextFrame.geometricBounds[1];
ramka = currTextFrame.parentPage.rectangles.add({

geometricBounds: [top, leftBorder, btm, leftBorder + columnWidth], 
 appliedObjectStyle: WhiteRectStyle});

Завершающие штрихи

Последний шаг: назначение рамке стиля в зависимости от стиля абзаца и переброска её на соответствующий слой:

(paraStyleName == fotoHeaderFlag) ? (
ramka.appliedObjectStyle = BlackRectStyle,
ramka.move(LayerBlack)) : ramka.move(LayerWhite);

После того, как закончили рисовать рамку, снова включаем отслеживание неоднозначных моментов — и так до самого конца материала:

fotoHeaderFlag = false;

Осталось лишь восстановить размерность единиц измерения (напрямую связаны с координатными линейками) и разблокировать панели InDesign.

viewPrefs.horizontalMeasurementUnits = viewPrefsOld[0];
viewPrefs.verticalMeasurementUnits = viewPrefsOld[1];
app.scsriptPreferences.enableRedraw = true;

Поздравляю! Мы закончили скрипт. Сложный ли он — сказать трудно, всё зависит от вашего опыта. Главная сложность — правильно определить начало и конец рамок, остальное — вопросы второстепенные. Во время отладки скрипта удобно пользоваться панелью Data Browser из инструмента разработки ESTK (ExtendScript Toolkit). Если переменная задана через специальное слово var и используются функции, то её легко отыскать среди остальных свойств и методов, поскольку в таком случае ExtendScript показывает только те свойства, которые используются в самой функции (локальные).

Величина отступов от краёв текста extra подбирается экспериментально, в зависимости от личных предпочтений. Для удобства её значение можно хранить в отдельном месте, например, файле pref.ini (в нём же можно переназначать стили оформления объявлений). Единственное, что осталось после работы скрипта: вручную передвинуть слои с рамками под слои с текстом — это специально оставлено, поскольку скрипт не может знать, куда именно их двигать (ведь в вёрстке элементы оформления могут быть разбросаны по нескольким слоям).

Замечания

Как обычно, несколько советов и уточнений. Первое по поводу абзацных отступов SpaceBefore и SpaceAfter. Скрипт работает корректно всегда, за исключением режима принудительного распределения текста по всей высоте колонки (Justify vertically). При нём оба эти параметра остаются неизменными, изменяется межстрочное расстояние, что в данном скрипте не учитывается. Во избежание неувязок можно использовать скрипт, выполняющий вёрстку текста полностью (в коллекции автора есть и такой), либо модифицировать предлагаемый скрипт, учитывая расстояние между нижней границей предыдущего объявления и верхней границей текущего.

Второе замечание касается газет, в которых закрашенные рамки не используются. Тут пригодятся возможности заякоренных объектов (in-line anchored). Вот фрагмент скрипта, создающего такой тип объекта (обратите внимание на задаваемые размеры):

inlineRect = currPara.insertionPoints[0].
rectangles.add({ 
 geometricBounds: [baseline, 0, btm, columnWidth], 
 appliedObjectStyle: roundedOStyle});
inlineRect.anchoredObjectSettings.properties = { 
 anchoredPosition: AnchorPosition.anchored, 
 anchorPoint: AnchorPoint.topLeftAnchor,
 horizontalReferencePoint: AnchoredRelativeTo.textFrame,
 verticalReferencePoint: VerticallyRelativeTo.lineBaseline,
 horizontalAlignment: HorizontalAlignment.centerAlign, 
 anchorYoffset: 0 — (ascent + before + extra)};
}

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

Напоследок несколько слов о быстродействии. В предыдущей статье для ускорения работы предлагалось сменить порядок просмотра материала на противоположный по отношению к традиционному (с конца в начало), что даёт 30% выигрыш во времени. Уместно ли в данном случае поступить так же? В принципе, противопоказаний нет; единственное, что потребует коренной переделки, — логика определения начала и конца рамки. Поскольку придётся «оглядываться по сторонам» при появлении абзацев с неоднозначными стилями (возможно, даже чаще, чем в предложенном варианте), то не факт, что удастся сохранить выигрыш во времени, да ещё сколько займёт отладка. Стоит ли овчинка выделки — решать вам. Возможно, найдёте более увлекательное занятие на то время, пока компьютер кропотливо исполняет долгий скрипт…


Об авторе: Михаил Борисов (bmike68b@gmail.com), пишет для Publish полезные советы по допечатной подготовке и обзоры ПО.

ПОХОЖИЕ СТАТЬИ
Тире без отступа

Году в 2008-м в комментариях тогда ещё «Живого журнала» случился прелюбопытнейший спор об оформлении абзацного отступа: ведь правый край текстового фрейма даже при множестве переносов и с отключённой оптической компенсацией всегда выглядит сносно, а вот левый по умолчанию страдает — от красных строк и реплик; как с этим быть?

RGB-workflow в печати: почему «цифра», а не традиционный офсет

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

Иллюстрируем мобильно

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

Допечатные эксцессы или 6 «детских» ошибок

Рейтинг самых частых ошибок в макетах печатной продукции по опыту типографии FastPrint, принимающей заказы через автоматизированную систему онлайн-проверки.

Лак и фольгирование со скоростью «цифры»

Подготовка макетов для цифрового облагораживания: выборочного УФ-лакирования и фольгирования.



Новый номер

Тема номера: Больше порядка. R-SUPERLAM AF-540. Пятикнижие конструкторов-полиграфистов. ARK-JET SOL 1804. Офсет – при своих. Когда ты – вне конкуренции. Бум в этикетке и не только. Глобальный плакат. Скрепка 2024. Интерлакокраска-2024. Инлегмаш 2024.



Организовав печать по текстильным материалам, стоит ли заводить своё швейное производство или лучше печатать на сторону?
    Проголосовало: 27