Новости

О проекте

Зачем?

Используемое ПО

Методика разработки сцен на PostScript

Операторы языка PostScript

Библиотека

Изучение языка

Урок 1

Урок 2

Урок 3

Урок 4

Урок 5

Урок 6

Урок 7

Статьи

Ссылки...

Занятие второе

Перед тем как продолжить рассмотрение основ языка, замечу, что для отладки программ на PostScript удобно использовать программу RIP, хотя она и работает под DOS. Так как в разных моделях принтеров реализованы различные версии этого языка, то при выводе PostScript-программы на реальный принтер посмотрите его документацию. В частности иногда перед текстом примера следует поставить знак процента, за которым следует восклицательный знак, т. е. %!. Эта комбинация символов переключает на PostScript принтер, понимающий разные языки описания страниц (обычно ещё имеется PCL5).

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

     newpath
       144 72 rmoveto
       0  360 rlineto
     stroke
  showpage 

Следующие две строки

      144  432 moveto
        0 -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.

Наш квадрат, как вы заметили, имеет выщерблину в левом нижнем углу, так как у линий заметная толщина. Чтобы избежать этого явления, следует использовать новый оператор: 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
          0 -72 rlineto
        -72   0 rlineto
     сlosepath
     fill
  showpage 

Обратите внимание, что на этот раз вместо перенесения прямых на текущую страницу (stroke), мы вызываем оператор fill, который заполняет некоторым цветом очерченную область. Уровень серого цвета для заполнения фигуры задается аргументом оператора setgray -- числом в интервале от 0 (черный цвет) до 1(белый).

     newpath
        200 300 moveto
          0  72 rlineto
          0 -72 rlineto
        -72   0 rlineto
     сlosepath
     .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-программы интерпретатором игнорируется.

Процедуры и переменные

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

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

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

Обсуждаемые выше словари хранятся в стеке словарей: словарь пользователя в верху стека, системный -- внизу. Таким образом слово ищется начиная с вершины стека. Программа может создать новые словари, которые будут размещены в вершине стека словарей. Словарь, находящийся в вершине стека и, следовательно, просматриваемый первым, называется текущим словарем.

Определение переменных и процедур

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

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

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

PostScript-шрифты

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

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

Чтобы задать шрифт, нужно выполнить следующие действия:

  • найти описание шрифта в словаре шрифтов. Это описание позволяет построить контуры каждого отдельного символа. Подробнее об этом словаре будет рассказано несколько позже;
  • отмасштабировать шрифт до нужного размера. Его размер задается минимальным расстоянием по вертикали между строками текста, необходимым, чтобы эти строки не накладывались одна на другую, например обычный шрифт часто задается высотой в 12 пунктов (напомним, что 1 пункт = 1/72 дюйма);
  • установить отмасштабированный шрифт в качестве текущего шрифта, которым и будет печататься текст.

Чтобы посмотреть, как это работает, давайте напечатаем слово PostScript шрифтом Helvetica размером 14 пунктов.

    /Helvetica findfont
            14 scalefont
               setfont

       100 150 moveto
  (PostScript) 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 

Графика и текст

В 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 

Обратите внимание, что второй перенос системы координат осуществляется уже относительно новой системы координат, а не относительно исходной.

Поворот осей

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

Изменение шкал по осям координат

Оператор scale позволяет изменить размер единицы измерения по каждой из осей координат. Он берет из стека два аргумента - коэффициенты изменения масштаба по осям x и y, соответственно, и с их учетом изменяет размер системных единиц. Например строка:

        2 2  scale 

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

Попробуйте напечатать треугольники из предыдущего примера используя следующие размеры системной единицы:

  1. по умолчанию;
  2. 1.5, 2.5;
  3. 1.75, 1.

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

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

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

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

16.11.2001



©Фурашев А. 2002
e-mail

Хостинг от uCoz