Семь уроков по PostScript

         

Арифметические операторы



Арифметические операторы

Оператор в 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 à объект



bitshift



bitshift

-- логический сдвиг числа. Сдвигает двоичное представление целого числа integer1 влево на shift разрядов, если shift положительно, или вправо, если отрицательно. Возвращает результат integer2. Биты исходящие теряются, а входящие -- обнуляются. Оба операнда должны быть целыми числами.

Синтаксис: integer1 shift bitshift à integer2

Пример.

5 4 bitshift à 80

144 -3 bitshift à 56

Генерация случайных чисел



ceiling



ceiling

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

Синтаксис: число1 ceiling à число2

Примеры.

-1.9 ceiling à -1.0

5.3 ceiling à 5.0

49 ceiling à 49



Циклы



Циклы

В языке PostScript имеется три основных конструкции циклов: простой цикл, индексируемый цикл и условный цикл.

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

4 {pop} repeat
Здесь всё достаточно прозрачно, непривычно, может быть, только то, что в качестве одного из аргументов выступает повторяемая процедура.



clear



clear

а1 а2 clear -

очистка стека - удаляет из стека все элементы 11 6 17 clear -> -



copy



copy

a1...an n copy a1...an a1...an

дублирует n верхних элементов стеков

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

Ряд принтеров, например Apple LaserWriter, позволяет интерактивно с ними взаимодействовать. Вот операторы для этого:

== удаляет элемент из вершины стека и отображает его на экране.

Pstack - печатает все содержимое стека, не изменяя его.

Pstack и == являются полиморфными операторами, так как они в качестве операндов принимают объекты многих типов.



count



count

a1...an count a1...an n

число элементов в стеке



Цветовые модели в PostScript



Цветовые модели в PostScript

В языке поддерживаются две цветовые модели: 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.



cvi



cvi

– берёт из стека число типа integer, real или строку и конвертирует его в целое число. У чисел типа real отбрасывается дробная часть, но, если это число больше максимально представимого в виде целого, возникает ошибка. Строка рассматривается как последовательность символов с записью числа в принятой в PostScript нотации.

Синтаксис:

число1 cvi à целое_число2

строка cvi à целое_число2

Примеры.

17.83 cvi à 17

-17.83 cvi à -17



cvlit



cvlit

-- конвертирует объект из вершины стека операндов из исполняемой формы в литерал.

Синтаксис: оператор cvlit à литерал



cvn



cvn

– конвертирует строку операнда в имя объекта, совпадающее с ней лексически. Имя объекта исполняемо.

строка cvn à имя

Пример.

Синтаксис: (abc) cvn à /abc



cvr



cvr

-- работает аналогично cvi, только результат преобразования – число типа real.

Синтаксис:

число1 cvr à real

строка cvi à real



cvrs



cvrs

– конвертирование в строку в заданной системе счисления. Работает как cvs, но при конвертировании результат записывается в заданной системе счисления. Если она десятичная, то ничем не отличается от cvs (или cvi, если число типа integer).

Синтаксис:

число система_счисления строка cvrs à подстрока

Примеры.

/tmp 14 string def

99 10 temp cvrs à (99)

144 16 temp cvrs à (E0)



cvs –



cvs –

конвертирование в строку. Создаёт текстовое представление произвольного объекта что-либо, записывает его в строку (стирая то, что было в строке ранее) и возвращает подстроку.

Если объект число, то возвращается его строковое представление. Для логических объектов возвращается строка со соловом true или false. Строку cvs просто копирует в другую строку. Если объект имя или оператор, cvs возвращает текстовое представление этого имени или оператора. Во всех других случаях возвращается текст --nostringval--.

Синтаксис: что-либо строка cvs à подстрока

Пример.

/newstr 10 string def

1996 4 add newstr cvs à (2000)



cvx



cvx

– конвертирование в исполняемую форму. Делает литеральный объект что-либо из вершины стека операндов исполняемым. Возможность выполнить динамически создаваемую процедуру.

Синтаксис: что-либо cvx à что-либо

Логические операторы в PostScript работают как с целыми числами, так и с логическими. В первом случае операция выполняется над операндом поразрядно. Имеется четыре основных логических операции: and, or, not и xor (из которых, как известно, можно построить все остальные булевские функции). Для краткости ниже дан пример только для xor.



Действия над стеком.



Действия над стеком.

Эта группа операторов, представителем которой был exch добавляет, удаляет и изменяет порядок следования элементов в стеке.



dup



dup

a1 dup a1 a1

дублирует в стеке его верхний элемент 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) и не могут быть из него удалены.



floor



floor

-- возвращает наибольшее целое число меньшее или равное операнду.

Синтаксис: число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 Systems



Книги по PostScript фирмы Adobe Systems

Литературы по 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



languagelevel

– определение поддерживаемого уровня языка.

Синтаксис: -- languagelevel à уровень

Уровень – это целое число, обозначающее уровень языка PostScript, поддерживаемый интерпретатором. Если он равен 2, то интерпретатором поддерживается язык PostScript Level 2. Если 1 или слова нет в словаре systemdict, то интерпретатор не поддерживает Level 2.



Логические операторы: not and or и xor.



Логические операторы: not and or и xor.

Результат операции сравнения или логической операции -- логическое значение 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 нет зарезервированных слов. Любое слово переопределяемо. Программа в PostScript может рассматриваться как данные и это сближает его с языками типа Лисп.









О работе с файлами



О работе с файлами

Отмечу, что здесь по сравнению с другими языками нет почти ничего нового. В 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.



Объекты типа operator



Объекты типа operator

Этот несколько необычный для языков программирования тип объектов в PostScript означает одно из встроенных в язык действий, вызываемое при исполнении объекта. Операторы имеют имена, большинство из которых хранится в systemdict в качестве ключей, а значением является программа, реализующая семантику данного оператора.

Другие типы объектов (name, file, mark, null, save, fontID), которые не были рассмотрены до сих пор, мы изучим в разделах, с ними непосредственно связанных. Но вот что важно для объектов всех типов: каждый объект кроме типа и значения имеет один или несколько атрибутов, которые влияют на поведении объекта при его исполнении или когда над ним выполняются определённые операции (кроме случая, когда объект рассматривается только как данные).



Оператор anchorsearch



Оператор anchorsearch

определяет, совпадает ли начальная подстрока строки1 со строкой2. (в этом случае строка1 как минимум равна по длине строке2 и соответствующие символы совпадают). Если совпадает, то строка1 разбивается на две подстроки в одну из которых помещается совпавшая часть, а в другую остаток строки1.

Синтаксис: строка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

возвращает координаты текущей точки.



Оператор fill



Оператор fill

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

(Замечу, что страница целиком очищается с помощью не имеющего аргументов оператора erasepage, который закрашивает её серым цветом уровня 1, не изменяя состояния графической среды. Этот оператор выполняется также автоматически после оператора showpage.)

Синтаксис: - fill à -

Перед рисованием fill явным образом закрывает любые открытые подпути текущей траектории. Для её сохранения следует использовать последовательность операторов gsave fill grestore.

Для заливки области по правилу чётный-нечётный используется оператор eofill. В остальном он полностью идентичен оператору fill.



Оператор if



Оператор if

Прежде чем рассмотреть этот популярный во всех процедурных языках оператор, посмотрим, как записываются операции сравнения чисел. В PostScript, напоминаю, операторы сравнения следуют за сравниваемыми величинами.

Оператор Значение

eg = (равно)

gt > (больше)

ge >= (больше или равно)

ne <> (не равно)

lt < (меньше)

le <= (меньше или равно)



Оператор ifelse



Оператор ifelse

Позволяет выбрать в зависимости от условия выполнение одной или другой последовательности операторов. Его формат:

условие {op.1} {op>2} ifelse

Если результат выполнения условия true, выполняется последовательность {op.1}, иначе -- {op.2}.



Операторы add и sub.



Операторы add и sub.

Операторы смотрят находятся ли в стеке их операнды. В общем случае оператор удаляет их из стека и помещает туда результат выполнения своих действий. Например, оператор add (сложение) удаляет из стека два верхних числа, складывает их и оставляет сумму в стеке. Так строка программы, приведенная ниже, будет влиять на стек как показано на рисунке. Аналогично работает оператор sub, вычитающий число, находящееся в вершине стека, из числа, лежащего в стеке следующим.

Другие арифметические операторы:

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, 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) -- это границы области, в которой может быть нарисовано изображение.



Переменные.



Переменные.

Чтобы определить переменную в PostScript, ее имя и значение нужно занести в текущий словарь. Это делается с помощью оператора def, как в следующем примере:

/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

Задание. Используя приведенные выше правила, определите содержимое стека в каждый момент выполнения этой строки.



Переносимость программ.



Переносимость программ.

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









pop



pop

a1 pop -

удаляет из стека его верхний элемент 31 4 pop -> 31



Постфиксная нотация



Постфиксная нотация

(обратная польская запись).

Операции над данными в PostScript требуют, чтобы их операнды сначала были помещены в стек. Такой стиль программирования, при котором операнды задаются до операции над ними (оператора) называется постфиксной нотацией. Так запись операции сложения двух чисел, допустим 4+5, в PostScript будет выглядеть так:

4 5 add



PostScript-шрифты



PostScript-шрифты

Шрифт - это набор символов, имеющих единый дизайн. Дизайн конкретного шрифта называется гарнитурой. Набор гарнитур, разработанных для совместного использования, называется семейством гарнитур. Наиболее популярные гарнитуры: Таймс, Курьер, Журнальная и др.

Конкретный 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



11 сентября 1996 г. фирма



PostScript Level 3

11 сентября 1996 г. фирма Adobe Systems объявила о выходе следующего уровня языка PostScript. В PostScript Level 3, по заявлению фирмы, улучшена производительность, функциональные возможности и качество. На самом деле, предпринята попытка создать совокупность решений, покрывающих очень широкую область применений: от домашних систем и малых офисов до больших корпоративных сетей и Интернет. По заявлению представителя фирмы, PostScript Level 3 это результат воздействия трёх тенденций рынка: распространения Интернет, усиления использования цвета и перехода от печати и дистрибуции к дистрибуции и печати по запросу. Учитывая, что появилось много новых источников цифровых документов, например онлайновые службы, intranet, цифровые камеры, электронная почта и т. д., а сами документы становятся всё более сложными и предназначенными для печати в любой точке планеты, создание нового уровня PostScript вполне закономерно. Adobe предложила больше чем язык описания страниц для выпуска и печати электронных документов. В Level 3 реализован ряд новых технологий: Advanced Page Processing, Enhanced Image Technology, NetWorks System и PlanetReady Printing.

Технология Enhanced Image Technology (EIT) обеспечивает более быструю, простую и качественную печать документов. Главное преимущество для пользователя в том, что EIT распознаёт объекты изображения и автоматически оптимизирует их обработку. Введена поддержка печати трёхмерных изображений, изображений с фотографическим качеством и др.

Технология Advanced Page Processing (APP) увеличивает производительность системы обработки изображения. Так как компоненты документа становятся более сложными печатающая система будет обрабатывать каждую компоненту как отдельный объект, в последовательности оптимизированной для повышения пропускной способности. PostScript Level 3 будет поддерживать обработку содержимого Web-узлов, включая работу с HTML- и PDF-файлами. Чтобы обеспечить совместимость с основными операционными системами и сократить время пересылки шрифтов в принтер, в APP расширен также набор резидентных шрифтов. Это. Кроме того, фирма Adobe интегрировала в Level 3 поддержку формата PDF.

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

Технология PlanetReady Printing, реализованная, обеспечивает в принтерах с PostScript Level 3 поддержку национальных языков.

Adobe завершила разработку PostScript Level 3 и сейчас занимается его внедрением. План-график выпуска продукта предусматривает два внутренних цикла улучшения качества перед поставкой системы производителям принтеров и партнерам, разрабатывающим ПО (начало поставок планировалось на декабрь прошлого года). Во второй половине этого года, когда начнётся выпуск продуктов, базирующихся на этой версии языка, фирма Adobe обещала опубликовать описание PostScript Level 3. Подождём. Время бежит быстро.


Поворот осей



Поворот осей

Оператор 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



у меня было желание написать



Предисловие

Когда-то у меня было желание написать книгу, посвященную
языкам описания страниц (PDL). Начал я с языка PostScript, как наиболее важного интересного в этой группе. Так в журнале PC Magazine/RE появилась серия статей под названием “Семь уроков по PostScript”. К сожалению, их электронный вариант в редакции журнала не сохранился, однако у меня остались предшествующие версии, которые объединены в этом файле и предлагаются вашему вниманию. Утрачены тексты некоторых примеров и картинки с результатами исполнения примеров. Так как, похоже, что я из-за нехватки времени уже никогда не напишу задуманную книгу, то
(F) Этот текст может свободно использоваться, модифицироваться и распространяться в любой форме. Автор же не несет за него ни малейшей ответственности.

print



print

-- записывает символы строки в стандартный файл вывода. Оператор print предоставляет простое средство для пересылки текста приложению или пользователю. Этот оператор не рисует символы на текущей странице (для этого используется операторы show и showpage).

Синтаксис: строка print à --

Следующая встроенная процедура == носит название “два знака равно” (twoequals). Она введена в язык для удобства отладки.

Синтаксис: что-либо == à--

== извлекает объект из стека операндов, создаёт его текстовое представление, близкое по форме к синтаксиссу PostScript, помещает вслед за ним знак перевода строки и записывает результат на стандартное устройство вывода. Имя == не является специальным: в программе на PostScript оно может быть разделено “белыми” пробелами или специальными символами, как и имя составленное из букв.

Встроенные функции

Некоторые встроенные функции были рассмотрены на первом занятии. Сейчас мы добавим к ним ещё десяток, связанных с работой с числами.



Процедуры.



Процедуры.

Процедура в PostScript - это набор операторов сгруппированных под общим именем. Имя процедуры является ключом в словаре, а набор операторов ассоциируется как его значение. Когда имя процедуры появляется в программе, то выполняется связанный с ним набор операторов. Процедуры в PostScript определяются точно так же, как и переменные, с тем только отличием, что набор операторов процедуры должен быть заключен в фигурные скобки. Следующая строка, например, описывает процедуру inch (дюйм), полезную для перевода дюймов в систему единиц, используемую в 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



product

-- возвращает объект типа строки только для чтения, содержащую название продукта, в котором исполняется интерпретатор языка PostScript.

Синтаксис: -- product à строка



Работа со шрифтами



Работа со шрифтами

Язык PostScript не был бы так популярен, если бы он не предоставлял богатейшие возможности вывода на печать текстов. Текстовые данные представлены в PostScript объектами типа string (строка). Строка может содержать любую последовательность символов, заключенную в круглые скобки. Строка может быть помещена в стек, присвоена переменной или напечатана. Однако перед тем как строка будет помещена на текущей странице интерпретатору PostScript необходимо указать какую гарнитуру и размер шрифта использовать при печати.



rand



rand

– помещает в стек случайное целое число типа integer в диапазоне от 0 до 231-1, полученное с помощью генератора псевдо-случайных чисел.

Синтаксис: -- rand à int



realtime



realtime

-- возвращает отсчет таймера, считающего реальное время независимо от интерпретатора PostScript. Минимальный интервал отсчитываемого времени равен одной миллисекунде, начальное значение и частота обновления счётчика произвольны и зависят от реализации. Как только значение счётчика времени станет больше, чем максимально большое целое число, интерпретатор меняет его на 0 или, в некоторых реализациях на наименьшее целое (наибольшее отрицательное) число. (L2).

Синтаксис: -- realtime à int



revision



revision

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

Синтаксис: -- revision à - int

Печать



roll



roll

вращает элементы стека, из стека извлекаются два числа. Верхнее говорит сколько раз и в каком направлении вращать элементы стека, второе - сколько элементов вращать.

7 8 9 3 1 roll -> 9 7 8

7 8 9 3 - 1 roll -> 8 9 7



round



round

-- возвращает целое число, ближайшее к ее операнду. Если аргумент дробная часть аргумента равна 0,5 (т. е. он одинаково удалён от соседних целых чисел), то возвращается большее целое число. Тип результата совпадает с типом операнда.

Синтаксис: число1 round à число2

Примеры.

-1.9 round à -2.0

8.5 round à 9.0

-8.5 round à -7.0

Index</A><BR>



rrand



rrand

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

Синтаксис: -- 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



Система координат.



Система координат.

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

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

Пространство пользователя может быть изменено тремя способами:

1) начало его системы координат может быть перенесено в любую точку пространства пользователя;

2) оси могут быть повернуты в любом направлении;

3) масштаб по каждой оси может быть произвольно изменен, т. е. может быть задано любое линейное преобразование из пространства пользователя в пространство устройства.



Соглашения по структуре программы



Соглашения по структуре программы

Язык PostScript не определяет общую структуру PostScript-программы, однако существуют некоторые соглашения, облегчающие её структуризацию. Для записи информации о программе используются комментарии специального вида. Такой комментарий занимает строку целиком и начинается не с одного знака процента, а с двух. Специальные комментарии делятся на три группы: заголовочные комментарии (header comments), комментарии тела программы (body comments) и комментарии эпилога(trailer comments).

Заголовочные комментарии предшествуют тексту программы. Комментарии тела программы служат для разделения разных частей описания страницы. Комментарии эпилога следуют после текста программы и дают о ней дополнительную информацию.



Сохранение состояния графики PostScript



Сохранение состояния графики PostScript

До сих пор мы работали с графикой явным образом, меняя с помощью операторов ее состояние. Состояние графики - это набор данных, которые описывают, как операторы будут влиять на текущую страницу. Пара взаимодополняющих операторов, gsave и grestore, позволяют сохранить текущее состояние графики, а затем в нужный момент восстановить его. Это может потребоваться до и после использования оператора fill, который, как вы помните, очищает текущую траекторию. Если нужно продолжить рисование из какой-либо точки заполняемой оттенком серого фигуры, то удобно просто восстановить состояние графики , сохраненное до выполнения fill. Пример вы легко придумаете сами.

Оператор gsave сохраняет копию текущего состояния графики в стеке состояния графики. Этот стек может хранить до 32-х состояний графики, включая текущее состояние.

Оператор grestore восстанавливает состояние графики, сохраненное в стеке самым последним. Все характеристики текущего графического состояния, включая текущий путь уровень серого цвета, ширину линии и систему пользовательских координат возвращаются в состояние, в котором они были перед выполнением оператора gsave.



Стек.



Стек.

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

Стек операндов - содержит собственно объекты PostScript и результаты действий над ними. Операторы PostScript получают операнды только через стек.



Стек и арифметические операции



Стек и арифметические операции

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



Типы данных.



Типы данных.

Как и другие распространенные языки программирования PostScript поддерживает различные типы данных, включая integer, real, boolean, массивы и строки. В нём определяются также объекты типа mark (отметка, метка) и dictionary (словарь).

Примеры записи целых чисел: 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.



truncate



truncate

возвращает целую часть своего операнда.

Синтаксис: число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



usertime

– возвращает значения интервального таймера, который увеличивается на 1 за каждую миллисекунду работы интерпретатора PostScript. Это значение никак не связано с календарным временем. При достижении предельного значения счётчика он, в зависимости от реализации, устанавливается либо равным нулю, либо наибольшему отрицательному целому числу.

Синтаксис: -- usertime à int



Условные переходы



Условные переходы

Введем понятие выполняемого массива. Это более формальное название объекта, который ранее был назван процедурой.

Какая разница для PostScript между строками

12 5 sub

и

{ 12 5 sub} ?

В первом случае числа 12 и 5 будут помещены в стек и будет выполнена операция вычитания, а во втором -- эти числа и оператор sub будут помещены в массив, который затем будет занесен в стек. Выполняемому массиву может предшествовать имя, задаваемое в виде литерала, а закрывать его может оператор def, который ассоциирует его с именем в текущем словаре.

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



version



version

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

Синтаксис: -- version à - версия



Виртуальная память



Виртуальная память

Виртуальной памятью (обозначается VM) называется область памяти, в которой хранятся значения составных объектов. В некоторых реализациях PostScript может сохранять VM в файле в конце сеанса и восстанавливать её в начале следующего. Сохранить и восстановить текущее состояние VM во время выполнения программы можно также с помощью операторов save и restore, а проверить состояние VM – с помощью оператора vmstatus.



Вместо заключения



Вместо заключения

На этом заканчивается наш вводный курс в язык PostScript. Мы почти полностью прошли PostScript Level 1 и чуть-чуть коснулись L2. Как всегда, в конце работы видно, что её нужно было делать совсем не так. Конечно же, к седьмому уроку автор уже сам почти всё понял ;).

С Эдуардом Пройдаковым, главным редактором еженедельника PC Week/RE, можно связаться по адресу: chief@pcweek.ru.



Встраивание PostScript-программ в документы



Встраивание PostScript-программ в документы

Так как в России наиболее широко для издательской подготовки текстов и даже для вёрстки используется 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 à -



xor –



xor –

если оба операнда логические величины, то в стеке возвращается результат операции “исключающее ИЛИ”, если операнды – типа integer, в стек помещается результат поразрядной операции xor над их двоичным представлением.

Синтаксис:

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 – меньше чем.



Индексируемый цикл напоминает широко известную



Задание.

Нарисуйте последовательность из N вложенных кругов, квадратов, эллипсов.
Индексируемый цикл напоминает широко известную по Бейсику конструкцию for... to... next. Оператор for берет из стека четыре операнда: начальное значение счетчика цикла, его приращение, конечное значение счетчика цикла и повторяемую процедуру. За исключением последнего операнда всё выглядит как и в обычной конструкция for. Следует учитывать, что непосредственно перед выполнением этой процедуры for помещает в стек текущее значение счетчика и, если он не используется, то его следует оттуда явным образом удалять.
Следующая строка напечатает звездочку через каждые 15 единиц на странице:
0 15 450 {0 moveto (*) show } for



Задание.

Нарисуйте пунктирную линию.
Вторая важная особенность for в том, что его операнды не обязательно должны быть целыми числами. Вот пример использования этого для возможной модификации шрифта:
/Helvetica findfont 30 scalefont setfont
/printword
{ 0 0 moveto (PC Magazine) show} def
200 300 translate
.95 -.05 0 % начало приращения, конец
{setgray printword -1.5 translate} for
1 setgray printword
showpage
<рис. файл p4_1.ps>
Условный цикл соответствует конструкции repeat...until в Паскале. Строится он из двух операторов: loop и exit. Опертор loop повторяет выполнение процедуры до тех пор пока в ней не встретится оператор exit, который заканчивает циклическое выполнение, причем не только в конструкции loop, но и в for, repeat и forall (об этой специальной форме цикла будет расказано ниже). Если в повторяемой процедуре нет оператора exit, то цикл будет бесконечным, например:
{(PC Magazine) show} loop
будет бесконечно печатать слово PC Magazine.
Нарисуем незамысловатую последовательность кругов просто, чтобы продемонстрировать работу loop - exit.
/pagewidth 8 72 mul def
/circle
{x y radius 0 360 arc stroke} def
/new-x
{x radius add
/x exch def} def
/dolineofcrle
{/y exch def
/radius exch def
/x 0 def
{x pagewidth le
{circle new-x}
{exit} ifelse
} loop
} def
% main
15 200 dolineofcrle
25 200 dolineofcrle
showpage



Задание

. Чтобы почувствовать разницу между двумя этими правилами, нарисуйте с помощью PostScript две одинаковых пятиугольных звезды (не убирая внутренние линии) и заполните их внутренние области с помощью операторов fill и eofill соответственно.
Для того, чтобы поместить графическое изображение на страницу, используется оператор image.
Синтаксис:
ширина высота бит/точка матрица процедура image à -
Изображение помещается в прямоугольную область размером ширина на высоту точек, каждая из которых представлена значением из бит/точка данных (1, 2, 4 или 8 битов на точку). Данные изображения считываются как последовательность символов, причём, если точка кодируется менее 8 битами, то данные упакованы в байте слева направо.
Изображение на странице имеет свою собственную систему координат, за начало которой (0,0) принят нижний левый угол прямоугольной области изображения, а верхний правый угол имеет координаты (ширина, высота). Операнд матрица задаёт преобразование из пространства пользователя в систему координат изображения.
Последний операнд (процедура) последовательно выполняется оператором image, чтобы получить данные изображения. Обычно эти данные читаются из файла с помощью оператора readhexstring.

Заголовочные комментарии



Заголовочные комментарии

Некоторые из этих комментариев могут помещаться в конце программы по усмотрению программиста или приложения, генерирующего 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



Занесение чисел в стек.



Занесение чисел в стек.

Любое число, появившееся в исходном файле PostScript-программы заносится в стек. Например, строка -8 10.4 +77...

Интерпретатор по мере ее чтения слева направо выполнит следующие действия:

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-программы интерпретатором игнорируется.