Свойство geometricBounds, единицы измерения
Свойство geometricBounds является одним из самых употребительных при решении задач автоматизации верстки в Индизайне при программировании на языке JavaScript. Оно определяет координаты объектов на полосах издания. Представляет собой массив, состоящий из 4-х элементов строкового или числового типа, который содержит координаты Х и Y верхнего левого и правого нижнего углов какого-либо объекта (см. рис.).
Например, координаты можно задать так:
with(myTextFrame){ geometricBounds = ["61p", "4p", "62p", "45p"]; } |
или при создании нового объекта в в составе метода add()
var myTextFrame = textFrames.add({geometricBounds:["0pt", "0pt", "100pt", "100pt"]}) |
Здесь задание координат Y1, X1, Y2, X2 производится при помощи массива из четырех членов. В нашем случае это четыре строки, но чаще используются числа.
geometricBounds = [25, 40, 100.5, 80.25]; |
Заметьте, что первой координатой в паре X-Y является координата Y. Следует также помнить, что в качестве разделителя между целой и дробной частью в числовых единицах измерения используется точка, а не запятая. Начинающие разработчики часто набивают себе шишки на этом. Возможно также задание единиц измерения, где в качестве разделителя между целой и дробной частью стоит единица измерения, напр., 1p6 т.е. 1 пика + 6 пунктов.
Если при задании geometricBounds не указаны никакие единицы измерения, например:
geometricBounds = [0,0,72,72] |
то при выполнении скрипта InDesign будет использовать те единицы измерения, которые сейчас установлены для документа.
В скриптах единицы измерения задаются в установках документа viewPreferences. Для этого используется следующий код:
myDoc = app.activedocument; // задаем единицы измерения picas with (myDoc.viewPreferences){ horizontalMeasurementUnits = MeasurementUnits.picas; verticalMeasurementUnits = MeasurementUnits.picas; } |
Здесь horizontalMeasurementUnits — единицы измерения для горизонтальной шкалы, verticalMeasurementUnits — для вертикальной.
Если надо задать другие единицы измерения, то внутри конструкции with используйте строки:
horizontalMeasurementUnits = MeasurementUnits.points; verticalMeasurementUnits = MeasurementUnits.points; //или horizontalMeasurementUnits = MeasurementUnits.inches; verticalMeasurementUnits = MeasurementUnits.inches; //или horizontalMeasurementUnits = MeasurementUnits.inchesDecimal; verticalMeasurementUnits = MeasurementUnits.inchesDecimal; //или horizontalMeasurementUnits = MeasurementUnits.millimeters; verticalMeasurementUnits = MeasurementUnits.millimeters; //или horizontalMeasurementUnits = MeasurementUnits.centimeters; verticalMeasurementUnits = MeasurementUnits.centimeters; //или horizontalMeasurementUnits = MeasurementUnits.ciceros; verticalMeasurementUnits = MeasurementUnits.ciceros; |
Если вы хотите использовать в скрипте единицы измерения, отличные от тех, которые в настоящий момент использует InDesign, то хорошим тоном считается по окончании работы скрипта вернуть всё на место, как было до запуска скрипта. Фирма Adobe Systems в составе демонстрационных скриптов приводит пример этого:
//ResetMeasurementUnits.jsx var myDocument = app.activeDocument; with (myDocument.viewPreferences){ // Сохраняем старые единицы измерения в переменных myOldXUnits, myOldYUnits var myOldXUnits = horizontalMeasurementUnits; var myOldYUnits = verticalMeasurementUnits; // Устанавливаем новые единицы измерения horizontalMeasurementUnits = MeasurementUnits.points; verticalMeasurementUnits = MeasurementUnits.points; } //---------------------------------------------------------- // Основной код скрипта //---------------------------------------------------------- // Возвращаем Индизайну старые единицы измерения with (myDocument.viewPreferences){ try{ horizontalMeasurementUnits = myOldXUnits; verticalMeasurementUnits = myOldYUnits; } catch(myError){ alert("Could not reset custom measurement units."); } } |
Определять и задавать единицы измерения можно с использованием прототипов:
var myDocument = app.activeDocument; myDocument.prototype.setUnitsTo = function(newUnits) { var arrUnits = (newUnits.length) ? newUnits : [newUnits,newUnits]; with(this.viewPreferences) { horizontalMeasurementUnits = arrUnits[0]; verticalMeasurementUnits = arrUnits[1]; } } Document.prototype.getUnits = function() { return([ this.viewPreferences.horizontalMeasurementUnits, this.viewPreferences.verticalMeasurementUnits ]); } |
В тексте программного модуля затем формируется массив из двух значений и устанавливаются новые единицы измерения
var units = this.activeDocument.getUnits(); app.activeDocument.setUnitsTo(MeasurementUnits.points); |
В конце работы программы возвращаются первоначальные единицы измерения:
app.activeDocument.setUnitsTo(units); |
О чем молчит Adobe
Если требуется рассчитать geоmetricBounds для текстового фрейма, у которого размер равен размеру страницы, то можно воспользоваться функцией, которую приводит фирма Adobe в своих примерах:
myDocument = app.activeDocument with(myDocument.documentPreferences){ var myPageWidth = pageWidth; var myPageHeight = pageHeight; } var myPage = app.activeWindow.activePage; var myTextFrame = myPage.textFrames.add( { geometricBounds:[0, 0, myPageHeight, myPageWidth] } ); |
Конечно редко нужно создавать текстовый фрейм размером на всю страницу. Гораздо чаще требуется ограничить создаваемый фрейм полями страницы. Рассмотрим функцию myGetBounds() (демонстрационный пример Adobe), которая рассчитывает geometricBounds в этом случае.
var myDocument = app.activeDocument; var myTextFrame = myPage.textFrames.add({geometricBounds:myGetBounds(myDocument, myPage), contents:TextFrameContents.placeholderText}); function (myDocument, myPage) { var myPageWidth = myDocument.documentPreferences.pageWidth; var myPageHeight = myDocument.documentPreferences.pageHeight if(myPage.side == PageSideOptions.leftHand){ var myX2 = myPage.marginPreferences.left; var myX1 = myPage.marginPreferences.right; } else{ var myX1 = myPage.marginPreferences.left; var myX2 = myPage.marginPreferences.right; } var myY1 = myPage.marginPreferences.top; var myX2 = myPageWidth - myX2; var myY2 = myPageHeight - myPage.marginPreferences.bottom; return [myY1, myX1, myY2, myX2]; } |
Как видите, для правильного расчета координат в скрипте используются свойства по определению положения страницы на развороте — правая или левая (.leftHand). Но тем не менее здесь скрыт подводный камень, о котором Adobe не сказала ни слова. Засада в том, что функция myGetBounds() правильно определяет массив координат geometricBounds только в том случае, если у каждой страницы своё начало координат и своя координатная система. Если же система координат общая для всего разворота, то рассчитанные координаты для правой страницы будут неверны, и создаваемый текстовый фрейм вместо правой страницы окажется на левой. Странно, что этот факт нигде не отражен в примерах скриптов фирмы Adobe.
Для того, чтобы эта функция всегда правильно работала, перед её вызовом надо установить отдельную координатную систему на каждую страницу разворота
myDocument.viewPreferences.rulerOrigin = RulerOrigin.pageOrigin; var myTextFrame = myPage.textFrames.add({geometricBounds:myGetBounds(myDocument, myPage), contents:TextFrameContents.placeholderText}); |
Если вы намерены менять координатную систему, то по окончании работы скрипта будет благородно вернуть её назад:
var oldRuler = myDocument.viewPreferences.rulerOrigin; myDocument.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN; var myTextFrame = myPage.textFrames.add({geometricBounds:myGetBounds(myDocument, myPage), contents:TextFrameContents.placeholderText}); // выполняем скрипт //............... // Возвращаем первоначальную систему координат myDocument.viewPreferences.rulerOrigin = oldRuler; |
Вы уже заметили использование параметра RulerOrigin.PAGE_ORIGIN? Этим параметром произведена установка одного из типов координатной системы. В Индизайне их три: spread, page, spine. Соответственно в объектной модели (раздел Preference > viewPreferences) свойство ruleOrigin может принимать значения RulerOrigin.SPREAD_ORIGIN, RulerOrigin.PAGE_ORIGIN, RulerOrigin.SPINE_ORIGIN.
Второй вариант получения всегда правильных координат заключается в модификации функции myGetBounds(), где происходит разветвление расчета в зависимости от установленной в текущий момент системы координат:
function myGetBounds(myDocument, myPage){ var myPageWidth = myDocument.documentPreferences.pageWidth; var myPageHeight = myDocument.documentPreferences.pageHeight; myRuler = myDocument.viewPreferences.rulerOrigin; if(myPage.side == PageSideOptions.leftHand){ var myX2 = myPage.marginPreferences.left; var myX1 = myPage.marginPreferences.right; } else{ if(myRuler == RulerOrigin.pageOrigin || myRuler == RulerOrigin.spineOrigin) { var myX1 = myPage.marginPreferences.left; var myX2 = myPage.marginPreferences.right; } else // система координат общая для разворота { var myX1 = myPageWidth + myPage.marginPreferences.left; var myX2 = myPageWidth + myPage.marginPreferences.right; } } var myY1 = myPage.marginPreferences.top; var myX2 = myPageWidth - myX2; var myY2 = myPageHeight - myPage.marginPreferences.bottom; return [myY1, myX1, myY2, myX2]; } |
В этом случае менять и возвращать первоначальную координатную систему не требуется. Теоретически этот способ более медленный, но вряд ли на практике вы это заметите.
С этим «pageOrigin» тоже нужно держать ухо востро. Простой пример: создаём документ с тремя страницами (смысл — нужен именно разворот), задаём линейке параметр «Ruler Per Page» и запускаем такой скрипт (рисует текстовый фрейм на правой странице разворота… в смысле, нам надо, чтоб нарисовал):
var myDoc = app.activeDocument;
var p = myDoc.pages;
var pb = p[2].bounds;
p[2].textFrames.add({geometricBounds:pb});
А теперь зададим линейке параметр «Ruler Per Spread» и запустим тот же скрипт. У меня результат отличается. А у вас? )))