You are on page 1of 27

b

Adobe Confidential 1
a
PostScript RIP
The PS interpreter consists of 2 main parts. the product code and the packages. The 2 products are Camelot and
cpsi, each having their own functionalities, but both share the same packages which forms the core of the
interpreter.
A short summary on what each of the packages do, should ease the understanding of the flow of the
interpretation process.
Package Overview
The main packages and their respective functions in the RIP are as follows
1. language
This package consists of the basic PostScript language interpreter.
The functions performed by the files in this package are
i. Scanning stream ( scanner.c )
ii. Tokenizing stream ( scanner.c )
iii. Making the PostScript Objects from the tokens ( StmToken in scanner.c )
iv. The main execution loop of the RIP is psExecute in exec.c from which
the respective postscript functions are called
v. Implementation of the control operators, the major files in this being exec.c,
stack.c, dict.c, math.c for their respective areas
b
Adobe Confidential 2
a
Package Overview
2. graphics
This package is responsible for graphics, under can be divided into
i. Maintaining graphics state ( color, linewidth, other parameters )
This functionality is mainly implemented in gstates.c, psgraphics.c
ii. Managing path opertators like newpath,closepath,stroke, fill
this is implemented in pathops.c, rect.c, userpath.c.
iii. Managing patterns
All the pattern related implementation is found in fandp.c
iv. Interpretation of images, this is implemented in image.c, imageint.c etc
v. Shading interpretation, the files here are shade*.c
vi. Marking device primitives onto framebuffer is performed if
frame device is used, else rendering into displaylist in case of Band device.
The implementation is in shademark.c & graphmark.c.
3. devpath
The devpath package is the main path interpreter.
Its main roles include
i. It takes care of stroke, fill
ii. Related functions, like stroke adjustments, miter points, line joins etc
b
Adobe Confidential 3
a
Package Overview
4. font/truetype/buildch
All the above are font related packages. Their are used
depending on the font type and function.
i. The font package contains the implementation of the show operator,
in fontshow.c, which is the main file. It determines the further
path the program takes depending on the type of font chosen.
ii. The buildch is the font rendering package that does the
glyph interpretation.
iii. The truetype package is used specially for truetype fonts. The truetype glyph
building is done in ttbuild.c, but the rendering is done by the common buildch
package.
5. vm
The vm package is used for PostScript vm maintenance, its main functions are garbage
collection and managing storage of composite objects
6. device
This package is implements the primitives storage into the display list
and also the retrieving of data from display lists
i. this implements the different device types like band, frame etc
ii. the primitives are stored into the display list in the
banddevdlwalk.c, where functions like WalkTraps call the
store functions like StoreTrap to store data into the display list
b
Adobe Confidential 4
a
Package Overview
iii. The showpage is achieved through the HybridShowPage
iv. the ProcessBand function is called for the actual rendering, and this
is implemented in banddevprocessband.c
7. devpattern
this package is a rendering package used mainly for color conversion.
not much is known about this package as of now
this package is a mystery, it has lots of files.
8. displaylist
the displaylist is used to store primitives in buffers. The buffers are managed
by this package. some of its major functions are
i. managing of display list in RAM and on disk as buffers grow bigger
ii. its used during rendering for in the renderer
9. framemarker
this is a rendering package. this package contains rendering code for all primitives except
images.
10. others
The other packages play small roles in different part of the execution
some of their functions are
i. framestorage manages frame buffer and generates checksums
b
Adobe Confidential 5
a
Package Overview
ii. fp implements fixed point arithmetic functions
iii. io implements a wrapper layer to the OS io
iv. opsys implements a wrapper layer for system calls
v. pslib implements a memory manager, cache etc
vi. rest of packages are not that important
b
Adobe Confidential 6
a
Rip basics
At startup the PS RIP loads PS.VM. The PS.VM contains operator names, resource dictionaries
etc. The interpreter takes even the operator names from PS.VM file, and it looks up arrays to map operator
names to C functions. Also some core objects need to build to startup. Building the VM, each time the RIP starts,
would slow it down, and hence PS.VM is used. Thus PS.VM is a snapshot of the VM pre-created for RIP
efficiency.
At startup the command line param supplied are processed by the product running ( cpsi or
Camelot ). The product code updates the parameters supplied in its data structures, for later use by the RIP. The
below chart shows the RIPS overall flow for CPSI.
The PS interpreter does its job by executing entities called PostScript Objects. These objects may
be numbers, boolean, strings etc. Other objects are executable like operators, procedures etc. The interpreter
works by executing these objects in a sequence. In PostScript 2 types of objects are defined, Literal objects and
Executable Objects. The Object structure used in RIP is below.
typedef struct _t_Object {
BitField tag:1; /* decides if literal or exec for 0 or 1
Access access:3; /* Access is actually a BitField too */
BitField type:4;
BitField shared:1;
BitField seen:1;
BitField mayRecycle:1; /* 1: may be recyclable; 0: definitely not */
BitField level:5;
BitField length:16;
b
Adobe Confidential 7
a
Rip basics
union {
/* null */ Int32 nullval;
/* int */ Int32 ival;
/* real */ real rval;
/* name */ PNameEntry nmval;
/* bool */ boolean bval;
/* str */ charptr strval;
/* stm */ PStmBody stmval;
/* cmd */ PNameEntry cmdval;
/* dict */ PDictBody dictval;
/* array */ PObject arrayval;
/* pkdary */ PCard8 pkdaryval;
/* mark */ Int32 markval;
/* save */ Int32 saveval;
/* font */ Int32 fontval;
/* generic */ PGenericBody genericval;
/* gstate */ PGState gstateval;
/* cond */ PCondition condval;
/* lock */ PLock lockval;
/* namearray*/PNameArrayBody namearrayval;
/* magic */ PMagicBody magicval;
} val;
} Object;
b
Adobe Confidential 8
a
Rip program flow
Start CPSI
Process command
args
Fill in CPSIEngine,
CPSIRasterBuffer
with relevant parameters
psExecute( ) starts
Parsing PS data
A function for each operator
Is called, like PSMoveTo,
PSLineTo etc
showpage
operator gives final
output
b
Adobe Confidential 9
a
PS parsing
The first functionality the RIP has to accomplish is parsing the input PS file. The parsing and
object creation is done by the StmToken rouctine in scanner.c. The StmToken routine reads the input string
character wise creates objects from them. If the object created is a operator the StmToken returns a executable
Object to its caller, which is psExecute. When StmToken meets operand objects it pushes them onto the operand
stack.
For.e.g consider the input PS string 100 100 moveto
Its execution through StmToken is traced below.
Step 1. Read in 1, recognizes numbers, starts begnum section
Step 2. Read in 0, recognizes as number, a new number has been begun earlier and so
appends 0 to current number, to get 10.
Step 3. Read in 0, a number appends to current number to get 100.
Step 4. Read a space. End current number and object created. As object is not executable
IPushSimple pushes it onto stack.
Step 5. Read in 1. Steps 1-4 are repeated again.
Step 6. Read in m, recognized as character, starts begname section to create name
Step 7. Read in o, append to current name.
Step 8. The above continues till EOL is met, then a executable object is returned to
psExecute
Step 9. psExecute calls function PSMoveTo which was registered as the function for
moveto operator
Step 10. If we give a invalid operator say mmoveto the psExecute fails to find the name
as defined and a error is flagged and interpretation stops
This shows the basic parsing process of the RIP.
b
Adobe Confidential 10
a
How is the opcode determined?
When the StmToken encounters a name object it
1. Tries to look for the name in a matching name in the dictionary.
2. FastPName() is called which first hashes the name.
3. Then it searches for name in the hash chain.
4. If the name matches then it returns a matching name object
5. Otherwise a new name object is created and returned.
Once StmToken gets the object the control is transferred to psExecute()
1. The currentCmd is stored in ob.length
2. psExecute() transfers control to the relevant function by (*cmds.cmds[ob.length])();
*cmds.cms[] is like a lookup table where the opcodes are mapped to the relevant function. Some of these
mapping are defined in languagenames.h
Example
cmd = moveto
ob.length = 263
psExecute calls PSMoveTo() on this opcode.
b
Adobe Confidential 11
a
Stack
The PS Stack is the main structure the interpreter maintains. The operand stack holds data that
will be consumed by the operators. To illustrate how the stack works, consider the earlier example where the
integer type object ( 100 ) was pushed onto the stack using IPushSimple function.
This function just takes in the stack pointer, checks for overflow and pushes the object and
updates the stack top pointer. If the input string was 100 moveto then a stackunderflow error occurs since 2
objects are not available to be popped out for moveto.
The PS manages 2 other stacks, the dictionary stack and the execution stack. The dictionary stack
contains the holds only dictionary objects. The execution stack holds executable objects. If for some reason the
interpreter pauses it pushes the executable object on this stack to be able to resume later
b
Adobe Confidential 12
a
Graphics in PS
PostScript provided a great deal of functionality for graphical manipulations. There are
seven kinds of operators in PS
1. Graphic State Operator which modify the graphic state, the global framework within
which the other graphical operators execute
2. Coordinate system and matrix operators are responsible for transformation from the user
to device coordinates. They are also used for transformations like skew, rotation, scaling,
translation
3. Path Construction Operators current path which define shapes and line trajectories.
1. 0 0 moveto moves the current point to 0, 0 in in the user coordinate and sets it as
the initial position of any path
4. Painting Operators these operators are used for painting graphical elements into the raster
memory of the output device.
5. Glyph and Font operators - select and paint character glyphs from fonts. Most of these are
grouped with path and paint operators.
6. Device Setup Operators establish an association between the raster memory and a
physical output device like a printer.
7. Output operators Once a page has been completely described, executing an output
operator transfers the page to the output device.
b
Adobe Confidential 13
a
Graphic State
All the graphical manipulation in PS takes place through the graphical state
typedef struct _t_GState {
GenericBody header;
Mtx matrix, /* CTM */
defaultMatrix; /* used by defaultmatrix, initgraphics */
PMakeFontEntry pMfe;
PReadyFontEntry pRfe;
DictObj fontDict, pfontDict;
Path path;
Path clip;
integer clipID; /* used in distillery */
PCState clipStack;
Integer clipCount; /* number of entries on the clipStack */
Cd cp;
real lineWidth;
real miterlimit;
real devhlw;
AryObj dashArray;
real dashOffset;
Color color;
Screen screen;
TfrFcn baseTfrFcn, tfrFcn;
b
Adobe Confidential 14
a
Graphic State
Rendering rendering;
real flatEps; /* epsilon for curve flatness test */
real smoothness; /* error percentage for smooth shading */
DevPoint screenphase;
PDevice device;
boolean isCharPath:1
boolean noColorAllowed:1; /* following fields should total to 16 bits */
boolean saveState:1;
boolean strokeAdjust:1;
boolean circleAdjust:1;
boolean overprint:1;
boolean overprintmode:1;
BitField lineCap:2;
BitField lineJoin:2;
boolean colorRemapped:1;
boolean useCIEColor:1;
BitField unused2:3;
/* end of 16 bits */
real strokeWidth;
PGState previous;
Object origColorSpaceObject;
char *extension; /* for experimental additions */
} GState;
b
Adobe Confidential 15
a
Graphics State
The PS needs to maintain a graphics state to keep track of the current execution state. This is done
though a global graphics state variable gs. gs is always the current graphics state. The gs holds the current
transformation matrix which is the key to conversion from user co-ordinate system to the device co-ordinate
system. The CTM is on the form [a b c d tx ty] where tx & ty are translation factors in x and y direction, a,b,c &
d are the scaling/rotation factors. Consider the operators that modify the CTM.
Case 1. 100 100 translate, the PSTlat function pops the 100 100 from stack and passes
them to the Tlat routine. This routine adds the translation values after converting
them to device space to the CTM->tx and CTM->ty ( gs->matrix is CTM ).
Case 2. 10 10 scale, the PSScal function pops the 10 10 from stack and passes them to
the Scal routine, which initializes the CTM->a and CTM->d to scaleX and scaleY
respectively.
Case 3. 20 rotate, the PSRtat function pops the 20 from stack and passes them to the
Rtat routine, which initializes CTM->a=CTM->d = cos(angle) and
CTM->c= -CTM->b=sin(angle);
Other than the above routines there are many functions that modify the graphics state. Some of
the important routines and the variables they modify are
NewPath this routine initiates a new path, by clearing the gs->path structure that holds the
current path.
PSLineWidththis routine sets a new line width chosen in gs->linewidth
PSSetStrokeAdjust this routine sets the strokeadjust flag
GSave saves the current graphics state by pushing it onto a graphics state stack for
restoring it later stage if necessary
GRestore restores the graphics state from the graphics state stack
PSMoveTo sets the current point variable in gs ( gs->cp )
b
Adobe Confidential 16
a
Paths
The paths define shapes, trajectories and regions of all kinds. It comprises straight and curved line
segments which might be connected or disconnected. Current path of graphics state contains all the
information about a path being constructed. Clipping path outlines the clipping region.
How are paths constructed ?
There are essentially 3 steps required:
1. Modify the CTM if required
2. Call the procedures to construct the path
3. Invoke the painting operator to mark the path
Example:
0 0 moveto
100 100 lineto
100 0 lineto
closepath
stroke
2
3
3
b
Adobe Confidential 17
a
Paths (MoveTo)
100 100 moveto
when the parser reaches this position the operands for moveto have already been placed on the
stack. After the command is parsed control returns to psExecute() which then in turn calls PSMoveTo().
PSMoveTo()
1. PopPCd() gets the coordinate to which the moveto is performed, (100 100) in this case.
They are stored on the top of the opStk
2. Then TfmPCd() converts this point to device coordinates
3. PSMoveTo then calls DPR_MoveTo() which then in turn calls InnerDPR_MoveTo()
4. InnerDPR_MoveTo() finds out whether a moveto was performed in the pervious step, if it
was then the previous point is removed from the path.
5. The BBox is increased to accommodate the current point
6. It adds this point on which the moveto was performed to dpOpnds in the path and the length
of the path is incremented
7. gs->cd = cd, the current point in the graphic state is updated
lineto operates in a similar manner.
b
Adobe Confidential 18
a
Stroke
The moveto, lineto, arcto operators just define the path. It is added to the display list only when a
stroke operator is called.
PSStroke()
1. It determines whether the color space is patterned or not. If it is then the pattern is cached.
2. A call to Stroke( gs->path ) is made
3. If the path is a char path then a stroke path is created using StrkPath()
4. All kinds of paths which are not list paths are converted to list path
5. Then the stroke parameters are filled up by a call to PS2CurrentStrokeParams()
6. GetDevClipBBox() in viewclip.c returns the BBox for the current clip and and the view
clip
7. After all the path parameters have been set StrokeDevPath() is called which in turn calls
InnerStrokeDevPath()
8. The control passes from DPFinStroke() in devstroke.c to StdTrapsFilled() in graphmark.c
to HybridMark() in banddevmain.c where a Display List is created and marked.
9. The control then returns to PSStroke() where the memory for the path is freed.
10. The current point gs->cp is reinitialized to fpZero.
b
Adobe Confidential 19
a
Graphic Primitives
The graphic primitives are added to the Display List in form data in the NDLBuffer when we perform a
stroke.
PSStroke() StdInitMark()
StrokeDevPath()
creates a DevMaskMaker
InnerStrokeDevPath()
PreStroke()
devstroke.c
Sets stroke param, s->doing vectors,
s->dashed, s->strokeAdjustCase and then
sets the half width using setHalfWidth()
DPFinStroke()
graphmark.c
MarkDevPrim()
graphmark.c
If the path is
not empty
HybridMark()
banddevmain.c
Sets up the colorspace,
gs->colorspace->patterned then
get the pattern object
else setup using gs->color
BdMark()
banddevmain.c
NewDLResources()
banddevmain.c
DLCreate()
displaylist.c
Creates a new
DisplayList and
initializes the
PDLBandHeaders
BandBdMark()
banddevdlwalk.c
Walk proc
banddevdlwalk.c
This is the final step
where the data is added
to the NDLBuffer for
each band using macros
defined in display.h. The
data is piced upfrom
here during the
showpage
If no
DL
Store proc
displaylist.h
b
Adobe Confidential 20
a
Display List
A display list is an internal representation of the marks that have been painted on the current page or
previous pages but have not yet been scan-converted into raster memory. Display List for a page are processed
when it is time to print the page. Graphic elements are retrieved from the list and rendered into the framebuffer
storage for subsequent delivery to the printers imaging machinery.
Band
Page
Display List
PDLBandHeader
NDLBuffer NDLBuffer NDLBuffer
P
a
g
e

S
i
n
k

M
o
d
e
l
b
Adobe Confidential 21
a
Clipping
Clipping is limiting the drawing area by defining a definite boundary for the drawing to be done
in. In PS we can define a clipping path by building a path and using the clip operator. The new clipping
area will be the intersection of the constructed path and the existing clipping path. For. E.g.. Consider
defining a square area as the clipping path. On executing the clip operator the following actions are
performed.
Step 1. The PSClip function is called for the clip operator. This acts only as a wrapper and
calls CurrentGStateDoClip routine.
Step 2. The ReducePathClipInt calculates the bounding box of the current path
Step 3. The 2 bounding boxes are considered and the intersection is calculated as the new
clipping area.
Step 4. The clip path is calculated and updated into gs->clip which holds current clipping
information.
Step 5. When we stroke a path next, the point to be marked is tested for insideness w.r.t
the clipping boundary to decide whether to mark or not to mark.
b
Adobe Confidential 22
a
Fill Handling
The fill operator is handled in the following method.
Step 1. fill encountered, a call to PSFill in pathops.c is made
Step 2. If pattern filling is needed PatternFill is called, else Fill is called
Step 3. Fill calls FillDevPath in devpath.c and sends it current path and current marking
state
Step 4. This routine calls EnumerateDevPath to mark the path outline and then calls the
StdTrapsFilled routines in graphmark.c code to do the actual filling.
Step 5. After a fill, a newpath in performed.
Step 6. To evaluate whether a given point is inside or outside a path PS uses the winding
number rule or the even odd rule. The fill routine uses one of the algorithm to
check for insideness of a point
Step 7. In case of a pattern being used for filling, the pattern itself is first executed using
PatternFill, the filled pattern is cached and the Fill routine continues. The
MarkPattern routine does the actual pattern marking
Step 8. The presence or absence of a pattern is tested through a flag in the graphics state
gs.
b
Adobe Confidential 23
a
Fonts
PS supports various types of fonts like Type 0, Type 1, Type 2, Type 3, CID fonts,
TTF fonts ( Type 42 ) etc. The type of a font should be known for the code to be able to call the correct glyph
building procedures. The type is always encoded in the font dictionary under the FontType key.
The font always contains all glyph specific data like width, height, kerning data, side bearing etc.
Also encoded is the character outline as a sequence of co-ordinates w.r.t the font co-ordinate system. These
points define the outline of the font using lines and curves. The exact method depends on the font types. For e.g
TTF uses quadratic splines to store curve info while Type 1 font uses cubic splines. The below image shows an
example of a character outline and its contour point details
b
Adobe Confidential 24
a
Font Handling
Consider a generic example below. The required font has already been chosen at this point, we
will see how the show operator works in this case
> (hello world) show
Step 1. The string hello world is pushed onto the stack as a object of type string
Step 2. The show operator is implemented in PSShow in fontshow.c, it pops the string on
the stack and calls ShowInternal, the parameters for show are passed to it in a
ShowState structure
Step 3. The ShowInternal sets some necessary variables like currentpoint, type of show
etc.
Step 4. The next major function is FastBuildGlyph which calls the BuildGlyph function
based on the font type. i.e. If a type 1 font is being used it calls BuildGlyph1, for a
TTF font it calls BuildGlyph42. These font specific functions are defined in the
current font manager structure.
Step 5. The corresponding BuildGlyph function calls CallBC which is the main character
building routine.
Step 6. The CallBC routine makes use of the CallBCCharOutline or
CallBCCharBitmap depending on size of glyph to be rendered. These routines
perform the actual rendering.
Step 7. Once the character has been rendered, the current point is updated to the next
position using the character width information and the next character is taken for
processing.
The above steps form the basic font handling routines. All shows go through the CallBC routine,
and the ShowInternal in fontshow.c.
b
Adobe Confidential 25
a
Interpretation of Images
PS supports image rendering. In PS, images are specified using some basic properties like height,
width, color depth and the color values themselves are specified as a matrix of values of height x width.
To understand interepreteation of images let us assume that the PS interpreter meets a image operator
and all the necessary information are supplied to it. The following steps can summarize the interpretation
of the image.
Step 1. The top level function called on encountering the image operator is PSImage.
Step 2. The PSImage saves current graphics state using GSave and calls DoImage for
further processing
Step 3. DoImage pops the necessary information from stack, like height, width, matrix etc
and fills up the ImageObj structure, which is sent to ImageInternal routine.
Step 4. The ImageInternal routine runs a loop son imagerows until it becomes 0, each
time reading a slice of data through ReadSlices, and the data is stored in the
ImageObj structure.
Step 5. This image information is sent to the Mark routine for the final rendering. This
process continues for all imagerows.
b
Adobe Confidential 26
a
Showpage
The content of all the PS operators does not generate any printed output until a showpage is
performed. The PS interpreter holds are rendered data in display lists and only on occurrence of
showpage are these written to the output media. If a PS file has no showpage then, no output is
generated. The different steps that finally print the data are as follows
Step 1. When RIP meets a showpage operator, a the routine PSShowPage is called, this
routine is only a wrapper which calls PSShowPageInternal
Step 2. The PSShowPageInternal finds number of copies of output to be generated and
then calls CurrentGStateDoShowPage
Step 3. This routine retrieves the page feed information and checks if manual feed is on,
before calling the HybridShowPage
Step 4. HybridShowPage decides if color separation is needed, and it fills up the
necessary information for printing in the relevant structures and passes them to
PSPCHandoffPage
Step 5. The PSPCHandoffPage fills up the PrintPage structure and sends it to the
HandoffPage procedure in the PageSink object.
Step 6. The HandoffPage receives PageSink and repeatedly uses the RenderBand
callback routine in the PrintPage to render a band each time.
Step 7. The above steps are generic and varies for the product. In case of Camelot the
HandoffPage in campagecontrolST.c is called, and it is sent the PrintPage and
current PageSink instance.
Step 8. The HandoffPage uses the display list constructed to render data band by band.
For each band the WriteBand routine is called, which writes out data on standard
output. Here RenderBand is WriteBand
b
Adobe Confidential 27
a
Man Pages
Considering that most of our work is around PS, there is usually a need to find out about a
operator at some point. Its almost impossible to remember all the operators and their argumanets
and functions. What I suggest we make a set of man pages for instant reference. This can be of
great use to everybody working on PostScript.

You might also like