Subject: 7 Programming in PostScript Subject: 7.1 What is PostScript level 2? (See the Section 11, ``About PostScript 2''.) Subject: 7.2 Should I learn level 2 PostScript? Yes, because Level Two will soon become the standard. Application developers using PostScript need to become aware of the new capabilities and how to take advantage of them. There are many good books on PostScript 2. (See Section 5, ``Books''.) Subject: 7.3 Where can I find examples of PostScript code? Many other books on PostScript make example PostScript code available. ``Thinking in PostScript'', by Glenn Reid, is the only book I know of that allows its examples to be freely distributed. (See Section 5, ``Books''.) All the examples in ``the blue book'' are available from the Adobe file server (See Section 5, ``Books''.) See the question ``How can I browse through PostScript programs?'' in the comp.sources.postscript FAQ. Subject: 7.4 How do I get the physical size of a page? The initial clipping path gives you the size of the imagable area. Use ``clippath pathbbox'' to get these coordinates. If you must know the size of the device's imageable area, use the sequence ``gsave initclip clippath pathbbox grestore'', but this will prevent an enclosing application from using the clippath to achieve some special effects (such as multiple pages per page). Subject: 7.5 Why can't I do a pathforall after a charpath ? (See Section 4, ``Fonts'', question ``Why are Adobe fonts hidden?''.) Subject: 7.6 How do I center a string of text around a point? Level 1 PostScript has two operators that can extract information about the metrics of characters: ``stringwidth'' and ``charpath''. The ``stringwidth'' operator returns the advance width of its string operand. This is the distance the current point would be moved by a ``show'' operation on the same string. ``stringwidth'' returns two numbers on the stack, representing the x and y components of the advance width. Usually the y component is zero because most fonts are displayed along a horizontal line, moving the current point only in the x direction. Also note that the ``stringwidth'' usually does not give an exact measure of the area of the page that will be touched by its operand. The letters can either project a little over the boundaries or fall a little within (leaving a touch of whitespace). If all that an application requires is horizontal centering of a long string of text, the result returned by ``stringwidth'' is sufficient. A common technique is x y moveto (string) dup stringwidth pop 2 div neg 0 rmoveto show (This code makes the assumption that the y component of advance width is irrelevant.) The ``charpath'' operator extracts the graphic shapes of its string operand and appends them to the current path in the graphic state. These shapes can then be processed by other PostScript operators. To get the actual size of the area touched by a character a simple approach is gsave newpath 0 0 moveto (X) false charpath flattenpath pathbbox grestore This code places four numbers on the stack, representing the coordinates of the lower left and upper right corners of the bounding box enclosing the character ``X'' rendered with the current point at (0,0). Leaving the flattenpath out will cause it to be less accurate, but it will take up less memory and be faster. There are two things to be careful about when using the code shown above: 1. There are severe limits on the size of the string operand, related to the limit on the number of elements in a graphic path. The PostScript Language Reference Manual recommends taking ``charpath''s one character at a time. 2. If user space is rotated or skewed with respect to device space, the result from ``pathbbox'' may be larger than expected; ``pathbbox'' returns a rectangle oriented along the user space coordinate axes, which fully encloses a (possibly smaller) rectangle oriented along the coordinate axes of device space. If user space is rotated at an integer multiple of 90 degrees these two rectangles will be the same, otherwise the rectangle in user space will be larger. So, to center text vertically one must get the bounding boxes of all the characters in the string to be displayed, find the minimum and maximum y coordinate values, and use half the distance between them to displace the text vertically. This still may not do a very good job, since this provides centering based on extrema, not on the optical center of the string (which is more related to a sort of ``center of mass'' of the text). If an application does this repeatedly, it would be wise to store the bounding boxes in an array indexed by character code, since ``charpath'' is a slow operation. Font metric information is available outside of a PostScript printer in font metrics files, available from the font vendor. A program generating PostScript output can obtain metrics from these files rather than extracting the metrics in the printer. Subject: 7.7 How can I concatenate two strings together? %% string1 string2 append string % Function: Concatenates two strings together. /append { 2 copy length exch length add % find the length of the new. string dup % string1 string2 string string 4 2 roll % string string string1 string2 2 index 0 3 index % string string string1 string2 string 0 string1 putinterval % stuff the first string in. % string string string1 string2 exch length exch putinterval } bind def Subject: 7.8 What do I do when I get stack overflow/underflow? These errors are among the most common in PostScript. When I get a stack overflow, that is usually a sign that a routine is leaving an object on the stack. If this routine gets called 2000 times, it leaves 2000 objects on the stack, which is too many. When I get a stack underflow, that is a sign that either: (A) one of the routines in the program doesn't work, and never has or (B) one of the routines in the program works, but expects to be called with some arguments left on the stack. There is no such thing as a PostScript debugger right now. For now, the best that you can do to debug your program is to put in lots of print statements. Learn to use the PostScript pstack command, and use an online interpreter so you don't have to run to the printer for each debugging cycle. Use an error handler to learn more about what exactly is happening when your program crashes. (see the comp.sources.postscript FAQ for a list of all PostScript related programs.) If your code has never worked yet (i.e. you are still writing it) then I find that it helps to put little comments in the margin about the state of the stack. Like this: Heart pathbbox % lowerx lowery upperx uppery exch 4 -1 roll % lowery uppery upperx lowerx I generally put these comments in originally, and then take them out when the program works. Maybe this is a bad practice, in case I ever want to go back and look at the code to modify it!! Subject: 7.9 How can I print in landscape mode? Landscape (the opposite of portrait) means that the page is turned on its side. You can redefine showpage in terms of the current definition of showpage. Do something like: /oldshowpage /showpage load def 90 rotate llx neg ury neg translate % for the first page /showpage { oldshowpage 90 rotate llx neg ury neg translate } def This won't work if the PostScript file you're editing uses initgraphics or grestoreall.