Ir al contenido

PGD | §3.2 – Elementos de PostScript

§3.1 – Introducciòn a PostScript

Luego de la introducción histórica, debe quedar claro que PostScript es un conjunto de tres cosas simultáneamente: un lenguaje de descripción de páginas, un lenguaje de control de impresoras y un lenguaje de programación. Ahondaremos un poco en su estructura, introduciendo esta definición:

Un documento PostScript es una descripción del contenido de una o más páginas que utilizan la sintaxis y el modelo de imagen de PostScript.

Por los propios objetivos de diseño, esta descripción es independiente de cualquier dispositivo particular —impresoras, filmadoras, grabadoras, monitores— empleado en su materialización posterior. Estos documentos son en esencia archivos de texto que contienen una secuencia de comandos y pueden por lo tanto abrirse utilizando cualquier programa[1] capaz de visualizar archivos de texto. En cambio, para conocer el contenido descripto por él es necesario interpretar dichos comandos, lo que normalmente se hace mediante un programa conocido como intérprete. Por esto se dice también que PostScript es un lenguaje interpretado. Cualquier dispositivo que transfiera esa descripción a algún medio o sustrato debe contener un intérprete PostScript.

Una descripción PostScript incluye las características siguientes, las cuales pueden usarse en cualquier combinación:

  • Formas geométricas arbitrarias creadas a partir de líneas rectas, arcos, rectángulos y curvas cúbicas.
  • Instrucciones de pintado que permiten que una forma pueda trazarse con líneas de cualquier espesor, llenadas con cualquier color, o bien que se utilice como máscara de recorte para recortar cualquier otro gráfico.
  • Los colores pueden especificarse, entre otras maneras, mediante escalas de grises, modelos RGB y CMYK y otros basados en modelos CIE.
  • Texto completamente integrado con gráficos, ya que los caracteres se tratan como formas geométricas a las que se le pueden aplicar cualquier instrucción que trabaje sobre gráficos.
  • Imágenes de pixeles obtenidas externamente (como fotografías escaneadas) o bien generadas sintéticamente, a cualquier resolución y expresadas en una gran variedad de modelos de color.
  • Un sistema general de coordenadas que permite toda combinación de transformaciones lineales, incluyendo desplazamientos, escalado, rotación, reflexión y deformación paralela, a cualquier elemento gráfico.

Sintaxis

Resulta ilustrativo ver la sintaxis de PostScript utilizando algunos sencillos ejemplos numéricos. Supongamos que necesitamos que PostScript calcule una operación matemática simple como 2 + 3 ó 5 • 8. En cualquier lenguaje de programación esto se escribiría así directamente, pero PostScript utiliza un mecanismo diferente, cuya utilidad pronto será evidente. Utilizando en cambio ese mecanismo, las operaciones se escriben respectivamente como

2  3  +                         y                               5  8 •

Para comprender esta nueva notación[2] introduciremos algunos conceptos simples. Los datos de las operaciones (2 y 3 en el primer ejemplo, 5 y 8 en el segundo) se denominan operandos, mientras que los símbolos que indican la operación misma (+ y •) se denominan operadores. Así, cada operador requiere que previamente se indiquen todos sus operandos.

¿Cómo se implementa esto? Supongamos el primer ejemplo. A medida que el intérprete lee el documento, leerá primero el 2 y luego el 3, pero hasta ese punto no sabrá qué hacer con esos datos. Es decir, es necesario conservarlos hasta que un operador los requiera. Para ello PostScript utiliza un mecanismo llamado pila, que es posible imaginar como un lugar temporario donde literalmente se apilan los operandos uno encima de otro —por orden de aparición— hasta la llegada del operador que los necesita. Cuando esto sucede, PostScript remueve esos operandos de la pila, dejando en su lugar el resultado de la operación (se dice de esta manera que los operandos son consumidos por los operadores).

Esto se hará evidente mediante una representación gráfica de la pila a medida que el intérprete ejecuta (lee e interpreta) el documento:

Analicemos ahora una operación más compleja, como 3 • 4 + 10. Usualmente se conviene que las multiplicaciones y divisiones deben resolverse antes que las sumas y restas, de modo que la expresión propuesta debe entenderse como una suma entre 10 y el producto de 3 y 4. Si hubiéramos querido en cambio expresar el producto de 3 con el resultado de la suma de 4 y 10 estaríamos obligados a escribir la expresión como 3 • (4 + 10). Es decir, para alterar el orden de precedencia (multiplicaciones antes que sumas) debemos usar paréntesis.

Ahora bien, mientras la primera expresión se escribe en PostScript como

3   4   •   10   +                      (resultado 22),

la segunda se escribe

3   4   10   +   •                      (resultado 42),

ya que la suma operará sobre los dos últimos operandos (4 y 10), y la multiplicación lo hará entre 3 y el resultado de esta última. Aquí vemos la ventaja de esta notación, que prescinde del uso de paréntesis pues el orden de los operadores y operandos determina sin ambigüedad el significado de la expresión.

Operadores

Una expresión como la anterior, ¿es ya una expresión válida en PostScript? No aún, pero casi. Para convertir esto en auténtico código PostScript debemos agregar que los operadores están representados por palabras y no por símbolos (éstos tienen otros usos que veremos después).

Los cuatro operadores matemáticos básicos +, , • y ÷ se escriben como add (add: suma), sub (substract: resta), mul (multiply: multiplicar) y div (divide: dividir). Así, la expresión presentada más arriba,

3   4   •  10   +

se escribe en PostScript

3   4   mul   10   add

¿Qué otros operadores PostScript existen? Son realmente numerosos; si bien nosotros iremos introduciendo diferentes operadores a medida que desarrollemos el tema, puede encontrarse una lista de todos ellos en el capítulo 8 del PostScript Reference Manual, disponible en Adobe. Como cada operador requiere un número diferente de operandos presente en la pila al momento de ser invocados —y pueden dejar un número diferente de resultados en la pila luego de su ejecución—, es conveniente indicar la notación utilizada para brindar esta información. Por ejemplo, el operador add (sumar) se encontrará presentado como

número1 número2 add suma

indicando que este operador espera dos operandos en la pila (número1 y número2) y devuelve un resultado (suma).

No todos los operadores toman y dejan resultados en la pila; de hecho, otras posibilidades son válidas: no tomar datos pero dejar resultados, o bien tomar datos pero no dejar resultados. Otros ejemplos para mostrar la diversidad posible de número de operandos y resultados pueden ser los siguientes:

rand número no toma ningún operando de la pila, pero devuelve un número aleatorio;
número sqrt raíz espera un número y devuelve su raíz cuadrada;
elemento pop  — descarta el último elemento almacenado en la pila.

Nótese que cuando un operador no espera operandos en la pila y/o no deja resultados, se escribe un guión (—).

Modelo de imagen[3]

Este término se aplica al modo que debe emplearse para representar los diferentes objetos gráficos, y constituye una visión simple y unificada de los elementos gráficos bidimensionales comunes en las artes gráficas:

El modelo de imagen es el conjunto de convenciones empleado para representar objetos en una página.

Un programa PostScript construye una imagen ubicando “marcas” en una “página” en áreas seleccionadas. El intérprete mantiene una página actual implícita (current page) que acumula las marcas efectuadas por los operadores de pintado. Al comenzar el programa, la página actual está en blanco. A medida que se ejecuta cada operador de pintado, se van ubicando marcas en la página actual. Cada nueva marca que se superpone a otra la oculta por completo, sin importar su color —ya sea blanco, negro, gris o de cualquier otro color; es decir, todos los colores se tratan como si fueran pintura opaca.

Una vez terminada de componer la página, todas las marcas acumuladas se transfieren al medio (al papel en el caso de una impresora) invocando el operador showpage, que además limpia la página actual, es decir, vuelve a quedar en blanco para componer la página siguiente.

Entre otros, los principales operadores de pintado antes mencionados son los siguientes:

  • fill permite pintar un área.
  • stroke permite trazar líneas (rectas o curvas).
  • image dibuja una imagen basada en pixeles.
  • show escribe texto mediante el trazado de sus caracteres.

Estos operadores requieren varios parámetros, algunos explícitos (es decir, presentes en la pila al momento de ser invocados) y otros implícitos, que dependen del contexto del intérprete en ese momento y no se encuentran directamente en la pila. Uno de los principales parámetros implícitos es el trazado actual (current path), empleado por ejemplo por los operadores fill y stroke. Un trazado (path) consiste en una secuencia de puntos, líneas y curvas, conectadas o no, que describen formas, y sus respectivas posiciones. Se crean mediante la aplicación sucesiva de operadores de construcción de trazos que modifican el trazado actual de alguna manera, generalmente agregando un nuevo trazo al existente. Ejemplos de estos operadores son newpath, lineto, curveto, arc y closepath —entre muchos otros. Hay que tener presente que ninguno de estos últimos realiza marcas en la página, ya que sólo definen un contorno para ser trazado o llenado; esa tarea la realizan los operadores de pintado.

Otros parámetros implícitos incluyen la posición actual (current point), el color actual (current color), el espesor de línea actual (current line thickness) y la fuente actual (current font), designando esto último la combinación de una tipografía y un tamaño específico. El conjunto de los parámetros implícitos define el estado gráfico (graphics state) del intérprete[4]. Otro conjunto de operadores de estado gráfico sirven para cambiar cualquiera de estos parámetros. Por ejemplo, setrgbcolor se emplea para cambiar el color actual a otro especificado en RGB, mientras que setcmykcolor hace lo propio con colores expresados en CMYK. Por último, otros operadores permiten averiguar el estado actual de algunos parámetros; por ejemplo, currentpoint devuelve en la pila las coordenadas de la posición actual.

Muchas veces es conveniente guardar el estado gráfico, por ejemplo cuando acabamos de definir un trazado complejo y queremos utilizarlo con varios propósitos distintos (para trazarlo, pintarlo, utilizarlo como máscara, etc.). Para ello PostScript dispone de dos operadores que se utilizan siempre en combinación: gsave y grestore. Al invocar el primero, se hace copia de todo el estado gráfico actual en una pila especial; a partir de allí puede modificarse como se requiera. Cuando se necesita volver al estado en que se encontraba el intérprete al momento de ejecutar gsave, se invoca grestore.

Sistema de coordenadas

Los operadores de trazado, al definir puntos, líneas y curvas, requieren especificar posiciones en la página, y para ello es necesario definir un sistema de coordenadas sobre ella.

ps-coords
Página PostScript dentro del espacio del usuario.

Este sistema, denominado espacio del usuario (user space) no tiene necesariamente relación con ningún otro espacio empleado por el fabricante del dispositivo —o espacio del dispositivo (device space) — en el que se “imprima” la página. Esto es necesario para preservar la independencia de dispositivo que se persigue como objetivo de diseño. De hecho, PostScript mantiene los datos necesarios para pasar del espacio del usuario al del dispositivo en un objeto que forma parte del estado gráfico y se denomina matriz de transformación actual o CTM (current transformation matrix).

Este espacio del usuario se define, sencillamente, mediante estas tres condiciones:

  • El origen de coordenadas es el extremo inferior izquierdo de la página.
  • Hacia la derecha del origen se extiende el eje x positivo, y hacia arriba el eje y positivo.
  • La unidad de medida en ambos ejes es el punto (point), definido como 1/72 de pulgada.
  • Los ángulos se miden en grados a partir del eje +x, y se consideran positivos en el sentido antihorario.

Este es el espacio del usuario predeterminado, con el cual empieza el intérprete. Sin embargo, existen operadores de transformación que permiten cambiar el origen (translate), la dirección de los ejes (rotate) y la escala (scale) del sistema de coordenadas en cualquier momento durante la ejecución del programa. De hecho, estos operadores no hacen sino modificar apropiadamente la CTM para que resulte en el efecto correspondiente.

El formato de archivo PostScript

De acuerdo a lo expresado, un documento PostScript es esencialmente texto, formado por secuencias de instrucciones del lenguaje PostScript. Es por ello que el formato de archivo correspondiente es simplemente el de un archivo de texto. No obstante, para informar a un intérprete que un archivo contiene código PostScript válido, se utiliza la convención de comenzar el archivo con los caracteres %!. Estos dos primeros caracteres constituyen la “firma” de un archivo PostScript. La extensión de archivo oficial para los documentos PostScript es .ps.

Una de las formas de producir un archivo PostScript consiste en imprimir el documento utilizando la opción imprimir a un archivo (print to file / save as file) disponible en el diálogo de impresión. Esto crea un archivo cuyo contenido es exactamente el mismo que el que se hubiera enviado hacia la impresora; si se elige para esto una impresora instalada que sea PostScript, su driver o controlador también lo será y el archivo producido contendrá código PostScript. En la plataforma Windows, estos archivos de impresión tienen en general la extensión .prn, sin distinción de si el lenguaje empleado sea o no PostScript. En este caso, si se ignora la procedencia del archivo, es necesario examinarlo para comprobar la existencia de la firma %! al comienzo del mismo.

Comentarios

Todo lenguaje de programación tiene la posibilidad de realizar anotaciones dentro del programa para comentar o explicar la función o necesidad de terminada sección de código. Esto se hace de manera de no entorpecer la lectura de ese código por parte del intérprete, para lo cual se define un símbolo o conjunto de símbolos que, al encontrarlo, indica al intérprete que ignore por completo el texto que aparece a partir de allí. En general, el límite a esta interrupción de interpretación está dado por la aparición de otro símbolo, o por el final de la línea en la que aparece. Este texto ignorado se denomina comentario, y es útil para explicar a un potencial lector humano de ese programa las funciones que se realizan.

En PostScript también existe esta posibilidad. Se adopta la convención de interpretar como comentario todo texto a continuación del símbolo % (porcentaje), hasta el final de la línea en que dicho símbolo aparece. Para ilustrar esto, veamos el siguiente fragmento para calcular el número de segundos que tiene un día:

%!
60        % Deja en la pila los segundos en un minuto
60 mul    % Deja en la pila los segundos en una hora
24 mul    % Deja en la pila los segundos en un día

El uso juicioso de esta característica permite que los programas PostScript queden debidamente documentados, facilitando su lectura y comprensión.

Actividades para el capítulo §3.2

  1. Escriba en notación polaca inversa la siguiente operación: ((3 + 7) • 15) / 5.
  2. Escriba en notación polaca inversa la siguiente operación, que resulta de quitar los paréntesis internos a la expresión anterior y comparar: (3 + 7 • 15) / 5.
  3. Reemplazando + por add, • por mul, etc, vuelva a escribir las expresiones anteriores en PostScript.
§3.3 – Procedimientos PostScript >

1 Por ejemplo, el Bloc de notas (Notepad) en Windows™ y el TextEdit en Macintosh™.
2 Esta forma de escribir las operaciones matemáticas es anterior a PostScript y se denomina notación polaca inversa o notación posfija, que data de alrededor de 1920 y cuyo uso fue muy común en las primeras calculadoras científicas. La denominación polaca proviene de la nacionalidad de su impulsor, el matemático y lógico Jan Łukasiewicz.
3 La mayor parte del contenido de este apartado es una traducción adaptada del PostScript Reference Manual ya citado, capítulo 4 (Graphics).
4 Con mayor precisión, el estado gráfico consiste principalmente en el conjunto de parámetros siguiente: color de trazado o pintado actual, espacio de color, coordenadas del punto actual, trazado en uso, trazado de recorte en uso (clipping path), fuente actual (current font), espesor de línea (line width), forma de los extremos de las líneas (line cap), y la matriz de transformación actual (CTM – current transformation matrix), que designa la transformación implícita de coordenadas que resulta necesaria para pasar del espacio del usuario al espacio del dispositivo, como veremos inmediatamente.