• Главная <
  • Галерея
  • Карта сайта
  • Наши контакты
  • Обратная связь

Максимум оголошень з мінімумом витрат

У минулій статті (Publish № 12, 2011 року; http://www.publish.ru/publish/2011/12/19814095/ ) Порушувалися ази управління InDesign скриптами. Навіть освоївши тільки їх, можна істотно скоротити кількість ручної роботи, якої і так з головою вистачає при верстці. Описаний тоді скрипт значно економить час і сили, хоча займає буквально пару рядків. Головне в написанні сценаріїв - розуміти підпорядкованість об'єктів, тоді не буде ніяких проблем (по крайней мере, не повинно виникати - опис об'єктної моделі практично не містить неточностей) ні з адаптацією наших скриптів, ні в написанні власних.

На цей раз візьмемося за більш цікаве завдання. Скрипт буде трохи складніше, але не по управлінню InDesign, а за логікою - куди, що, як і в якій послідовності ставити. Він на 90% замінює праця верстальника з оформлення рекламних оголошень, причому чим видання крупніше, тим вигода відчутніше.

Скрипт розставляє рамки навколо рекламних блоків в газетах безкоштовних оголошень. Таке оформлення привертає до блокам читачів і є одним з фінансових джерел існування видання. Припустимо, в газеті два види оформлення блоків: рамки з округленими краями і різним кольором фону - без заливки, але з чорною окантовкою, і повністю чорний фон (текст вивороткой), а окантовки немає.

Вибір способу реалізації

Такий стиль оформлення зустрічається часто, тому скрипт має велике практичне значення. Якщо ж у виданні прийнятий інший стиль, буквально пара змін - і він запрацює так, як потрібно саме вам.

Спочатку, як завжди, проведемо аналіз способів реалізувати таке оформлення засобами 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% виграш у часі. Чи доречно в даному випадку вчинити так само? В принципі, протипоказань немає; єдине, що потребують докорінної переробки, - логіка визначення початку і кінця рамки. Оскільки доведеться «озиратися по сторонах» при появі абзаців з неоднозначними стилями (можливо, навіть частіше, ніж в запропонованому варіанті), то не факт, що вдасться зберегти виграш у часі, та ще скільки займе налагодження. Чи варта шкурка вичинки - вирішувати вам. Можливо, знайдете більш захоплююче заняття на той час, поки комп'ютер ретельно виконує довгий скрипт ...

Про автора: Михайло Борисов ( [email protected] ), Пише для Publish корисні поради з додрукарської підготовки та огляди ПО.

Але як отримати округлені кути і як бути, якщо потрібна тільки тонка рамка (коли фонової заливки не потрібно)?
IsValid)?
IsValid)?
Чому я запропонував брати значення з поточного абзацу, а не з стилю, адже це значно повільніше?
Чи доречно в даному випадку вчинити так само?
Новости