TweetFollow Us on Twitter

The Perils Of PostScript--The Sequel

The Perils Of PostScript--The Sequel


Developers are discovering the advantages of using PostScript ® dictionaries in applications, but along with the advantages come some perils. One peril awaits if you download a dictionary using PostScriptHandle. Another can trip you up after downloading a dictionary if you then download a font using the SetFont procedure I described in develop, Issue 1. How to avoid these perils? Read on to learn some tricks for dicts in picts.

More and more developers are beginning to use direct PostScript code in their applications. In my "Perils of PostScript" article in develop, Issue 1, I addressed a couple of problems that arise when you use PostScript code to print documents. In this sequel, we'll look at some problems you will encounter if you attempt to use PostScript dictionaries in your applications.


A PostScript dictionary is a collection of predefined variables and/or procedures. Using a PostScript dictionary can significantly reduce the size of the PostScript code generated by your application and make it more efficient. For instance, consider a large PostScript file in which the operatorcurrentpoint is used frequently. You can define in your dictionary a PostScript procedure called cp that makes a call to the currentpoint operator. You can then replace currentpoint with cp throughout the file, thus reducing its size. Similarly, by defining a PostScript procedure to represent a series of operators, you can express a compound operation much more efficiently. And storing procedures in a dictionary that you create can also prevent you from inadvertently redefining something that has already been defined.

One great example of a PostScript dictionary is the one used by the LaserWriter ® driver, variously called LaserPrep (after the file it resides in, at least until System 7), AppleDict (the Apple name for it), and good ol' md (the PostScript name for it, and the one I prefer to use). The LaserWriter driver generally uses one or more md

routines to perform a particular QuickDraw operation. (See the sidebar on the next page for a review of how the LaserWriter driver works.) For example, a call to the QuickDraw CopyBits routine is translated by the driver into a call to the db or cdb operators stored in md. As another example, during font downloading the LaserWriter driver uses bn and bu , both stored in md, to call save and restore ( bn calls save and bu calls restore).If you want to record a piece of PostScript code that references procedures contained in a dictionary, you must also record the dictionary. I describe how to download a dictionary, and how to avoid the pitfalls involved, in the next section.

Once your dictionary has been downloaded, you should be able to continue to reference it until the end of the job. But alas, this is not so, at least until the new printing architecture ships sometime after System 7. Under the current architecture, font downloading interferes with PostScript dictionaries. I discuss this problem and how to get around it under "The Perils of Font Downloading."


One of the easiest methods for downloading a PostScript dictionary is by using the PostScriptHandle picture comment. You can use this comment to download directly to the LaserWriter a block of PostScript code stored in a handle. (See Technical Note #91, Optimizing for the LaserWriter--PicComments, for more information.) When you use the PostScriptHandle comment, you must insert the PostScriptBegin and PostScriptEndpicture comments around the block of PostScript code you are trying to download, like this:

PicComment(PostScriptBegin, 0, NIL);
(*** Your PostScript representation of document goes here.***)
PicComment(PostScriptHandle, size, handle);
(*** Your QuickDraw representation of document goes here.***)
PicComment(PostScriptEnd, 0, NIL);

As described in my first article, the PostScriptBegin/Endcomments are markers that ensure that the right piece of code will execute on the right device. When the LaserWriter driver sees PostScriptBegin, it ignores all QuickDraw drawing calls and just executes picture comments. When a PostScriptEndis received, the LaserWriter driver will once again interpret QuickDraw calls. So when printing to a LaserWriter printer, only the picture comments are executed, while the QuickDraw code between PostScriptBeginand PostScriptEnd is ignored. But PostScriptBegin and PostScriptEnd also save and restore at least part of the state of the device, which can cause problems for your dictionary. To avoid this, you should use the picture comment PostScriptBeginNoSave (comment kind = 196) to prevent the save and restore from occurring, like this:

(*** Your definition of the dictionary goes here.***)

PicComment(PostScriptBeginNoSave, 0, NIL);
PicComment(PostScriptHandle, dictsize, dicthandle);
PicComment(PostScriptEnd, 0, NIL);
(*** Now you send the document. ***)

PicComment(PostScriptBegin, 0 NIL);
(*** Your PostScript representation of document goes here.***)
PicComment(PostScriptHandle, size, handle);
(*** Your QuickDraw representation of document goes here.***)
PicComment(PostScriptEnd, 0, NIL);

If you don't need to export your dictionary into picture files, you can get the LaserWriter driver to auto-download your dictionary by keeping the dictionary code in a PREC(103) resource. After the LaserWriter has saved its state, it does a blind GetResource (that is, from any open resource file) on PREC(103). If one is found, it is downloaded to the printer after the md dictionary, and before the job. You can use this method of downloading for dictionaries that are used only to contain state information about the current job. (When a graphic is copied onto the clipboard, only the state information, not the entire dictionary, is required for the code to execute.)

However, use of the PREC(103) resource does have some limitations. It only works at print time, and there can be only one. That is, the LaserWriter driver does not attempt to download all the PREC(103) resources in all the open resource files. The first one it finds wins. (This method of downloading dictionaries is documented in Technical Note #192, Surprises in LaserWriter 5.2 and Newer.)


In my "Perils of PostScript" article in Issue 1 of develop, I showed a small procedure called SetFont that downloaded a font using QuickDraw, while maintaining the ability to reference that font using PostScript. The problem with that method is that the process of font downloading executes the PostScript restore operator. This operator restores the state of the printer to a state that was saved before your dictionary was defined. Because of this, any reference to your dictionary is lost.

Another way to understand what happens in this case is to look at what the LaserWriter driver does during printing. At the start of a print job, the LaserWriter driver configures the LaserWriter's graphics state to look more like QuickDraw. This includes moving the origin (0,0) from the bottom left (PostScript style) to the top left (QuickDraw style), and setting the default resolution to 72 dpi. After the driver has configured the printer, it performs a save, which saves the complete state of the device. The driver then begins downloading the rest of the job, containing the PostScript code generated by the LaserWriter as well as any additional PostScript code sent by the application.

The LaserWriter driver fully restores the state of the device, by executing the PostScript restore operator, before downloading a font. During font downloading, the characters of the font are actually defined, sometimes using normal PostScript drawing operators. Because of this, the LaserWriter driver restores the state of the printer before defining the characters. Once the characters have been defined, the state is saved again. This way, the LaserWriter driver can assume it knows the state of the device. Since the state saved by the LaserWriter driver does not contain any of the symbols defined by the application, all of them are lost after any attempt to download a font.

Now that we understand the problem, let's discuss potential solutions. The restore operator affects everything that has changed except two areas: some of the PostScript stacks (specifically the operand, dict, and execution stacks), and the contents of PostScript strings. This suggests that to save small units of information, you can simply push them onto the stack, or convert them and store them as PostScript strings.

Unfortunately, it's not quite that easy.

PostScript makes a distinction between simple and composite objects. Simple objects (like numerical values and booleans) contain their value within the object. Composite objects (like strings, procedures, and dictionaries) contain only a pointer to the real data, which is stored elsewhere in PostScript Virtual Memory. Simple objects on the stack are indeed preserved across a restore, but if there are composite objects on the stack that are new (that is, newer than the state being restored), an invalidrestore error is generated. If your dictionary only contains simple objects, then you can indeed push each of the variables defined in the dictionary onto the stack separately and rebuild the dictionary after the restore. The overhead here is obviously enormous, though, and most useful dictionaries contain procedures and/or strings, rendering this technique useless.

In the case of strings being preserved across a restore, let me quote from the PostScript Language Reference Manual , p. 44: "In the current PostScript design, restore actually does not undo changes made to the elements of strings. We consider this behavior to be a defect, and do not recommend that PostScript programs take advantage of it." Beyond this easily ignored admonishment, though, is another problem. The strings in question must be preexisting: strings you create just before the restore will, of course, be destroyed by the restore, or, if they are on the stack, will cause an error. You could probably find some scratch strings in one of the standard dictionaries to use, but this is not recommended, for obvious reasons.

Another way to solve the problem would be to redefine save and restore to not do anything. This way, font downloading would not cause the state to be restored. This would make the application developer responsible for preserving the state, which is easily done using other PostScript operators. But unfortunately, the definitions of save and restore cannot be changed without exiting the server loop. That is, you cannot override their definitions from within a job. Because of this, you have to fall back on plan B: override the operators that call save and restore. In the case of font downloading, these operators are bn and bu, as mentioned earlier.

This method is the most widely used solution to our problem, has the fewest limitations, and is the method recommended here. Please note, however, that tinkering with md operators outside of this specific use is strongly discouraged. (See the sidebar on the next page.)

The main job of bu and bn is to preserve the state of the PostScript device. As long as your PostScript code preserves the state, these calls aren't even required. In the fragment that follows, we first create our own dictionary, called mydict, with room for ten symbols, although we don't define them all. Next we define killbu. killbu is responsible for first saving the old definition of the buroutine, and then setting its value to the empty procedure ( {}), which does nothing. The original definition of bu is simply pushed onto the stack. Next we write a routine restorebu, to restore the definition of bu when we are through. This routine is responsible for popping the original value off the stack and storing it back into the bu symbol; it assumes that the definition of bu is on the top of the stack. Then we define two similar routines, killbn and restorebn, which take care of the bn operator. Finally, we define a fun little routine to call to make sure our dictionary is actually being preserved after font downloading. We call this one titleshow. So now we have a dictionary, all ready to use.

SendPostScript('/mydict 10 dict def');
SendPostScript('mydict begin');
SendPostScript('/killbu {//md /bu get //md /bu {} put} def');
SendPostScript('/restorebu {//md exch /bu exch put} def');
SendPostScript('/killbn {//md /bn get //md /bn {} put} def');
SendPostScript('/restorebn {//md exch /bn exch put} def');
SendPostScript('/titleshow {dup gsave');
SendPostScript('currentscreen 3 -1 roll pop 120 3 1 roll setscreen');
SendPostScript('.5 setgray show grestore true charpath gsave');
SendPostScript('1 setlinewidth 0 setgray stroke grestore');
SendPostScript('.5 setlinewidth 1 setgray stroke }def');

Okay, now that we have the routines for killing bu and bn, we need to call them. It's very important at this point to check for their existence before attempting to alter their definitions. This is because, as mentioned earlier, the new printing architecture that will ship sometime after System 7 will handle font downloading differently. The bu and bn operators will no longer exist; in fact, it's not clear that the md dictionary will still exist. The following PostScript commands check for the existence of both the dictionary and the symbol. If they don't exist, our code assumes it is running under the new printing architecture, and does nothing to insulate the dictionary. The code fragment executes fine on LaserWriter drivers up to and including System 7.0. It has also been tested in both foreground and background. Considering the future of bn and bu, it is very likely that this code will continue to work even under the new printing architecture. Here, then, is the code to check for and kill bn and bu:

SendPostScript('mydict begin');
SendPostScript('//md /bu known {killbu} if');
SendPostScript('//md /bn known {killbn} if');

Pretty straightforward: if the routine exists, call the correct routine to kill it. The most important thing to note here is the order of the routines. Since killbuand killbnpush things onto the stack, restorebu and restorebnmust be called in opposite order to get the correct results. So after the job is finished, we call:

SendPostScript('mydict begin');
SendPostScript('//md /bn known {restorebn} if');
SendPostScript('//md /bu known {restorebu} if');


PostScript dictionaries are useful because they can significantly reduce the size of the PostScript code generated by your application, and can be exported into pictures. Perhaps the easiest way to record PostScript into a picture is by using the PostScriptHandlepicture comment. In this case, remember to use the PostScript BeginNoSave comment to prevent PostScriptBegin and PostScriptEnd from saving and restoring at least part of the state of the device, which can cause problems for your dictionary. To prevent font downloading from interfering with your PostScript dictionaries, you can override bn and bu, the PostScript operators that call save and restore. Outside of this solution, you should absolutely avoid using md operators.

The code included in the Perils of PS II folder on the Developer Essentials disc is basically the same code that has been shown here, rolled into an application shell that opens and initializes the Printing Manager. Also included is the definition of the SendPostScriptprocedure referenced in this article.


The LaserWriter driver is a complex piece of software that handles communications between an application and the LaserWriter printer. To print a document, the application opens the Printing Manager, which in turn loads and initializes the LaserWriter driver. The application then makes standard QuickDraw calls similar to those used to render the document on the screen. The LaserWriter driver intercepts these calls and converts them into the equivalent PostScript code for rendering the document on the LaserWriter printer.

(See Figure 1.) In some cases, one QuickDraw operation translates into one PostScript operation, but more frequently, the QuickDraw operation translates into several PostScript operations. To abbreviate these operations, the LaserWriter driver stores them as procedures in a PostScript dictionary.

When the LaserWriter driver first connects to the LaserWriter printer, it checks to see if its dictionary exists and if the version of the dictionary matches the version of the driver being used. If not, it downloads the correct dictionary before proceeding. (This is what the message "initializing printer" means when you print for the first time after turning on the printer.)

Once the correct dictionary is in place, the job of translation becomes much easier. Each QuickDraw operation now becomes one line of PostScript code, referencing a procedure defined by the dictionary. Complex QuickDraw operations (like font downloading) still require many lines of PostScript code, but in general, the translation is one for one. Since the QuickDraw code is translated rather than rendered, the LaserWriter driver doesn't need to spool the data to disk. Instead, each operation is translated and sent to the printer as it is received.

[IMAGE postscript1.GIF]

Figure 1 How the LaserWriter Driver Works


Many developers have started to call md routines from within the PostScript code generated by their applications. This is dangerous, for a number of reasons.

The first is that the md dictionary is defined and maintained by the LaserWriter driver. This means that it is always subject to change, and code that depends on the md dictionary must be version dependent. This is possible, but far from elegant.

Another problem with using md operators is that they may not work the same way on all devices. Remember that the LaserWriter driver is used to drive a lot more devices than just an Apple LaserWriter.

Use of md operators has already led to compatibility problems with major applications, and most developers have realized the danger in using them. The easiest way to avoid problems with these routines is to not call them. If you really need the functionality of a particular md operator, simply redefine it in your own dictionary. Using tools like LaserTalk (formerly from Emerald City Software, now from Adobe), you can "disassemble" md operators back to their PostScript primitives. You can then redefine them using a different name in your own dictionary. Now you have a routine that does exactly what the md routine did, but you remain in control of its definition. Most of the md operators are very small, so the storage penalty of redefining them in your own dictionary is minimal.

Now that I've warned you, I'm going to show you how to tinker with two operators stored in md: bn and bu. All routines, including these two, are subject to change; by special arrangement with engineering, bn and bu will change in a compatible way, but this isnot true for any of the other routines defined in md. This article shows a specific use of bn and bu, and checks for their existence before attempting to access them. This is not meant to endorse other uses of these or any other md routines.

SCOTT "ZZ" ZIMMERMAN is a DTS printing guru. After two and a half years at Apple he says he's particularly impressed with the strictly enforced dress code. In his spare time he sails, scuba dives for lobsters, and plays the piano, guitar, and saxophone. Zz has a penchant for pets. His doorway is adorned by a melted gummy rat, a good luck charm left over from his Intel days. At home, atop his monitor is perched a rare Asian black scorpion (behind glass, we hope). His other cuddly pets include two geckos and a lovable iguana. *

The definitive references on the PostScript language are the PostScript Language Reference Manual (Addison- Wesley, 1985, available from APDA--#T0182LL/A), the PostScript Language Tutorial and Cookbook (Addison-Wesley, 1985), and PostScript Language Program Design (Addison-Wesley, 1988). *

Thanks to Our Technical Reviewers Pete "Luke" Alexander, Jay Patel, David Williams*


Community Search:
MacTech Search:

Software Updates via MacUpdate

Monosnap 3.4.11 - Versatile screenshot u...
Monosnap lets you capture screenshots, share files, and record video and .gifs! Features Capture Capture full screen, just part of the screen, or a selected window Make your crop area pixel... Read more
Yummy FTP Pro 2.0.3 - $29.99
Yummy FTP Pro is an advanced Mac file transfer app which provides a full-featured professional toolkit combined with blazing speeds and impeccable reliability, so whether you want to transfer a few... Read more
Smultron 10.1.3 - Easy-to-use, powerful...
Smultron 10 is an elegant and powerful text editor that is easy to use. You can use Smultron 10 to create or edit any text document. Everything from a web page, a note or a script to any single piece... Read more
Time Out 2.4 - Break reminder tool with...
Time Out helps remind you to take work breaks throughout the day. It has two kinds of breaks: a "Normal" break, typically for 10 minutes after 50 minutes of work, so you can move about and relax,... Read more
Iridient Developer 3.2.2 - Powerful imag...
Iridient Developer (was RAW Developer) is a powerful image-conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more
DesktopLyrics 2.6.13 - Displays current...
DesktopLyrics is an application that displays the lyrics of the song currently playing in "iTunes" right on your desktop. The lyrics for the song have to be set in iTunes; DesktopLyrics does nothing... Read more
BusyContacts 1.2.8 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
iClock 4.2.5 - Customizable menu bar clo...
iClock replaces the old Apple's default menu bar clock with more features, customization and increases your productivity. Features: Have your Apple or Google calendar instantly available from the... Read more
Dropbox 45.4.92 - Cloud backup and synch...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keeps them up-to-date between systems... Read more
MacFamilyTree 8.3.4 - Create and explore...
MacFamilyTree gives genealogy a facelift: modern, interactive, convenient and fast. Explore your family tree and your family history in a way generations of chroniclers before you would have loved.... Read more

Latest Forum Discussions

See All

How PUBG, Fortnite, and the battle royal...
The history of the battle royale genre isn't a long one. While the nascent parts of the experience have existed ever since players first started killing one another online, it's really only in the past six years that the genre has coalesced into... | Read more »
Around the Empire: What have you missed...
Oh hi nice reader, and thanks for popping in to check out our weekly round-up of all the stuff that you might have missed across the Steel Media network. Yeah, that's right, it's a big ol' network. Obviously 148Apps is the best, but there are some... | Read more »
All the best games on sale for iPhone an...
It might not have been the greatest week for new releases on the App Store, but don't let that get you down, because there are some truly incredible games on sale for iPhone and iPad right now. Seriously, you could buy anything on this list and I... | Read more »
Everything You Need to Know About The Fo...
In just over a week, Epic Games has made a flurry of announcements. First, they revealed that Fortnite—their ultra-popular PUBG competitor—is coming to mobile. This was followed by brief sign-up period for interested beta testers before sending out... | Read more »
The best games that came out for iPhone...
It's not been the best week for games on the App Store. There are a few decent ones here and there, but nothing that's really going to make you throw down what you're doing and run to the nearest WiFi hotspot in order to download it. That's not to... | Read more »
Death Coming (Games)
Death Coming Device: iOS Universal Category: Games Price: $1.99, Version: (iTunes) Description: --- Background Story ---You Died. Pure and simple, but death was not the end. You have become an agent of Death: a... | Read more »
Hints, tips, and tricks for Empires and...
Empires and Puzzles is a slick match-stuff RPG that mixes in a bunch of city-building aspects to keep things fresh. And it's currently the Game of the Day over on the App Store. So, if you're picking it up for the first time today, we thought it'd... | Read more »
What You Need to Know About Sam Barlow’s...
Sam Barlow’s follow up to Her Story is #WarGames, an interactive video series that reimagines the 1983 film WarGames in a more present day context. It’s not exactly a game, but it’s definitely still interesting. Here are the top things you should... | Read more »
Pixel Plex Guide - How to Build Better T...
Pixel Plex is the latest city builder that has come to the App Store, and it takes a pretty different tact than the ones that came before it. Instead of being in charge of your own city by yourself, you have to work together with other players to... | Read more »
Fortnite Will Be Better Than PUBG on Mob...
Before last week, if you asked me which game I prefer between Fortnite Battle Royale and PlayerUnknown’s Battlegrounds (PUBG), I’d choose the latter just about 100% of the time. Now that we know that both games are primed to hit our mobile screens... | Read more »

Price Scanner via

Sale of the year continues as Apple resellers...
Adorama has new 2017 15″ MacBook Pros on sale for $250-$300 off MSRP. Shipping is free, and Adorama charges sales tax in NJ and NY only: – 15″ 2.8GHz Touch Bar MacBook Pro Space Gray (MPTR2LL/A): $... Read more
Sunday Sales: $200 off 13″ Touch Bar MacBook...
Amazon has new 2017 13″ 3.1GHz Touch Bar MacBook Pros on sale this weekend for $200 off MSRP, each including free shipping: – 13″ 3.1GHz/256GB Space Gray MacBook Pro (MPXV2LL/A): $1599.99 $200 off... Read more
B&H drops prices on 15″ MacBook Pros up t...
B&H Photo has dropped prices on new 2017 15″ MacBook Pros, now up to $300 off MSRP and matching Adorama’s price drop yesterday. Shipping is free, and B&H charges sales tax for NY & NJ... Read more
Apple restocks Certified Refurbished 2017 13″...
Apple has restocked Certified Refurbished 2017 13″ 2.3GHz MacBook Pros for $200-$230 off MSRP. A standard Apple one-year warranty is included with each MacBook, models receive new outer cases, and... Read more
13″ Space Gray Touch Bar MacBook Pros on sale...
Adorama has new 2017 13″ Space Gray Touch Bar MacBook Pros on sale for $150 off MSRP. Shipping is free, and Adorama charges sales tax in NY & NJ only: – 13″ 3.1GHz/256GB Space Gray MacBook Pro (... Read more
Best deal of the year on 15″ Apple MacBook Pr...
Adorama has New 2017 15″ MacBook Pros on sale for up to $300 off MSRP. Shipping is free, and Adorama charges sales tax in NJ and NY only: – 15″ 2.8GHz Touch Bar MacBook Pro Space Gray (MPTR2LL/A): $... Read more
Save $100-$150+ on 13″ Touch Bar MacBook Pros...
B&H Photo has 13″ Touch Bar MacBook Pros on sale for $100-$150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13″ 3.1GHz/256GB Space Gray MacBook Pro... Read more
Current deals on 27″ Apple iMacs, models up t...
B&H Photo has 27″ iMacs on sale for up to $150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 27″ 3.8GHz iMac (MNED2LL/A): $2149 $150 off MSRP – 27″ 3... Read more
Thursday Deal: 13″ 2.3GHz MacBook Pro for $11...
B&H Photo has the 13″ 2.3GHz/128GB Space Gray MacBook Pro on sale for $100 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz/128GB Space... Read more
How to save $100-$190 on 10″ & 12″ iPad P...
Apple is now offering Certified Refurbished 2017 10″ and 12″ iPad Pros for $100-$190 off MSRP, depending on the model. An Apple one-year warranty is included with each model, and shipping is free: –... Read more

Jobs Board

Firmware Engineer - *Apple* Accessories - A...
# Firmware Engineer - Apple Accessories Job Number: 113452350 Santa Clara Valley, California, United States Posted: 28-Feb-2018 Weekly Hours: 40.00 **Job Summary** Read more
Automation and Performance Engineer, *Apple*...
# Automation and Performance Engineer, Apple Pay Job Number: 113557967 Santa Clara Valley, California, United States Posted: 09-Mar-2018 Weekly Hours: 40.00 **Job Read more
Hardware Systems Architect - *Apple* Watch...
# Hardware Systems Architect - Apple Watch Job Number: 113565323 Santa Clara Valley, California, United States Posted: 05-Mar-2018 Weekly Hours: 40.00 **Job Read more
Lead *Apple* Solution Consultant - Apple (U...
# Lead Apple Solution Consultant Chicago IL Job Number: 113560644 Chicago, Illinois, United States Posted: 10-Mar-2018 Weekly Hours: 40.00 **Job Summary** As a Lead Read more
Art Director, *Apple* Music + Beats1 Market...
# Art Director, Apple Music + Beats1 Marketing Design Job Number: 113258081 Culver City, California, United States Posted: 07-Mar-2018 Weekly Hours: 40.00 **Job Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.