Оператор в PostScript - это слово, заставляющее интерпретатор выполнять те или иные действия. Он эквивалентен командам или процедурам в других языках программирования. Когда интерпретатор встречает слово в PostScript-программе, он просматривает свой внутренний словарь и пытается определить, является ли это слово именем оператора. Если оно в словаре найдено, то выполняются все связанные с ним действия, а затем переходит к следующему слову в исходном файле.
Каждый объект либо литерал (literal), либо исполняемый(executable). Это важно для интерпретатора при исполнении PostScript-программы. Отметим, что при такие операторы, как "[" и "]" создают литеральные объекты, а операторы "{" и "}" – исполняемые. Другим атрибутом объекта является тип доступа (access) к нему. Имеется четыре типа доступа (расположены в списке по возрастанию ограничений): неограниченный (unlimited), только чтение (read only), только исполнение (execute-only) и без доступа (none).
Как правило, объект имеет неограниченный доступ. Это означает, что допускается применение к нему всех операторов, какие определены для работы с ним. Объекты с атрибутом "только чтение" не допускают модификацию своего значения и могут быть только считаны или выполнены. Аналогично, атрибут "только исполнение" определяет, что объект не может быть прочитан, а только исполнен интерпретатором. И наконец, объекты с атрибутом "без доступа" служат для каких-то внутренних целей, о которых я в данный момент ничего не знаю. Понятно, что они не используются программами напрямую. Для получения типа объекта служит оператор type.
Синтаксис: объект type à имя_типа
Результатом операции может быть одно из перечисленных имен:
arraytype booleantype dicttype
filetype fonttype integertype
marktype nametype nulltype
operatortype realtype savetype
stringtype
Следующие три оператора проверяют соответственно тип доступа объекта: wcheck - возвращает true, если объект имеет атрибут ulimited; xcheck – возвращает true, если объект исполняемый, и false, если литерал; rcheck – возвращает true, если объект "только для чтения".
Синтаксис у них одинаковый. Например, для wcheck он выглядит так:
объект wcheck à лог_значение
Операторы cvlit и cvx позволяют изменить атрибут объекта, находящегося в вершине стека операндов, с исполняемого на литеральный и наоборот.
Синтаксис: объект cvlit à объект
объект cvx à объект
Синтаксис: integer1 shift bitshift à integer2
Пример.
5 4 bitshift à 80
144 -3 bitshift à 56
Генерация случайных чисел
Синтаксис: число1 ceiling à число2
Примеры.
-1.9 ceiling à -1.0
5.3 ceiling à 5.0
49 ceiling à 49
В языке PostScript имеется три основных конструкции циклов: простой цикл, индексируемый цикл и условный цикл.
Простой цикл неявным образом уже использовался в примерах предыдущего занятия. Он реализуется с помощью оператора repeat, который берет из стека два операнда: счетчик цикла и повторяемую процедуру. Например, для очистки стека мы использовали следующий цикл:
4 {pop} repeat
Здесь всё достаточно прозрачно, непривычно, может быть, только то, что в качестве одного из аргументов выступает повторяемая процедура.
очистка стека - удаляет из стека все элементы 11 6 17 clear -> -
дублирует n верхних элементов стеков
Существует еще ряд более специального вида операторов, работающих со стеком, они будут рассмотрены по мере изложения.
Ряд принтеров, например Apple LaserWriter, позволяет интерактивно с ними взаимодействовать. Вот операторы для этого:
== удаляет элемент из вершины стека и отображает его на экране.
Pstack - печатает все содержимое стека, не изменяя его.
Pstack и == являются полиморфными операторами, так как они в качестве операндов принимают объекты многих типов.
число элементов в стеке
В языке поддерживаются две цветовые модели: HSB (тон-насыщенность-яркость) и RGB (красный-зеленый-голубой). В каждой из этих моделей можно задать любой цвет с помощью трёх числовых параметров. В более простой модели RGB цвет задаётся сочетанием интенсивности трёх основных цветов: красного, зеленого и голубого. Интенсивность цвета задаётся числом в диапазоне от 0 до 1, причём 0 означает полное отсутствие данного цвета, а 1 – его максимальную интенсивность. Если для всех трёх цветов заданы равные интенсивности, то в результате получится чистый серый цвет с градацией по всей шкале от белого (0, 0, 0) до черного (1, 1, 1). Напомню, что уровень серого цвета обычно устанавливается оператором setgray.
В HSB тон задаёт собственно цвет. Он определяется его расположением на цветовом круге: 0° -- чистый красный, 120° -- зелёный, 240° -- синий. Остальные цвета получаются из смешения двух соседних. (Так, 60° -- жёлтый, , 180° -- голубой, 300° -- фиолетовый.) Насыщенность – густота цвета заданного тона: 0 соответствует отсутствию цвета, а 1 – максимальной его насыщенности. Яркость – общая интенсивность цвета (содержание белого цвета в данном цвете): 0 соответствует чёрному цвету, а 1 – белому (максимальной интенсивности).
Цвет может быть задан с помощью соответствующих модели операторов setrgbcolor и sethsbcolor.
Синтаксис:
число1 cvi à целое_число2
строка cvi à целое_число2
Примеры.
17.83 cvi à 17
-17.83 cvi à -17
Синтаксис: оператор cvlit à литерал
строка cvn à имя
Пример.
Синтаксис: (abc) cvn à /abc
Синтаксис:
число1 cvr à real
строка cvi à real
Синтаксис:
число система_счисления строка cvrs à подстрока
Примеры.
/tmp 14 string def
99 10 temp cvrs à (99)
144 16 temp cvrs à (E0)
Если объект число, то возвращается его строковое представление. Для логических объектов возвращается строка со соловом true или false. Строку cvs просто копирует в другую строку. Если объект имя или оператор, cvs возвращает текстовое представление этого имени или оператора. Во всех других случаях возвращается текст --nostringval--.
Синтаксис: что-либо строка cvs à подстрока
Пример.
/newstr 10 string def
1996 4 add newstr cvs à (2000)
Синтаксис: что-либо cvx à что-либо
Логические операторы в PostScript работают как с целыми числами, так и с логическими. В первом случае операция выполняется над операндом поразрядно. Имеется четыре основных логических операции: and, or, not и xor (из которых, как известно, можно построить все остальные булевские функции). Для краткости ниже дан пример только для xor.
Эта группа операторов, представителем которой был exch добавляет, удаляет и изменяет порядок следования элементов в стеке.
дублирует в стеке его верхний элемент 8 dup -> 8 8
Для печати текста часто требуются различные операции по выравниванию слов по границам страницы, выравниванию промежутков между буквами (кернинг), чтобы напечатанный текст выглядел приятно. Для этой цели в PostScript имеется 4 варианта оператора show:
ashow - при печати строки добавляет после каждого символа заданный промежуток;
widthshow - при печати строки добавляет заданный промежуток после каждого появления некоторого символа (например после каждого пробела);
awidthshow - является комбинацией двух предыдущих операторов;
kshow - выполняет заданную процедуру между каждой парой символов в строке.
Текущий символ и символ, следующий за ним передаются этой процедуре как аргументы.
Так строка
{pop pop (-) show} (World) kshow
напечатает его с дефисом между каждой парой букв:
W-o-r-l-d
Оба символа удаляются из стека, так как данная прцедура их не использует. В основном оператор предназначен для кернинга, но может быть использован и в других целях.
Операторы clip и clippath мы рассмотрели на прошлом занятии. Теперь несколько углубим эту важную тему.
Оператор eoclip находит пересечение внутри текущей траектории отсечения с внутренней областью текущей траектории, чтобы создать новый, меньший текущий путь отсечения. Область внутри текущего пути определяется по правилу чётное-нечётное, тогда как область внутри текущего пути отсечения определяется правилом, использованным при создании данного пути отсечения.
За исключением указанных правил, действие оператора eoclip аналогично действию оператора clip.
Синтаксис: - eoclip à -
Оператор initclip замещает параметр текущей траектории отсечения в состоянии графической среды на траекторию отсечения, устанавливаемую для текущего графического устройства по умолчанию. Этот путь обычно соответствует границам максимально большой области для вывода изображения. Для устройств, ориентированных на постраничный вывод, его размерности устанавливаются оператором setpagedevice. Для экрана область отсечения, устанавливаемая оператором initclip, не очень хорошо определена.
Ситуаций, когда в PostScript-программе следует применять оператор initclip, не так много. Описание страницы, в которой применён этот оператор, обычно даёт некорректный результат, если оно встроено в другую, составную страницу.
Синтаксис: - initclip à -
Оператор eoviewclip (L2) аналогичен оператору viewclip за исключением того, что использует правило чётный-нечётный для определения области внутри пути отсечения.
Синтаксис: - eoviewclip à -
К сожалению, за одно занятие удаётся рассказать не так много, как хотелось бы, поэтому рекомендую посмотреть очень полезные примеры программ на PostScript из Голубой книги по адресу: http://www.fwi.uva.nl/~heederik/ps/bluebook/
Все данные, доступные PostScript-программам, существуют в виде объектов. Объекты делятся на простые, не имеющие внутренней структуры, и сложные (или составные). К последним относятся строки, массивы и словари.
Говоря о строках в PostScript, следует отметить, что в нём, как и в языке Си, есть возможность с помощью обратной косой черты и следующего за ним символа задавать специальные и управляющие символы. Вот ещё одна полезная таблица с такими комбинациями знаков.
\n новая строка
\r возврат каретки
\t табуляция
\b возврат на позицию
\f перевод формата
\\ обратная косая черта
\( левая скобка
\) правая скобка
\ddd символ с восьмеричным кодом ddd
Если за \ следует символ, не перечисленный выше, то и он, и обратная косая черта игнорируются. Следующие две строки одинаковы:
(Строка с символом перевода строки.
)а
(Строка с символом перевода строки.\n)
Ещё один тип данных, о котором мы почти не говорили, – словари. Словарь – это ассоциативная таблица, элементы которой – пары PostScript-объектов. Первый элемент пары называется ключом, а второй – значением.
Обычно в качестве ключей используются имена объектов, а в качестве значений – переменные и процедуры. В частности, шрифты в PostScript также задаются словарями: именам символов соответствуют процедуры рисования образов этих символов. Есть и другие примеры использования словарей. В языке есть операторы, которые ищут ключ и выбирают соответствующее ему значение, вставляют пару ключ--значение в словарь и выполняют некоторые другие действия.
Для работы со словарями в языке имеется специальный стек. Словарь, находящийся в вершине этого стека, называется текущим словарём. Обычно, встречая имя объекта в выполняемой программе, интерпретатор обращается с ним к текущему словарю. Если он не находит там это имя, он обращается к словарю, расположенному в стеке словарей вслед за текущим, и так далее, пока не будут просмотрены все словари в стеке.
В интерпретаторе имеется два встроенных словаря, называющихся systemdict и userdict (в PostScript Level 2 к ним добавился ещё один словарь – globaldict). Первый из них связывает (ассоциирует) имена всех операторов языка с их значениями (т. е. действиями, которые выполняются самим интерпретатором). Второй словарь предназначен для связи имён переменных среды с их значениями. Оба встроенных словаря находятся внизу стека (userdict над systemdict) и не могут быть из него удалены.
Синтаксис: число1 floor à число2
Примеры.
1.9 floor à 1.0
-3.7 floor à -4.0 <BR>
В PostScript не существует различия между графикой и текстом. Символ текста рассматривается как один из графических объектов, размещаемых на текущей странице. Поэтому для совмещения на ней текста и графики не требуется никаких специальных действий.
Графические операторы PostScript выполняют свои действия в пространстве пользователя, или, иначе говоря, в пользовательской системе координат. Как уже говорилось, это пространство независимо от какого-либо физического устройства и результат работы операторов PostScript при печати автоматически преобразуется в систему координат устройства. Однако иногда бывает удобно изменить действующую по умолчанию систему координат. Можно, например, перенести в другое место начало координат, изменить ориентацию осей и масштабы по ним.
Перенесение начала координат. Для этой цели служит оператор translate. Он берет из стека два числа, и перемещает пространство пользователя в точку с этими новыми координатами. Например строка:
150 180 translate
переместит их начало координат в точку (150, 180). После этого все позиции на текущей странице будут отмеряться от этой точки.
Пример.
Треугольник. Переместить 3 раза.
/treangl
0 0 moveto
90 0 lineto
x y lineto
closepath fill} def
treangl
200 250 translate
treangl
200 250 translate
treangl
showpage
Обратите внимание, что второй перенос системы координат осуществляется уже относительно новой системы координат, а не относительно исходной.
Оператор scale позволяет изменить размер единицы измерения по каждой из осей координат. Он берет из стека два аргумента - коэффициенты изменения масштаба по осям x и y, соответственно, и с их учетом изменяет размер системных единиц. Например строка:
2 2 scale
увеличит размер системной единицы вдвое, т.е. объект будет рисоваться вдвое большего размера, чем до выполнения этой команды.
Задание. Напечатать треугольники из предыдущего примера используя следующие размеры системной единицы:
а) по умолчанию;
б) 1.5, 2.5;
с) 1.75, 1.
Литературы по PostScript не так уж много. В основном это три руководства, изданных (и переиздаваемые) фирмой Adobe в издательстве Addison-Wesley Publishing.
PostScript Language Program Design. ISBN 0-201-14396-8, 256 pp., $24.95.
PostScript Language Reference Manual, Second Edition. ISBN 0-201-18127-4, 784 pp., $32.95.
PostScript Language Tutorial and Cookbook. ISBN 0-201-10179-3, 256 pp., $21.95.
Возможно вам окажутся полезными ещё несколько книг:
Programming the Display PostScript System with NEXTSTEP. ISBN 0-201-58135-3, 416 pp. $26.95.
Programming the Display PostScript System with X. ISBN 0-201-62203-3, 624 pp. $29.95.
Adobe Type 1 Font Format. ISBN 0-201-57044-0, 114 pp., $16.95.
Portable Document Format Reference Manual: The Official Guide to the File Format for Adobe Acrobat. ISBN 0-201-62628-4, 240 pp., $24.95
Кроме печатных книг по языку, существует ряд полезных публикаций на различных Web-узлах. Так, задав в поисковой системе строку "PostScript Level 2" AND "David Burch", вы найдете в Интернет весьма полезный справочник, составленный этим автором.
Каждый словарь шрифта содержит описание символов в соответствии с некоторой кодовой таблицей, в частности это может быть ASCII. Таким образом каждый символ имеет свой цифровой код -- число от 0 до 255. Кодовая таблица не является постоянной, ее можно изменять из приложения.
Коды символов можно использовать двумя способами:
- их можно с помощью оператора put вставлять в строку;
- или непосредственно использовать в строке в виде восьмеричных чисел.
Многие шрифты имеют символы не входящие в стандартную кодировку и кроме того, часто такие символы отсутствуют на клавиатуре. Чтобы посмотреть как кодируются символы того или иного шрифта, напишем программу, которая распечатывает кодовую таблицу любого заданного шрифта.
/Helvetica findfont 12 scalefont setfont
/cod 3 string def
/char 1 string def
/newline
{currentpoint 13 sub
exch pop LM
exch moveto }def
/prtnum % в стеке код
{cod cvs show}def
/prtchar %в стеке код
{char 3 - 1 0 roll put
char show}def
/prtall
{dup prtnum () show
prtchar newline} def
% основная программа.
/LM 72 def
LM 450 moveto
12 1 60 {prtall} for
/LM 144 def
LM 144 moveto
6 1 100 {prtall} for
showpage
Преобразование шрифта задается матрицей преобразования (трансформации), представляющей из себя массив из шести чисел. Они определяют, как координаты пространства пользователя должны быть трансформированы в позицию на текущей странице. Элементы этого массива определяют масштаб, ориентацию и позицию осей х и у.
Графическое состояние программы работает с текущей матрицей трансформирования, определяющей, как на текущей странице позиционируются все изображения.
Операторы translate, rotate и scale для модификации координат пространства пользователя изменяет соответствующие элементы этой матрицы.
Отдельная матрица преобразования ассоциируется с каждым шрифтом, определяя как символы этого шрифта должны печататься на текущей странице. Эта матрица шрифта может быть изменена непосредственно оператором makefont, который берет из стека словарь шрифта и шестиэлементный массив, а затем преобразует с помощью этого массива матрицу шрифта и помещает измененный словарь шрифта обратно в стек.
Чтобы изменить масштаб шрифта по х и по у, нужно задать соответственно значения чисел m и n в матрице
[m 0 0 n 0 0 ]
Так строки
/Helvetica findfont 6 scalefont
/Helvetica findfont [6 0 0 6 0 0] makefont
выполняют ровно одно и тоже: создают шрифт Helvetica размером 6 пунктов. Действие оператора makefont однако значительтно шире, чем у scalefont. Он позволяет как угодно сжимать и растягивать текст. Следующая прграмма из “Голубой книги” показывает технику работы с makefont.
/basefont /Helvetica findfont def
/LM 72 def
/newline
{currentpoint 13 sub
exch pop LM
exch moveto} def
% основная программа
LM 400 moveto
% обычная печать
basefont [12 0 0 12 0 0] makefont setfont
(Пример нормальной печати) show newline
% растянутый.
basefont [17 0 0 12 0 0] makefont setfont
(Растянутый шрифт) show newline
% сжатый
basefont [7 0 0 12 0 0] makefont setfont
(Сжатый шрифт) show newline
% наклонный
basefont [12 0 6.93 12 0 0] makefont
setfont
(Italic) show
showpage
<рис. файл p4_4.ps>
Программа печатает четыре строки, каждый раз преобразуя текущий шрифт, с помощью различных матриц шрифта. Во второй и третьей строке изменялся масштаб по горизонтали (Вы можете поэксперементировать, задавая различный масштаб и по вертикали, но не забудьте поменять константу в процедуре newline, чтобы строки не наползали одна на другую). Интересна последняя строка. Третье число в матрице 6.93 представляет собой результат умножения у на tg 30 градусов. Таким образом задан наклон шрифта.
Вы можете поэкспериментировать с матрицами преобразования, чтобы лучше почувствовать, что происходит с шрифтом.
Все эти преобразования пространства пользователя можно выполнить также с помощью операторов scale и setmatrix. Однако в отличие от makefont их действие распространяется на все, что печатается на текущей странице. Если нужно сжать, растянуть или наклонить текст, то следует пользоваться только makefont.
Эта секция состоит из комментариев типа %%DocumentFonts, %%Pages и %%BoundingBox.
%%EndProlog
конец секции пролога программы.
%%Page: метка порядковый_номер
где метка – текст с названием страницы, а порядковый_номер – номер страницы в многостраничном документе.
%%PageFonts: шрифт1 шрифт2 ...
задает список шрифтов, используемых для текущей страницы документа.
%%Trailer
отмечает конец тела программы и начало эпилога.
Напомню, что по способу представления в компьютере шрифты делятся на векторные и растровые. Каждый словарь шрифта в PostScript содержит описание вида входящих в данный шрифт символов. В большинстве шрифтов символы описываются контуром (представленным в виде векторов), который заполняется каким-либо цветом при печати конкретного символа. Растровые шрифты описывают символы как линии, которые должны быть начерчены или как битовую карту.
<картинка с контурами букв>
Контурное или линейное описания символа могут быть непосредственно использованы в операторе charpath. Вместо рисования траектории оператор charpath добавляет её к текущей пути. Это позволяет производить над результатом различные операции заполнения отсечения и т.д. Он берет из стека строку и логическое выражение и добавляет к текущему пути контур символа, который описан в данной строке. Логическое выражение определяет тип оставляемого контура т.е. что произойдёт, если траектория символа предназначена для штриховки, а не для заполнения или оконтуривания. Если значение операнда false, то charpath просто добавляет траекторию символа, которая точно отображает описание символа в словаре шрифта, к текущему пути (результат удобный только для штрихового заполнения). Если операнд true, то charpath применяет к траектории символа оператор strokepath и полученный результат можно использовать для заливки каким-либо цветом (но не для штриховки). Если все символы шрифта будут заливаться, то разницы не видно. Оператор charpath не работает с теми частями символа, которые определенны как изображения или маски не являющиеся траекториями.
Например:
(B) false charpath
(B) true charpath
< 2 картинки>
Следует учесть, что контуры некоторых шрифтов защищены. в реализации языка PostScript Level 1 это относится ко всем шрифтам, в PostScript Level 2 – только некоторых специальных шрифтов и не относится к обычным шрифтам Type 1 или Type 3. Если текущий шрифт защищён, использование charpath, чтобы получить их контуры, вызывает блокирование работы операторов pathforall и upath до тех пор пока контуры символов из такого шрифта остаются в текущей траектории.
Путь построенный с помощью charpath может быть вычерчен либо заполнен (залит).
Пример использования тривиальная рекламная виньетка с названием вашей фирмы. Для этого поэспериментируйте с текстом этой процедуры.
% Їа®жҐ¤гал
/Helvetica-Bold findfont
24 scalefont setfont
/oshow % б⥪Ґ (бва®Є )
{true charpath stroke} def
/CircleName
{30 30 360
{gsave
rotate 0 0 moveto
( PC Magazine) oshow
grestore
} for
} def
%
150 350 translate
.3 setlinewidth
CircleName
gsave 0.8 setgray fill grestore
stroke
showpage
<сюда вставить рис. после выполнения>
Для построения реального изображения одних отрезков прямых линий явно недостаточно. Поэтому в PostScript для построения нужных кривых, окружностей и дуг окружностей имеется ряд операторов. Во-первых, оператор arc. Он добавляет окружность к текущей траектории и требует наличия в стеке пяти аргументов:
- координат х, у центра окружности;
- радиуса;
- угла начала;
- угла конца дуги.
Угол строится против часовой стрелки:
100 100 42 30 110 arc
<рисунок 1 file R1.psc>
Аналогичный arc оператор arcn строит угол по часовой стрелке. Сравните:
100 100 42 30 110 arcn
<рисунок 2 file R2.psc>
Эти операторы ведут себя несколько иначе, если уже существует точка текущей траектории -- тогда дуга соединяется с ней прямой линией. Сравните:
newpath
150 200 60 30 150 arc stroke
<рисунок 3 file R3.psc>
и
newpath
150 200 moveto
150 200 60 30 150 arc stroke
<рисунок 4 file R4.psc>
Чтобы нарисовать окружность, нужно задать arc угол в 360 градусов, например:
150 200 60 0 360 arc
Задание 1. Используя оператор arc, нарисуйте произвольную ромашку с 4, 6 и 9 лепестками. Напишите процедуру, аргументом которой будет число лепестков.
Задание 2. Эллипсы можно получить, изменяя при рисовании окружности масштабы по осям координат. Напишите программу, в которой это используется.
Синтаксис: -- languagelevel à уровень
Уровень – это целое число, обозначающее уровень языка PostScript, поддерживаемый интерпретатором. Если он равен 2, то интерпретатором поддерживается язык PostScript Level 2. Если 1 или слова нет в словаре systemdict, то интерпретатор не поддерживает Level 2.
Результат операции сравнения или логической операции -- логическое значение true или false. Оператор if берет из стека логический объект и выполняемый массив. Если значение логического объекта true, то выполняются операции, записанные в этом массиве.
Пример.
/step 15 def
/rightmargin 450 def
/checkmargin
{currentpoint pop % оставляет в стеке х
rightmargin gt % >450
{ 0 step translate 0 0 moveto} if
} def
Процедура получает координату текущей точки и сравнивает её со значением правой границы рабочего поля. Если условие выполняется, то происходит перенос начала координат на следующую строку.
PostScript работает с одномерными массивами - (векторами), которые определяются как набор объектов ( возможно разного типа), заключенный в квадратные скобки. Так
[ (PC Magazine) 1991 54]
и
[ (Julia) 4 12 78]
массивы, причем первый элемент этих массивов - строка. (Такие структуры в других языках , кроме АПЛ, обычно называют записями). Операции внутри квадратных скобок выполняются по обычным правилам PostScript, так после вычисления
[(add) 10 5 6 mul sub]
получим массив из двух элементов.
Массив может быть также определен с помощью оператора array, который берет из стека число и создает массив такой длины.
8 array
Эта строка оставит в стеке массив из 8 элементов. Его элементы -- NULL-объекты.
Когда массив создается строкой типа
[1 2 3 8 ],
то квадратные скобки, используемые для его записи играют в PostScript большую роль, чем это кажется на первый взгляд. Открывающая (левая) квадратная скобка оставляет в стеке объект, называемый маркером (mark). После маркера интерпретатор просматривает строку программы дальше и помещает в стек все встречающиеся ему объекты до правой квадратной скобки. Эта скобка является оператором, создающим массив из хранящихся в стеке объектов: от вершины до маркера. При этом маркер удаляется из стека, а массив остаётся.
Массивы, строки и словари -- всё это примеры объектов сложных типов. Их значения хранятся PostScript отдельно от самого объекта (то есть PostScript работает в этом случае не со значением, а с указателем на него). Так операция dup над строкой дублирует объект, но не его значение, которое в этом случае разделяется двумя объектами. Массив в PostScript индексируются с нуля. Для работы с элементами массивов служат операторы put и get.
Оператор put берет из стека три аргумента: массив, индекс элемента в массиве и объект. Он помещает объект в массив в позицию, заданную индексом:
/MyArray 12 array def
MyArray 5 (Jerry) put]
У оператора get два аргумента: массив и индекс. Он возвращает в стеке элемент массива с заданным индексом. После выполнения строки
[0 1 2 3 4 5] 5 get
в вершине стека будет число 4.
Для работы с массивами также необходим оператор length, возвращающий длину массива (то есть число его элементов). Следующая программа распечатывает массив, находящийся в стеке.
/LeftM 60 def
/TmpString 40 string def
/Helvetica findfont 11 scalefont setfont /newln
{currentpoint 15 sub exch pop % y-15
LeftM exch moveto} def
/printarr % в стеке массив
{/arr exch def % поместить массив в переменную 0 1 arr length 1 sub % параметры цикла
{arr exch get % следующий элемент
TmpString cvs
show newln} for
} def
LeftM 400 moveto
[(Julia) % строка
15 % число
/SimplName % литерал
[8 3 4] % массив
{NewLN} % исполняемый массив
LeftM % переменная
]
printarr
showpage
Перед каждым выполнением цикла оператор for помещает в стек счетчик, который используется в качестве индекса в строке arr exch get. ( В этой строке берется не сам массив из стека, а ссылка на него по имени переменной, поэтому и делается exch.)
Результат работы программы
Julia
15
SimplName
--nostringval--
--nostringval--
Все виды скобок (круглые, квадратные, фигурные, угловые) и знак процента являются для PostScript специальными знаками. Остальные символы -- подмножество кода ASCII используются в программе без ограничений и называются регулярными символами.
Язык PostScript был разработан для получения графических изображений, для этого у него имеется большой набор операторов.
Рисование в PostScript начинается с конструирования пути на идеальной поверхности, называемой текущей страницей. Путь - набор прямых и кривых линий, определяющих область, которая будет заполнена, или траекторию, которая будет нарисована на текущей странице.
Конструируя путь, необходимо решить, что с ним делать: мы можем нарисовать линию заданной толщины или заполнить его, чтобы создать непрерывное изображение.
После того, как заполнение текущей страницы закончено, ее можно распечатать на физическом листе бумаги.
Начнем с простой задачи: нарисуем вертикальную линию длиной 5". Это выполнит следующая программа:
newpath
144 72 moveto
144 432 lineto
stroke
showpage
Разберем этот пример строка за строкой. Оператор newpath читает текущую страницу и объявляет, что начато рисование новой страницы. Конструирование пути начинается переносом воображаемого пера в заданную точку. Это перо при его переносах не оставляет "следа" на бумаге. Положение пера в каждый конкретный момент называется текущей точкой на текущем пути.
Оператор movedo переносит перо в точку, координаты которой заданы его операндами. он извлекает из стека два числа и рассматривает их как координаты х и у точки, которая становится текущей.
В системе координат, принятой в PostScript по умолчанию, начало координат находится в нижнем левом углу страницы. Координата х увеличивается вправо, а у - при движении вверх. Единица длины в этой системе равна 1/72 дюйма. Таким образом, оператор moveto переместит текущую точку на два дюйма вправо (144/78) и один дюйм вверх (72/72).
Оператор lineto добавит сегмент к текущему пути, нарисуя линию между текущей точкой и точкой, координаты которой заданы его операндами, в данном случае 144 и 432. Точка, заданная как операнд lineto становиться текущей точкой. Обратите внимание, что lineto в действительности не рисует ничего на текущей странице. Он просто добавляет сегмент линии к текущему пути. Позже эту линию можно будет нарисовать, но это не происходит автоматически.
Оператор stroke вызывает рисование сконструированного нами пути на текущей странице. Теперь этот путь становится видимой линией.
И, наконец, оператор showpage печатает текущую страницу (отправляет ее на печать).
Таким образом можно выделить 3 этапа построения:
1) Конструирование пути (newpath, moveto, lineto);
2) нанесение его на текущую страницу (stroke);
3) вывод текущей страницы (showpage).
Задание: Написать программу, которая строит квадрат со стороной 1 дюйм.
Отмечу, что здесь по сравнению с другими языками нет почти ничего нового. В PostScript файл определяется как конечная последовательность символов, заканчивающаяся маркером "конец файла". Нет разницы между файлом, хранящимся на диске, и файлом, получаемым по линии связи или генерируемым "на лету" каким-либо приложением. Различаются входные (input) и выходные (output) файлы. Входные файлы служат для интерпретатора PostScript источником исполняемых программ и они могут им читаться как последовательность символов. При этом входной файл может быть закрыт явно с помощью оператора closefile, либо неявно – при достижении маркера конца файла. Файл – это один из объектов языка. Объект такого типа создаётся с помощью оператора file. По существу это обычное открытие файла. Кстати, существует ограничение на число одновременно открытых файлов (зависит от ОС).
Синтаксис: имя_файла тип_доступа file à файл
Аргумент имя_файла должен соответствовать соглашениям операционной системы, в которой работает интерпретатор. В PostScript существуют предопределённые имена файлов, такие как %stdin и %stdout. Тип_доступа задаётся одной из букв:
'r' – входной файл (только чтение);
'w' – выходной файл (только запись).
Для удобства в языке есть несколько операторов чтения: read, readstring, readhexstring и readline.
Оператор read проверяет есть ли в файле ещё непрочитанные символы. Если нет (конец файла), закрывает файл и возвращает в стеке false. В противном случае читает из файла следующий символ, помещает его в стек, а затем, как признак успешной операции, помещает в стек true.
Синтаксис: файл read à байт true 'if not EOF
à false 'if EOF
Оператор readline читает из файла последовательность символов, ограниченную символом конца строки, и сохраняет их в аргументе строка (при этом сам терминатор строки туда не записывается). Если строка заполнена раньше, чем встретился символ новой строки, возникает ошибка, которая называется rangecheck. При успешном завершении операции чтения в стеке возвращается также true, иначе – false.
Синтаксис: файл строка readline à подстрока true 'if not EOF
à false 'if EOF
Так как изображение в PostScript часто кодируется как массив 16-ричных чисел и, если оно достаточно большое, его неудобно держать внутри программы, то считать его из файла поможет специальный оператор – readhexstring.
Он последовательно считывает 16-ричные цифры из файла проверяя их на диапазон 0-9, A-F. Происходит последовательное формирование из двух цифр одного байта и запоминание его в строке. При этом все символы типа пробелов, табуляций и возвратов каретки игнорируются. Чтение заканчивается, когда достигается конец файла. Ограничения на максимальную длину строки накладываются операционной системой. Синтаксис как и у оператора readline.
Такой же синтаксис имеет и оператор readstring. От readline он отличается только тем, что считанные символы рассматриваются как целые числа в диапазоне от 0 до 255. Особо рассматривается только символ новой строки.
Информация о числе байтов, доступных для чтения в файле, возвращается оператором bytesavaiable. Если результат равен -1, достигнут конец файла.
Синтаксис: файл bytesavaiable à число_байтов
Оператор currentfile возвращает объект типа file, из которого интерпретатор PostScript читал наиболее недавно.
Синтаксис: - currentfile à файл
Обычно возвращается стандартный файл ввода. Если не было чтения из какого-либо файла, то оно производится из файла программы. При этом указатель текущей позиции устанавливается после последнего считанного интерпретатором слова (оператора или элемента данных). Данное свойство используется для того, чтобы поместить в переменные текст или рисунок, находящиеся непосредственно в программе. Это демонстрирует пример, взятый из описания оператора:
/str 128 string def
currentfile str readline
строка, помещаемая в переменную текст
pop /text exch def
Оператор closefile разрывает связь между объектом типа file и соответствующим ему реальным файлом.
Синтаксис: файл closefile à -
Наконец, среди операторов ввода-вывода есть ещё ряд вспомогательных и очевидных операторов типа status, flush.
Этот несколько необычный для языков программирования тип объектов в PostScript означает одно из встроенных в язык действий, вызываемое при исполнении объекта. Операторы имеют имена, большинство из которых хранится в systemdict в качестве ключей, а значением является программа, реализующая семантику данного оператора.
Другие типы объектов (name, file, mark, null, save, fontID), которые не были рассмотрены до сих пор, мы изучим в разделах, с ними непосредственно связанных. Но вот что важно для объектов всех типов: каждый объект кроме типа и значения имеет один или несколько атрибутов, которые влияют на поведении объекта при его исполнении или когда над ним выполняются определённые операции (кроме случая, когда объект рассматривается только как данные).
Синтаксис: строка1 строка2 anchorsearch à
остаток совпавшая_часть true (если найдена)
строка1 false (если не найдена)
Примеры.
(edward) (ed) anchorsearch à (ward) (ed) true
(edward) (dw) anchorsearch à (edward) false
Более общую форму поиска даёт оператор search. Он позволяет найти первое вхождение строки2 в строку1. Результат поиска как и у anchorsearch возвращается в стеке операндов. При этом в вершине стека находится результат операции (true или false), а строка1 разбивается на 3 сегмента: часть строки до совпавшей подстроки (pre), совпавшая подстрока (match) и остаток строки (post).
Синтаксис: строка1 строка2 search à
post match pre true (если найдена)
строка1 false (если не найдена)
Примеры.
(edward) (ed) search à (ward) (ed) () true
(edward) (dw) search à (ard) (dw) (e) true
(edw) (W) search à (edw) false
В одном из писем читатель спросил, нет ли ещё каких-либо операторов отсечения, так как тех, что были описаны в уроках, ему недостаточно. Вот некоторые из них:
- reversepath à -
изменяет направление текущего пути;
- pathbox à llx lly urx ury
возвращает границы области текущего пути;
- currentpoint à x y
возвращает координаты текущей точки.
(Замечу, что страница целиком очищается с помощью не имеющего аргументов оператора erasepage, который закрашивает её серым цветом уровня 1, не изменяя состояния графической среды. Этот оператор выполняется также автоматически после оператора showpage.)
Синтаксис: - fill à -
Перед рисованием fill явным образом закрывает любые открытые подпути текущей траектории. Для её сохранения следует использовать последовательность операторов gsave fill grestore.
Для заливки области по правилу чётный-нечётный используется оператор eofill. В остальном он полностью идентичен оператору fill.
Прежде чем рассмотреть этот популярный во всех процедурных языках оператор, посмотрим, как записываются операции сравнения чисел. В PostScript, напоминаю, операторы сравнения следуют за сравниваемыми величинами.
Оператор Значение
eg = (равно)
gt > (больше)
ge >= (больше или равно)
ne <> (не равно)
lt < (меньше)
le <= (меньше или равно)
Позволяет выбрать в зависимости от условия выполнение одной или другой последовательности операторов. Его формат:
условие {op.1} {op>2} ifelse
Если результат выполнения условия true, выполняется последовательность {op.1}, иначе -- {op.2}.
Другие арифметические операторы:
div - деление. Второе число делится на число в вершине стека.
13 8 div -> 1.625
idiv - целочисленное деление.
25 3 idiv-> 8
mod - второе число делится на число в вершине стека, сохраняя остаток от деления.
7 5 mod-> 8
Операнды операторов mod и idiv должны быть целыми числами.
mul - перемножает два числа в вершине стека, помещая вместо них их произведение.
8 9 mul-> 72
neg - изменяет знак числа, находящегося в вершине стека.
-37 neg-> 37
(sgrt, exp, ceiling, sin)
Запись арифметических выражений.
Выражение 5+(8:2) на языке PostScript можно представить несколькими способами:
82 div 5 add
либо
5 8 2 div add
Чуть более сложный случай, выражение 9-(4*7), можно записать минимум двумя способами:
9 4 7 mul sub
4 7 mul 9 exch sub
Во втором способе введен новый оператор exch. Он меняет местами положение двух верхних чисел в вершине стека.
рисунок
Применение оператора exch вызвано тем, что sub вычитает число в вершине стека из следующего за ним, что без exch приводит к неверному порядку действий.
Создать пустой словарь ёмкостью N элементов можно с помощью оператора dict. Его синтаксис:
число_элементов dict à словарь
Этот пустой словарь помещается в стек операндов. Аргумент число_элементов не может быть отрицательным.
Оператор currentdict выполняет обратное действие – помещает копию текущего словаря в стек операндов.
Синтаксис: - currentdict à словарь
Оператор countdictstack пересчитывает число словарей, находящихся в стеке словарей, и помещает это число в стек операндов.
Синтаксис: - countdictstack à int
Оператор cleardictstack извлекает из стека все словари, кроме постоянных.
Синтаксис: - cleardictstack à -
Для замены или внесения нового элемента в словарь используется оператор put. На самом деле этот оператор полиморфен и позволяет также заменять элементы массивов и строк.
Синтаксис:
массив индекс значение put à -
словарь ключ значение put à -
строка индекс целое put à -
Если первый операнд массив или строка, то второй рассматривается как индекс, значение которого лежит в диапазоне от 0 до n-1 (где n – длина строки или массива). Элемент с этим индексом замещается третьим операндом.
Если первый операнд — массив, то второй — рассматривается как ключ и в словаре сохраняется пара ключ--значение, если данный ключ не будет найден, либо замещается только значение, если пара с таким ключом уже существует. Конечно, при создании нового входа в словарь интерпретатор проверяет наличие там свободного места и выдаёт сообщение об ошибке dictfull, если число входов уже исчерпано.
Пример.
/mydict 10 dict def
mydict /A 65 put
Обратное действие выполняет оператор get. С его помощью можно получить значение элемента массива, строки или по ключу найти соответствующее значение в словаре.
Синтаксис:
массив индекс put à значение
словарь ключ put à значение
строка индекс put à целое
Пример.
/abc [1 2 3] def
currentdict /abc get à [1 2 3]
Со словарём очень интересно работает также оператор forall. Ранее его действие рассматривалось только по отношению к массиву, но он, как и два предыдущих оператора, работает и со словарями, и со строками.
Синтаксис:
массив proc forall à -
словарь proc forall à -
строка proc forall à -
Если первый операнд — словарь, то forall помещает ключ и значение в стек операндов и выполняет заданную процедуру (proc) над каждой парой ключ--значение в словаре. Если процедура пустая "{}", то таким образом все пары из словаря просто переписываются в стек операндов.
Операторы length, put, get и forall работают как с массивами, так и со строками и словарем. Так length -- возвращает длину строки, массива или число пар ключ--значение в словаре.
Еще два оператора, aload и astore облегчают загрузку и сохранение сразу всего массива. Так оператор aload берет в качестве аргумента массив, заносит в стек по очереди все его элементы, а затем заносит туда сам массив. Так строка
[1 2 3] aload
оставит в стеке:
1 2 3 [1 2 3]
оператор astore выполняет обратную функцию.
1 2 3 3 array astore
создаст массив
[1 2 3]
В языке PostScript в операторах рисования важно знать когда точка считается внутренней по отношению к текущей траектории (отсечению), а когда – внешней. Есть два правила определения внутренней точки: чётный-нечётный и ненулевого поворота (on-zero winding). Оба правила основываются на подсчете пересечений лучей из проверяемой точки с текущей траекторией.
Метод ненулевого поворота заключается в следующем: из проверяемой точки по всем направлениям рисуются лучи, а затем анализируются места пересечения с сегментом траектории. Начиная со счётчика равного нулю мы добавляем к нему единицу, если луч пересекает траекторию слева направо, вычитаем единицы, если он пересекает её справа налево. Если счётчик равен нулю, точка внешняя, иначе – внутренняя. Правило не определяет, что происходит в случае, если луч проходит по касательной или перпендикулярно к сегменту.
Правило чётный-нечётный отличается от предыдущего тем, что подсчитывается просто число пересечений лучом сегментов траектории. Если число чётное, точка внутри области. Если нечётное – внешняя.
Для простых фигур результат применения каждого из правил совпадает. Различие проявляется на более сложных фигурах.
Одной из причин, вызвавшей появление и расцвет языка PostScript является необходимость выводить текст и изображения на растровые внешние устройства: матричные, струйные и лазерные принтеры, а также экраны мониторов. Основное свойство таких устройств заключается в том, что изображение на них строится из массива прямоугольных элементов, называемых пикселами (от picture element - элемент изображения). Каждый пиксел имеет в этом массиве свой адрес - номер строки и номер столбца, где он расположен, а также цвет: у обычных матричных принтеров пикселы могут быть либо черного цвета, либо белого (в этом случае их часто называют точками); у лазерных принтеров пикселы имеют до 256 градаций серого цвета, у цветных мониторов - до сотен тысяч цветов. Устанавливая определенные пикселы в нужные цвета, мы получаем на экране текст и графические изображения.
Так как у каждого растрового устройства пикселы имеют физические размеры, зависящие, например, от размера печатающих иголок матричного принтера или сетки на экране монитора, то число элементов изображения на единицу длины (обычно дюйм) называется разрешением растрового выводного устройства. В зависимости от этой характеристики устройства делятся на устройства с низким, средним и высоким разрешением. Для лазерных принтеров это соответственно до 300, 300-600 и более 600 dpi (точек на дюйм). Для каждого типа устройств границы этих классов свои, так для 14" мониторов разрешение более 50 dpi будет уже высоким. Чем выше разрешение, тем лучше качество изображения.
PostScript-устройство (принтер, монитор) -- это устройство, в котором имеется интерпретатор языка PostScript. Интерпретатор PostScript принимает из компьютера текстовый файл с описанием страницы и преобразует его в растровую форму, которая и выводится на печать или на экран. (С этим и связана близкая к языку Форт структура PostScript -- она обеспечивает наименьший размер интерпретатора). Во время преобразования описания интерпретатор выполняет различные действия, зависящие от типа устройства. Так если на черно-белое печатающее устройство выводится полутоновое изображение, то интерпретатор PostScript этого устройство выполняет разбиение полутоновых областей на зоны с определенным уровнем серого цвета и заполняет каждую зону черными точками с плотностью, зависящей от этого уровня, что создает иллюзию полутонов на результирующем изображении.
Передача описания страницы по многим причинам более выгодна, чем передача сразу всего массива составляющих страницу пикселов (растрового образа страницы). Во-первых, описание во много раз компактнее даже сильно сжатого изображения. Во-вторых, процесс подготовки печатной страницы требует значительного времени: если пересылается описание, то подготовкой к печати занимается процессор принтера или дисплейный процессор, что освобождает процессор персонального компьютера (ПК) для выполнения другой работы и тем самым повышает его производительность. И наконец, самое важное преимущество - это независимость описания от типа устройства.
(Однако с интерпретатором языка PostScript можно работать и на самом ПК как работаем мы с Бейсиком или любым другим языком. Есть различные реализации интерпретаторов PostScript, но лучше воспользоваться общедоступной программой Gnostscript, работающей как под DOS, так и в Windows. Её можно, в частности, поискать в Internet. )
Чтобы обеспечить независимость описания страницы от всего разнообразия внешних растровых устройств в языке PostScript введено понятие текущей страницы.
Текущая страница - "идеальная" страница в памяти, на которой рисует PostScript. Она не зависит от физических характеристик принтера, на который страница будет вводиться. В начале работы программы это совершенно чистая страница. Когда текущая страница полностью описана, она посылается на принтер, который распечатывает ее с таким качеством, которое способен обеспечить.
Текущий путь (current path) - это набор соединенных между собой отдельных точек, линий, кривых, которые вместе описывают фигуры и их положение. На текущий путь не накладывается никаких ограничений (он может пересекать сам себя и т. д.) Элементы текущего пути задаются их позициями на текущей странице.
Текущий путь обрезки (Current clipping path) -- это границы области, в которой может быть нарисовано изображение.
/ed 47 def
Косая черта перед именем переменной показывает, что интерпретатору следует поместить это имя в стек как литерал и не пытаться сразу же искать его в словаре. Вслед за именем в стек заносится число 47. И наконец def берет оба эти объекта из стека и помещает их в текущий словарь. Второй элемент стека (ed) становится ключом, с которым ассоциировано значение первого элемента (47). На первый взгляд это больше похоже на определение константы, чем переменной. Однако определенное с помощью def значение переменной может быть изменено либо новым оператором def, либо другими операторами, например:
/ed 52 def
Посмотрим на примере, как PostScript работает с новой переменной. Если дальше в программе появится строка:
13 ed add
то интерпретатор сделает следующее:
1) поместит число 13 в стек;
2) найдет в стеке словарей значение для ключа ed и поместит его в стек;
3) сложит два числа из вершины стека, заменив их полученной суммой.
Следующий оператор умножает значение переменной ed на 5:
/ed ed 5 mul def
Задание. Используя приведенные выше правила, определите содержимое стека в каждый момент выполнения этой строки.
удаляет из стека его верхний элемент 31 4 pop -> 31
Операции над данными в PostScript требуют, чтобы их операнды сначала были помещены в стек. Такой стиль программирования, при котором операнды задаются до операции над ними (оператора) называется постфиксной нотацией. Так запись операции сложения двух чисел, допустим 4+5, в PostScript будет выглядеть так:
4 5 add
Шрифт - это набор символов, имеющих единый дизайн. Дизайн конкретного шрифта называется гарнитурой. Набор гарнитур, разработанных для совместного использования, называется семейством гарнитур. Наиболее популярные гарнитуры: Таймс, Курьер, Журнальная и др.
Конкретный PostScript-шрифт является реализацией начертания некоторого семейства гарнитур. PostScript-шрифты относятся к классу векторных и, следовательно, масштабируемых шрифтов. Существующие методы описания векторных шрифтов позволяют автоматически менять размер шрифта (кегель) с минимальными искажениями его начертания при преобразовании размера.
Чтобы задать шрифт, нужно выполнить следующие действия:
- найти описание шрифта в словаре шрифтов. Это описание позволяет построить контуры каждого отдельного символа. Подробнее об этом словаре будет рассказано несколько позже;
- отмасштабировать шрифт до нужного размера. Его размер задается минимальным расстоянием по вертикали между строками текста, необходимым, чтобы эти строки не накладывались одна на другую, например обычный шрифт часто задается высотой в 12 пунктов (напомним, что 1 пункт = 1/72 дюйма);
- установить отмасштабированный шрифт в качестве текущего шрифта, которым и будет печататься текст.
Чтобы посмотреть, как это работает, давайте напечатаем слова PC Week шрифтом Helvetica размером 14 пунктов.
/Helvetica findfont
14 scalefont
setfont
100 150 moveto
(PC Week) show
showpage
В этом фрагменте используется ряд новых операторов. В первой строке в стек сначала помещается литерал с именем шрифта, а затем вызывается оператор findfont. Этот оператор ищет это имя в словаре с названием FontDictionary и помещает соответствующий словарь шрифта в стек. Данный словарь содержит описания образов символов для шрифта размером в один пункт. Нужный размер устанавливается с помощью оператора scalefont, который берет из стека число и словарь шрифта и возвращает в стек словарь шрифта модифицированный под нужный размер. Так, в нашем примере строка
14 scalefont
вернет в стек словарь для шрифта Helvetica с кеглем 14 пунктов. Наконец, оператор setfont переводит словарь шрифта из стека в текущий шрифт, который и будет использован для печати текста. Чтобы что-либо напечатать, нужно установить местоположение текущей точки, поместить в стек заключенную в круглые скобки строку и вызвать оператор show. Этот оператор "печатает" строку из стека на текущей странице, начиная с текущей точки. По мере печати текущая точка перемещается в конец строки.
Изменение размера шрифта при печати
Следующий пример показывает, как во время печати текста можно менять шрифт. Определим процедуру устанавливающую шрифт нужного размера.
/newsize % в стеке размер
{ scalefont setfont} def
/ getfont
{ Helvetica findfont} def
getfont 8 newsize
72 250 moveto (example) show
getfont 10 newsize
72 275 moveto (example) show
getfont 12 newsize
72 300 moveto (example) show
showpage
Эта программа напечатает три раза слово example шрифтом разного размера. Процедуры newsize и getfont можно объединить, если учесть порядок следования аргументов в стеке. (Понятно, что в нем хранится не сам словарь шрифта непосредственно, а ссылка на него).
/scaleHelv %в стеке размер
{/ Helvetica findfont
exch scalefont % кегель в стеке
setfont } def
Теперь запись строки программы станет еще компактней:
6 scaleHelv
Оператор rotate позволяет повернуть систему координат на заданный угол. Он берет из стека число, показывающее угол поворота осей в градусах (угол отсчитывается от вертикальной оси против часовой стрелки) и выполняет разворот. Снова нарисует наши три треугольника, но с поворотом осей.
/neworigin
{250 150 translate 60 rotate} def
/treangl
0 0 moveto
90 0 lineto
x y lineto
closepath fill} def
treangl
neworigin
treangl
neworigin
treangl
showpage
Синтаксис: строка print à --
Следующая встроенная процедура == носит название “два знака равно” (twoequals). Она введена в язык для удобства отладки.
Синтаксис: что-либо == à--
== извлекает объект из стека операндов, создаёт его текстовое представление, близкое по форме к синтаксиссу PostScript, помещает вслед за ним знак перевода строки и записывает результат на стандартное устройство вывода. Имя == не является специальным: в программе на PostScript оно может быть разделено “белыми” пробелами или специальными символами, как и имя составленное из букв.
Встроенные функции
Некоторые встроенные функции были рассмотрены на первом занятии. Сейчас мы добавим к ним ещё десяток, связанных с работой с числами.
/inch {72 mul} def
Любое появление слова inch после этой строки заставит интерпретатор поместить в стек число 72, умножить его на число лежащее в стеке ниже его и поместить в стек вместо двух этих чисел результат их произведения, таким образом следующие две строки эквивалентны:
3 72 mul
3 inch
Как известно, использование процедур сокращает длину программы, улучшает ее читабельность, а главное дает возможность расширить средства языка за счет введения в него новых слов. Таким образом обычный процедурный язык программирования (3GL) можно поднять до сверхвысокого уровня.
При определении процедуры ничего не было сказано о передаче параметров. Для языка ориентированного на работу со стеком естественный способ передачи параметров -- размещение их в стеке. Перепишем программу рисования двух перекрывающихся областей:
/inch {72 mul} def
/box % в стеке: x y
{ newpath moveto
1 inch 0 rlineto
0 1 inch rlineto
-1 inch 0 rlineto
closepath } def
/fillgray % в стеке: уровень серого цвета
{setgray fill} def
% Основная программа
2 inch 3 inch box
.9 fillgray
2.5 inch 3.5 inch box
.7 fillgray
showpage
В такой записи программу уже значительно проще изменять и она более самодокументирована, чем ее первый вариант. За это приходиться платить некоторым увеличением времени выполнения, так как интерпретатору приходится больше работать со словарями, однако быстродействие встроенных микропроцессоров, управляющих внешними устройствами (так в лазерных принтерах обычно используется RISC-процессор Intel 960) настолько велико, что эти микросекунды обычно никого не волнуют.
Словарь (dictionary) - это таблица, которая связывает между собой пары объектов. Например, словарь терминов по мультимедиа связывает слова с их толкованиями. PostScript-словарь связывает объект, именуемый ключом, с другим объектом - значением этого ключа. Интерпретатор языка PostScript может искать по ключу в словаре и получать его значение, если такой ключ есть в таблице.
PostScript всегда имеет два словаря: системный и пользовательский. Системный словарь объединяет имя каждого встроенного в язык оператора с соответствующим ему действием. Словарь пользователя ассоциирует имена с процедурами и переменными, определенными в программе.
Когда интерпретатор встречает имя он сначала просматривает словарь пользователя, а затем системный. Если имя в словаре найдено, то выполняются соответствующие ему действия: либо объект помещается в стек, либо выполняются некоторый набор операторов. Если имя не найдено в словаре (например на стадии отладки программы), то выдается сообщение об ошибке.
Обсуждаемые выше словари хранятся в стеке словарей: словарь пользователя в верху стека, системный -- внизу. Таким образом слово ищется начиная с вершины стека. Программа может создать новые словари, которые будут размещены в вершине стека словарей. Словарь, находящийся в вершине стека и, следовательно, просматриваемый первым, называется текущим словарем.
Синтаксис: -- product à строка
Язык PostScript не был бы так популярен, если бы он не предоставлял богатейшие возможности вывода на печать текстов. Текстовые данные представлены в PostScript объектами типа string (строка). Строка может содержать любую последовательность символов, заключенную в круглые скобки. Строка может быть помещена в стек, присвоена переменной или напечатана. Однако перед тем как строка будет помещена на текущей странице интерпретатору PostScript необходимо указать какую гарнитуру и размер шрифта использовать при печати.
Синтаксис: -- rand à int
Синтаксис: -- realtime à int
Синтаксис: -- revision à - int
Печать
вращает элементы стека, из стека извлекаются два числа. Верхнее говорит сколько раз и в каком направлении вращать элементы стека, второе - сколько элементов вращать.
7 8 9 3 1 roll -> 9 7 8
7 8 9 3 - 1 roll -> 8 9 7
Синтаксис: число1 round à число2
Примеры.
-1.9 round à -2.0
8.5 round à 9.0
-8.5 round à -7.0
Index</A><BR>
Синтаксис: -- rrand à int
Время
Пересекающиеся линии часто бывает необходимо соединить плавной кривой. В PostScript для этого существует удобный оператор arcto. В качестве операндов ему в стеке задаются координаты двух точек и радиус, т. е.:
x1 y1 x2 y2 r arcto
Он рисует сегмент прямой линии от текущей точки по направлению к точке х1, у1, а затем дугу до её пересечения со второй прямой.
<рисунок 4 R4.psc на бумаге>
Arcto возвращает в стеке координаты начала и конца дуги. Если они не нужны, то эти числа следует удалить из стека:
4 {pop} repeat
Используя оператор arcto, нарисуем какую-нибудь карточку:
/clearstack {4{ pop} repeat} def
200 300 translate
0 20 moveto
0 72 108 72 20 arcto clearstack
108 72 108 0 20 arcto clearstack
108 0 0 0 20 arcto clearstack
0 0 0 72 20 arcto clearstack
fill
0.5 setgray
80 45 20 0 360 arc fill
/Helvetica findfont 25 scalefont setfont
30 50 moveto
(My Card) show
showpage
Позиция на текущей PostScript-странице описывается в системе координат пользователя (или в пространстве пользователя), которая не зависит от пространства устройства. Координаты PostScript-программе перед печатью текущей страницы автоматически преобразуются из пространства пользователя в пространство устройства. Пространство пользователя таким образом представляет систему координат, внутри которой страница может быть описана независимо от конкретной машины, где эта страница будет напечатана.
Пространство пользователя может быть изменено тремя способами:
1) начало его системы координат может быть перенесено в любую точку пространства пользователя;
2) оси могут быть повернуты в любом направлении;
3) масштаб по каждой оси может быть произвольно изменен, т. е. может быть задано любое линейное преобразование из пространства пользователя в пространство устройства.
Язык PostScript не определяет общую структуру PostScript-программы, однако существуют некоторые соглашения, облегчающие её структуризацию. Для записи информации о программе используются комментарии специального вида. Такой комментарий занимает строку целиком и начинается не с одного знака процента, а с двух. Специальные комментарии делятся на три группы: заголовочные комментарии (header comments), комментарии тела программы (body comments) и комментарии эпилога(trailer comments).
Заголовочные комментарии предшествуют тексту программы. Комментарии тела программы служат для разделения разных частей описания страницы. Комментарии эпилога следуют после текста программы и дают о ней дополнительную информацию.
До сих пор мы работали с графикой явным образом, меняя с помощью операторов ее состояние. Состояние графики - это набор данных, которые описывают, как операторы будут влиять на текущую страницу. Пара взаимодополняющих операторов, gsave и grestore, позволяют сохранить текущее состояние графики, а затем в нужный момент восстановить его. Это может потребоваться до и после использования оператора fill, который, как вы помните, очищает текущую траекторию. Если нужно продолжить рисование из какой-либо точки заполняемой оттенком серого фигуры, то удобно просто восстановить состояние графики , сохраненное до выполнения fill. Пример вы легко придумаете сами.
Оператор gsave сохраняет копию текущего состояния графики в стеке состояния графики. Этот стек может хранить до 32-х состояний графики, включая текущее состояние.
Оператор grestore восстанавливает состояние графики, сохраненное в стеке самым последним. Все характеристики текущего графического состояния, включая текущий путь уровень серого цвета, ширину линии и систему пользовательских координат возвращаются в состояние, в котором они были перед выполнением оператора gsave.
Стек операндов - содержит собственно объекты PostScript и результаты действий над ними. Операторы PostScript получают операнды только через стек.
Элементы данных в языке PostScript называются объектами (числа, массивы, строки, символы). Над объектами можно производить различные действия, но если в других языках объекты помещаются в переменные и адресуются указанием имени переменной, то PostScript работает с данными напрямую, используя механизм стека.
Примеры записи целых чисел: 345 -87 38554 0 +57
Если величина числа превышает предел для представления целых чисел, оно автоматически конвертируется интерпретатором в число типа real.
Примеры записи действительных чисел:
-2.0 12.3 2E-5 0.0 345.6e8 -.025
Беззнаковые целые числа могут быть записаны в любой из 35 систем счисления с использование префикса в виде:
база#число
где база - основание системы счисления, десятичное целое число от 2 до 36;
число - представление числа в системе в указанной префиксом системе счисления. Цифры в системах счисления по основанию больше 10 представляются буквами латинского алфавита от A до Z.
Например: 16#cb2e 2#11001011 8#377
Строка - это последовательность символов, заключенная в круглые скобки.
В графическом состоянии PostScript имеется траектория отсечения
(clipping path), представляющая собой границы области на текущей странице, в которой изображения могут быть нарисованы. Первоначально этот путь совпадал с углами бумаги, используемой принтером. Текущая траектория отсечения может быть изменена с помощью оператора clip. Этот оператор делает текущую траекторию траекторией отсечения. Все последующие "рисующие" операторы будут отсекаться, если изображение выходит за границы траектории отсечения.
Например, следующая программа конструирует траекторию в виде треугольника и делает его траекторией отсечения. Затем она рисует прямоугольную сетку и после печати мы видим, что осталось только та часть сетки, которая попала в этот прямоугольник.
/triangle
/inch {72 mul} def
{newpath
0 0 moveto
2 inch 0 lineto
1 inch 2.8 inch lineto
closepath} def
/vgrid
{newpath
0 9 2 inch
{0 moveto
0 3 inch rlineto} for
stroke} def
/hgrid
{newpath
0 10 2.8 inch
{0 exch moveto
2 inch 0 rlineto} for
stroke} def
% main program
200 300 translate
triangle clip
vgrid
hgrid
showpage
<сюда вставить после выполнения>
В качестве отсекающих границ может быть использован любая траектория, включая и след символа, оставляемый оператором сharpath.
Синтаксис: число1 truncate à число2
Примеры.
1.9 truncate à 1.0
-3.4 truncate à -3.0 <BR>
Эта фраза замечательна тем, что мы с детства получаем представление о рекурсии. PostScript поддерживает рекурсивный вызов процедур, т. е. когда процедура вызывает сама себя. Классический пример -- вычисление факториала:
/factorial % в стеке n
{dup 1 gt
{ dup 1 sub factorial mul} if
} def
% вызов
5 factorial
cvs show
Новый оператор cvs преобразует число из вершины стека и помещает его в заданную строку. Дело в том, что оператор show может печатать только строки. Кроме чисел, cvs преобразует и логические величины -- они заменяются в зависимости от значения словами true или false. Вот пример процедуры, печатающей целое число из стека:
/printint
{( ) cvs show} def % строка первоначально содержит 3 пробела
Оператор string создает строку длиной n. Определение строковой переменной выглядит так:
/nstr 7 string def
где 7 -- длина строки (знаков).
Рекурсивный вызов процедур даёт возможность рисовать фрактальные картинки, но это мы попробуем сделать на следующем занятии, когда изучим конструкции циклов.
Начать это занятие, наверное, нужно с извинений. В тексте предыдущего урока (см. №12/1996) по техническим причинам во всех строчках с описанием синтаксиса операторов PostScript вместо правой стрелки (à), показывающей результат операции, напечатан символ “n”. Сделайте, пожалуйста, авторучкой замену.
Синтаксис: -- usertime à int
Введем понятие выполняемого массива. Это более формальное название объекта, который ранее был назван процедурой.
Какая разница для PostScript между строками
12 5 sub
и
{ 12 5 sub} ?
В первом случае числа 12 и 5 будут помещены в стек и будет выполнена операция вычитания, а во втором -- эти числа и оператор sub будут помещены в массив, который затем будет занесен в стек. Выполняемому массиву может предшествовать имя, задаваемое в виде литерала, а закрывать его может оператор def, который ассоциирует его с именем в текущем словаре.
Выполняемый массив может использоваться также в некоторых управляющих операторах, таких как repeat. В этом случае выполняемый массив содержит операции, которые будут иметь место, когда выполнятся условия для условного оператора.
Синтаксис: -- version à - версия
Виртуальной памятью (обозначается VM) называется область памяти, в которой хранятся значения составных объектов. В некоторых реализациях PostScript может сохранять VM в файле в конце сеанса и восстанавливать её в начале следующего. Сохранить и восстановить текущее состояние VM во время выполнения программы можно также с помощью операторов save и restore, а проверить состояние VM – с помощью оператора vmstatus.
На этом заканчивается наш вводный курс в язык PostScript. Мы почти полностью прошли PostScript Level 1 и чуть-чуть коснулись L2. Как всегда, в конце работы видно, что её нужно было делать совсем не так. Конечно же, к седьмому уроку автор уже сам почти всё понял ;).
С Эдуардом Пройдаковым, главным редактором еженедельника PC Week/RE, можно связаться по адресу: chief@pcweek.ru.
Так как в России наиболее широко для издательской подготовки текстов и даже для вёрстки используется Word для Windows, то следующей вопрос, который требует пояснения, – как встроить программу на PostScript в документ Word. Дело в том, что Word имеет собственный формат файлов, а программа на PostScript – это обычный ASCII-текст. Разработчики решили эту задачу просто: они оставили для таких случаев лазейку, которая называется поле print. Напомню, что полями в Word называются специальные команды редактора, заключённые в фигурные скобки. Поле print предназначено для того, чтобы выводить символы непосредственно на принтер (например, команды прямого управления принтером, команды на языке PCL и, конечно, PostSript-программы). Формат поля:
{print \p Size “текст”}
Ключ \p указывает, что в поле текст будет записана PostSript-программа. Операторы PostScript, заданные в этом поле, могут работать только в окне рисования, определённом атрибутом Size, значения которого приведены в таблице.
Аргумент | Значение |
page | Рисунок на всей текущей странице (по умолчанию) |
para | В пределах абзаца (высотой не менее дюйма), содержащего поле print |
pic | Рисунок располагается после поля print и до конца абзаца, содержащего это поле |
row | Рисунок в текущей строке таблицы |
cell | Рисунок в текущем элементе таблицы |
Dict | Используется для создания определений и процедур на PostScript, которые будут выполнены позже на той же самой странице. Поэтому dict не следует использовать для рисования. |
Так как текст и графика документа Word печатаются на той же PostScript-странице, что и результат PostScript-программы, не следует использовать операторы, которые изменяют или сбрасывают среду PostScript, а именно, избегайте операторов: banddevice, copypage, framedevice, grestoreall, initgraphics, initmatrix, nulldevice, renderbands и showpage.
При работе с PostScript в Word вам доступны переменные, которые я свёл в следующую таблицу. Значения, представленные этими переменными, даны в пунктах.
Size | Переменная | Описание |
Для всех аргументов | wp$x
wp$y wp$page wp$fpage wp$date wp$time wp$box |
Ширина прямоугольника рисования для заданного аргумента Size
Высота прямоугольника рисования для заданного аргумента Size Текущий номер страницы Отформатированный номер страницы (строка) Текущая дата (строка) Текущая дата (строка) Путь, содержащий прямоугольник рисования |
page, para | wp$top
wp$bottom wp$left wp$right |
Верхняя граница (page); расстояние до (para)
нижняя граница (page); расстояние после (para) Левая граница (page); левый отступ (para) Правая граница (page); правый отступ (para) |
page | wp$col
wp$colx wp$colxb |
Число столбцов на странице. Это число может различаться в зависимости от секции документа, в которой появилось поле с PostScript-операторами
Ширина каждого столбца Расстояние между столбцами |
para | wp$first
wp$style |
Отступ до первой строки
Стиль |
Пример.
{print \p page "/Times-Roman findfont strsize scalefont 0.8 setgray" }
Оператор index удаляет неотрицательное целое число n из стека операндов, отсчитывает n-й элемент от вершины стека и помещает копию этого элемента в стек. Это очень напоминает выборку элемента массива. При этом первый элемент в стеке имеет индекс 0. Вместе с операторами copy, dup и roll он позволяет свободно манипулировать содержимым стека операндов.
Синтаксис: an ... a0 n index à an ... a0 an
где an ... a0 – элементы стека операндов.
Пример.
Обозначим буквами содержимое стека, тогда:
A D G 0 index à A D G G
A D G J F 4 index à A D G J F A
Оператор clear извлекает все объекты из стека операндов и уничтожает их.
Синтаксис: a1 ... an clear à -
Оператор count пересчитывает число элементов в стеке операндов и возвращает его в вершине стека.
Синтаксис: a1 ... an count a1 ... an n
Примеры.
clear count -à 0
clear 1 2 3 count à 1 2 3 3
Оператор countexecstack считает число объектов в стеке исполнения и помещает это число в стек операндов.
Синтаксис:- countexecstack à int
Оператор counttomark считает число любых объектов в стеке операндов начиная с вершины стека и до первого маркера (не включая его самого).
Синтаксис: mark ob1 ... obn counttomark à mark ob1 ... obn n
Пример.
1 mark 2 3 counttomark à 1 mark 2 3 2
Оператор cleartomark извлекает любые объекты из стека операндов, пока не будет достигнут маркер, который также удаляется из стека.
Синтаксис: mark ob1 ... obn cleartomark à -
Синтаксис:
bool1 bool2 xor à bool3
int1 int2 xor à int3
Пример.
true false xor à true
Операторы сравнения
ge – больше или равно.
Синтаксис:
число1 число2 ge à результат_сравнения
строка1 строка2 ge à результат_сравнения
извлекает два объекта из стека операндов и помещает в него значение true, если первый операнд больше или равен второму. Строки сравниваются посимвольно.
Пример.
8.2 8.1 ge à true
Аналогично работают и другие операторы сравнения:
gt – больше чем
eq – равно
ne – не равно
le – меньше равно
lt – меньше чем.
Некоторые из этих комментариев могут помещаться в конце программы по усмотрению программиста или приложения, генерирующего PostScript-файл.
%%DocumentFonts: шрифт1 шрифт2 ...
где шрифт1 шрифт2 – имена PostScript-шрифтов, используемых в документе. Данная информация может использоваться некоторыми утилитами, загружающими шрифты в принтер до печати документа. Допускается указывать (atend), означающее присутствие, ожидание или что-то в этом роде.
%%Title: текст
задаёт заголовок документа. текст – строка заголовка.
%%Creator: имя_создателя
содержит имя программиста (или программы), породившего данный текст.
%%CreationDate: дата_и_время_создания
%%For: текст
указывает имя персоны, для которой был создан документ. Если комментарий %%For пропущен, подразумевается автор документа, указанный в %%Creator.
%%Pages: страниц
число страниц в документе (неотрицательное целое число), либо слово (atend).
%%BoundingBox: llx lly urx ury
координаты левого нижнего и правого верхнего угла в системе координат пользователя, либо слово (atend).
%%EndComments
завершает секцию заголовочных комментариев.
Пример.
%!PS-Adobe-2.1
%%Creator: Adobe Illustrator(TM) 3.2
%%For: (Eduard Projdakov) (PC Week/RE)
%%Title: (NewPS)
%%CreationDate: (2/10/97) (4:30 PM)
%%BoundingBox: 429 490 495 565
%%Pages: (atend)
%%DocumentFonts: (atend)
%%EndComments
Интерпретатор по мере ее чтения слева направо выполнит следующие действия:
1. Заносит в стек число -8; перемещает указатель на следующую свободную позицию.
2. Заносит в стек число 10.4; перемещает указатель на следующую позицию и т. д.
рисунок
Теперь в вершине стека число 77 и оно может быть использовано первым в какой либо операции. Остальные числа используются в порядке обратном порядку их занесения в стек.
Таким же образом в стек могут быть занесены PostScript-объекты любого вида: массивы, строки и такие экзотические объекты этого языка как словари.
Для упрощения объяснений рассмотрим сначала операции в стеке над числами. Обратите внимание, что пробелы, символы табуляции и новой строки являются в PostScript-программе разделителями объектов, другие символы типа круглых и квадратных скобок в некоторых случаях также могут быть разделителями.
Начиная весной эту серию уроков у меня было сомнение -- хватит ли материала на семь занятий. Задав в Интернет поиск по ключевому слову PostScript и получив сообщение, что найдено более 99 тыс. документов, где оно встречается, я успокоился – об этом языке писать можно до 2000 года. Кроме того, обнаружилась книга по PostScript и на русском языке. Это изданный Физматлитом в 1993 г. учебник: Ф.Доймлинг, Д.Стиллеску "Язык программирования PostScript. 20 уроков быстрого освоения". В ней очень детально описывается то, что нами будет пройдено на четырех первых уроках. Следует отметить, что наши занятия методически следуют книге "PostScript Language Tutorial and Cookbook" (Adobe Systems & Addison Wesley, 1987), являющейся де-факто описанием стандарта языка и потому именуемой "Голубой книгой". Тем у кого это издание есть, я рекомендую подождать седьмого урока, который будет отчасти посвящён текущему состоянию языка, литературе и другим не описанным в "Голубой книге" вопросам.
Ну, а если у вас по ходу чтения уроков возникли вопросы, предложения или пожелания, вы можете связаться с автором по телефону (095)237-8901 или по адресу chief@pcweek.ru.
Занятие первое
Есть два подхода к описанию языка PostScript: как к обычному языку программирования и как к языку описания страниц. В статье использован, в основном, первый подход, поэтому предполагается, что читатель имеет хоть какой-то опыт программирования.
Язык PostScript был разработан Джоном Уорноком (John Warnock) в фирме Adobe Systems в 1982 г. История создания языка описана в предисловии одного из его авторов к "Справочному руководству по языку PostScript". PostScript создавался в качестве простого стандартного языка для описания вида текста, чертежей и простых изображений на печатаемой странице, что наложило определенный отпечаток на используемые в PostScript конструкции. Язык содержит около 250 операторов, что позволяет одни и те же действия запрограммировать самыми разными способами. С другой стороны разработчики не предполагали, что программы на PostScript будут большими, поэтому средства структуризации в языке не сильно развиты. Треть языка PostScript посвящена графике, остальное - это обычный процедурный язык программирования, который включает в себя элементы из многих других языков, но наиболее близок к языку Форт. Очень важно, что описание страниц на PostScript не зависит от устройства, на котором страница будет воспроизведена. Как правило программы на PostScript генерируются приложениями, например текстовыми процессорами, программами для настольных издательских систем, в частности CorelDrow, однако, как вы убедитесь сами, в ряде случаев знание этого языка может быть весьма полезным.
До сих пор мы обходились без указания на различия в версиях различных языка PostScript, но сейчас это необходимо сделать. Начнём с небольшого экскурса в историю языка.
Итак язык PostScript был разработан фирмой Adobe Systems в 1985. За эти годы он активно развивался: в следующих версиях добавилась работа с цветом, изображениями и т.д. Реализации PostScript организованы по уровням. Различают языки PostScript Level 1 более поздний , PostScript Level 2. Отметим, что ядро языка при этом не изменилось. PostScript Level 2 адаптирован для новых технологий печати, в него добавлено около 150 новых операторов, оформленных в виде расширений языка. Для нас важно, что эти реализации языка совместимы снизу-вверх, т. е. программа, написанная для реализации Level 1 будет выполнена в интерпретатором для PostScript Level 2. Далее мы будем помечать операторы, относящиеся к Level 2 знаком (L2).
Есть несколько способов определить, какой уровень языка поддерживает ваше оборудование, его название, версию и номер релиза.
Перед тем как продолжить рассмотрение основ языка, замечу, что для отладки программ на PostScript удобно использовать программу RIP, хотя она и работает под DOS. Так как в разных моделях принтеров реализованы различные версии этого языка, то при выводе PostScript-программы на реальный принтер посмотрите его документацию. В частности иногда перед текстом примера следует поставить знак процента, за которым следует восклицательный знак, т. е. %!. Эта комбинация символов переключает на PostScript принтер, понимающий разные языки описания страниц (обычно ещё имеется PCL5).
Итак, продолжим рассмотрение команд перемещения. Как и в других языках описания страниц в PostScript имеется возможность задавать перемещение не в абсолютных координатах, а в приращениях относительно текущей точки. Для этого служат операторы rmoveto и rlineto. Пример из первого занятия можно записать так:
newpath
144 72 rmoveto
0 360 rlineto
stroke
showpage
Следующие две строки
144 432 moveto
-216 rlineto
перемещают текущую точку вверх над сегментом первой линии и добавляют к траектории сегмент линии, проводя ее вертикально вниз (обратите внимание на отрицательный аргумент у) на 216 единиц от текущей точки.
Задание: Напишите программу, рисующую две пересекающиеся прямые (в этом случае текущий путь не будет последовательным).
Траектория не обязательно должна быть единым связанным друг с другом куском. Она может содержать на текущей странице любой набор прямых линий и кривых.
Прямоугольник
Напишем программу, рисующую квадрат со стороной один дюйм, расположенный в центре страницы:
newpath
200 300 moveto
0 72 rlineto
0 -72 rlineto
-72 0 rlineto
5 setlinewidth
stroke showpage
Использование приращений позволяет вам поместить квадрат в любое место страницы, исправив только одну строку. В этой программе новой является только предпоследняя строка
5 setlinewidth
Оператор setlinewidth позволяет вам установить ширину линии. В этой строке задана ширина 5/72 дюйма. Данный оператор действует на все линии, помещаемые на текущую страницу, пока не встретится другой оператор setlinewidth.
Рис. 1 (прогнать пример на принтере)
Наш квадрат, как вы заметили, имеет выщерблину в левом нижнем углу, так как у линий заметная толщина. Чтобы избежать этого явления, следует использовать новый оператор: closepath.
newpath
200 300 moveto
0 72 rlineto
72 0 rlineto
0 -72 rlineto
closepath
5 setlinewidth
stroke showpage
Оператор closepath добавляет к текущему пути линию, соединяющую текущую точку с начальной точкой адресуемой оператором moveto.
Научившись строить квадрат посмотрим как его можно заполнить. Для этой цели служит оператор fill, который "заливает" квадрат черными чернилами:
newpath
200 300 moveto
0 72 rlineto
72 0 rlineto
0 -72 rlineto
сlosepath
fill
showpage
Обратите внимание, что на этот раз вместо перенесения прямых на текущую страницу (stroke), мы вызываем оператор fill, который заполняет некоторым цветом очерченную область. Уровень серого цвета для заполнения фигуры задается аргументом оператора setgray -- числом в интервале от 0 (черный цвет) до 1(белый).
newpath
200 300 moveto
0 72 rlineto
72 0 rlineto
0 -72 rlineto
.6 setgray
fill
showpage
Заданный уровень серого действует до появления следующего оператора setgray. Если setgray не задан, то по умолчанию область заполняется черным цветом. Так как у каждого типа принтера свой способ построения полутонов, то полутона одной и той же PostScript-страницы, выведенной на разных принтерах могут не совпадать. То, что вы получите запустив эти программы может не совпадать по полутонам с рисунками в журнале.
Перекрывающиеся области
При рисовании перекрывающихся областей цвет их пересечения определяется цветом, нанесенным на текущую страницу последним. Пример: нарисуем два перекрывающихся прямоугольника.
newpath % серый квадрат
200 300 moveto
0 72 rlineto
72 0 rlineto
0 -72 rlineto
сlosepath
0.5 setgray
fill
newpath % светлый квадрат
236 336 moveto
0 72 rlineto
72 0 rlineto
0 -72 rlineto
closepath
.8 setgray
fill
showpage % послать на принтер
Обратите внимание, что каждый квадрат начинается с оператора moveto. Это связано с тем, что оператор fill очищает текущую траекторию и после него не определена текущая точка, поэтому lineto и rlineto не имеют начальной точки. Оператор stroke также очищает текущий путь. Каждый блок этой программы содержит также комментарий, который начинается со знака % и продолжается до конца строки. Все что следует за знаком % в строке PostScript-программы интерпретатором игнорируется.