Методика разработки сцен на PostScript Урок 6 | Занятие шестоеВстраивание PostScript-программ в документыТак как в России наиболее широко для издательской подготовки текстов и даже для вёрстки используется Word для Windows, то следующей вопрос, который требует пояснения, - как встроить программу на PostScript в документ Word. Дело в том, что Word имеет собственный формат файлов, а программа на PostScript - это обычный ASCII-текст. Разработчики решили эту задачу просто: они оставили для таких случаев лазейку, которая называется поле print. Напомню, что полями в Word называются специальные команды редактора, заключённые в фигурные скобки. Поле print предназначено для того, чтобы выводить символы непосредственно на принтер (например, команды прямого управления принтером, команды на языке PCL и, конечно, PostSript-программы). Формат поля: {print \p Size "текст"} Ключ \p указывает, что в поле текст будет записана PostSript-программа. Операторы PostScript, заданные в этом поле, могут работать только в окне рисования, определённом атрибутом Size, значения которого приведены в таблице.
Так как текст и графика документа Word печатаются на той же PostScript-странице, что и результат PostScript-программы, не следует использовать операторы, которые изменяют или сбрасывают среду PostScript, а именно, избегайте операторов: banddevice, copypage, framedevice, grestoreall, initgraphics, initmatrix, nulldevice, renderbands и showpage. При работе с PostScript в Word вам доступны переменные, которые я свёл в следующую таблицу. Значения, представленные этими переменными, даны в пунктах.
Пример. {print \p page "/Times-Roman findfont strsize scalefont 0.8 setgray"} Ещё о типах данныхВсе данные, доступные PostScript-программам, существуют в виде объектов. Объекты делятся на простые, не имеющие внутренней структуры, и сложные (или составные). К последним относятся строки, массивы и словари. Говоря о строках в PostScript, следует отметить, что в нём, как и в языке Си, есть возможность с помощью обратной косой черты и следующего за ним символа задавать специальные и управляющие символы. Вот ещё одна полезная таблица с такими комбинациями знаков.
Если за \ следует символ, не перечисленный выше, то и он, и обратная косая черта игнорируются. Следующие две строки одинаковы: (Строка с символом перевода строки. ) и (Строка с символом перевода строки.\n) Операторы для работы со словарямиЕщё один тип данных, о котором мы почти не говорили, - словари. Словарь - это ассоциативная таблица, элементы которой - пары PostScript-объектов. Первый элемент пары называется ключом, а второй - значением. Обычно в качестве ключей используются имена объектов, а в качестве значений - переменные и процедуры. В частности, шрифты в PostScript также задаются словарями: именам символов соответствуют процедуры рисования образов этих символов. Есть и другие примеры использования словарей. В языке есть операторы, которые ищут ключ и выбирают соответствующее ему значение, вставляют пару ключ--значение в словарь и выполняют некоторые другие действия. Для работы со словарями в языке имеется специальный стек. Словарь, находящийся в вершине этого стека, называется текущим словарём. Обычно, встречая имя объекта в выполняемой программе, интерпретатор обращается с ним к текущему словарю. Если он не находит там это имя, он обращается к словарю, расположенному в стеке словарей вслед за текущим, и так далее, пока не будут просмотрены все словари в стеке. В интерпретаторе имеется два встроенных словаря, называющихся systemdict и userdict (в PostScript Level 2 к ним добавился ещё один словарь - globaldict). Первый из них связывает (ассоциирует) имена всех операторов языка с их значениями (т. е. действиями, которые выполняются самим интерпретатором). Второй словарь предназначен для связи имён переменных среды с их значениями. Оба встроенных словаря находятся внизу стека (userdict над systemdict) и не могут быть из него удалены. dict создает пустой словарь ёмкостью N элементов. число_элементов 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) над каждой парой ключ--значение в словаре. Если процедура пустая "{}", то таким образом все пары из словаря просто переписываются в стек операндов. Объекты типа operatorЭтот несколько необычный для языков программирования тип объектов в PostScript означает одно из встроенных в язык действий, вызываемое при исполнении объекта. Операторы имеют имена, большинство из которых хранится в systemdict в качестве ключей, а значением является программа, реализующая семантику данного оператора. Другие типы объектов (name, file, mark, null, save, fontID), которые не были рассмотрены до сих пор, мы изучим в разделах, с ними непосредственно связанных. Но вот что важно для объектов всех типов: каждый объект кроме типа и значения имеет один или несколько атрибутов, которые влияют на поведении объекта при его исполнении или когда над ним выполняются определённые операции (кроме случая, когда объект рассматривается только как данные). Атрибуты объектаКаждый объект либо литерал (literal), либо исполняемый(executable). Это важно для интерпретатора при исполнении PostScript-программы. Отметим, что при такие операторы, как "[" и "]" создают литеральные объекты, а операторы "{" и "}" - исполняемые. Другим атрибутом объекта является тип доступа (access) к нему. Имеется четыре типа доступа (расположены в списке по возрастанию ограничений): неограниченный (unlimited), только чтение (read only), только исполнение (execute-only) и без доступа (none). Как правило, объект имеет неограниченный доступ. Это означает, что допускается применение к нему всех операторов, какие определены для работы с ним. Объекты с атрибутом "только чтение" не допускают модификацию своего значения и могут быть только считаны или выполнены. Аналогично, атрибут "только исполнение" определяет, что объект не может быть прочитан, а только исполнен интерпретатором. И наконец, объекты с атрибутом "без доступа" служат для каких-то внутренних целей, о которых я в данный момент ничего не знаю. Понятно, что они не используются программами напрямую. Для получения типа объекта служит оператор type. объект type -> имя_типа Результатом операции может быть одно из перечисленных имен:
Следующие три оператора проверяют соответственно тип доступа объекта:
Синтаксис у них одинаковый. Например, для wcheck он выглядит так: объект wcheck -> лог_значение Операторы cvlit и cvx позволяют изменить атрибут объекта, находящегося в вершине стека операндов, с исполняемого на литеральный и наоборот. объект cvlit -> объект объект cvx -> объект Виртуальная памятьВиртуальной памятью (обозначается VM) называется область памяти, в которой хранятся значения составных объектов. В некоторых реализациях PostScript может сохранять VM в файле в конце сеанса и восстанавливать её в начале следующего. Сохранить и восстановить текущее состояние VM во время выполнения программы можно также с помощью операторов save и restore, а проверить состояние VM - с помощью оператора vmstatus. Цветовые модели в 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. Выборка произвольного элемента из стекаОператор index удаляет неотрицательное целое число n из стека операндов, отсчитывает n-й элемент от вершины стека и помещает копию этого элемента в стек. Это очень напоминает выборку элемента массива. При этом первый элемент в стеке имеет индекс 0. Вместе с операторами copy, dup и roll он позволяет свободно манипулировать содержимым стека операндов. an ... a0 n index -> an ... a0 an Пример. Обозначим буквами содержимое стека, тогда: 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 -> - Ещё о работе с отсечениямиОператоры 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/ 21.11.2001 |