The previous article, Preparing EPS file for use in VDP, introduced the EPS file format, and covered the basics of working with EPS files in your VDP workflow.
Often, a particular EPS file will be used repeatedly within a PostScript job. An example might be a repeated logo, a page background, or a form layout.
Ideally, such a repeated image should only be processed (RIP-ped) once. PostScript provides image caching natively, using a structure called the "Form Dictionary". This articles details how to perform image caching using EPS files.
PostScript provides the "Form Dictionary" structure for reusable content caching. The basic structure is as follows:
/FormName
<< /FormType 1
/BBox [0 0 612 792]
/Matrix [1 0 0 1 0 0]
/PaintProc
{ pop
% some procedure to draw the "form"
} bind
>> def
Every Form has a FormType of "1". Presumably Adobe will expand this in the future. The BBox entry corresponds to dimensions of your image. In many cases this is the entire page, as in my example. If your image covers a smaller area, you can use the coordinates found in the %%BoundingBox comment of the EPS itself.
The "Matrix" entry provides a mechanism for changing the position, scale, and/or skew of the image. I find it much easier to use the PostScript translate, rotate and scale operators for this. The values shown, 1 0 0 1 0 0, leave the size/position unchanged (this is often called the "identity matrix").
The heart of the Form Dictionary is the PaintProc. This is where your drawing/image data goes. You can put any PostScript code you like in the PaintProc (it doesn't have to be an EPS or an image). Note that the first thing the PaintProc contains is the "pop" operator. The form mechanism puts a copy of the Form Dictionary on the stack prior to running the PaintProc. It is rarely needed, so, we throw it away with "pop".
In the previous article, I showed you the "run" operator and how to use an EPS image in your programs. You could in fact drop that code directly into your PaintProc:
/FormName
<< /FormType 1
/BBox [0 0 612 792]
/Matrix [1 0 0 1 0 0]
/PaintProc
{ pop
save
/showpage {} def
/setpagedevice /pop load def
522 702 translate
.75 .75 scale
(c:/vdp/samples/tg_logo.eps) run
restore
} bind
>> def
This is perfectly fine if your workflow allows you to refer to files on a hard drive in this manner. This isn't always an option. Many times, you'll want to completely embed the EPS in your PostScript file. Your workflow might require you to submit a completely self-contained PostScript file to your output device.
If we want to embed our EPS though, we can't just copy the EPS into the /PaintProc. This is because of the way PostScript "tokenizes" procedures (Notice that "PaintProc" is a procedure). It will try to turn the contents of the EPS, including any image data, into valid PostScript tokens. When these get executed, you'll get errors, because binary or hex-encoded image data are not valid PostScript operators.
We have to use a little bit of misdirection. The solution comes via the ReusableStreamDecode filter.
PostScript Filters are used to create file objects from other file objects or strings. As the name implies, the filter object "filters" and/or encodes/decodes one file format into another. An example might be to decode a hex-encoded file into binary format.
The ReusableStreamDecode filter actually does no filtering at all! But the key point is that it can take a string or procedure and "turn it into" a File object. That file object can be used in our Form dictionary's PaintProc.
The Form Dictionary might look like this:
/IDForm
<< /FormType 1
/BBox [154 321 441 521]
/Matrix [ 1 0 0 1 0 0]
/PaintProc
{ pop
/ostate save def
/showpage {} def
/setpagedevice /pop load def
ImageData 0 setfileposition ImageData cvx exec
ostate restore
} bind
>> def
Notice the BBox entry. Take that directly out of your EPS file. The PaintProc first does a pop, this is to remove the copy of the Form dictionary that gets put there as an artifact of how forms work. Next you see the standard "EPS housekeeping" statements.
The magic happens with "ImageData 0 setfileposition ImageData cvx exec". ImageData is a file we created with the ReusableStreamDecode filter. We first set it back to the start. Then we put the file on the stack, change it to executable with the cvx operator, and execute it.
To draw this logo or image, we simply perform "IDForm execform" wherever we want the EPS to draw. "execform" is the operator to actually draw or "execute" a given form.
Precede that statement with appropriate save, scale, and translate operators, and of course match your save with a restore. So far so good, but where does the "ImageData" file come from?
To create your file object, simply copy the EPS in its entirety into the very top of your PostScript program. We'll precede it with code that uses the ReusableStreamDecode filter to turn it into a file:
/ImageData currentfile << /Filter /SubFileDecode /DecodeParms << /EODCount 0 /EODString (*EOD*) >> >> /ReusableStreamDecode filter
Next would come our complete EPS. After the EPS code, complete the file definition with:
*EOD* def
Notice the "*EOD*". This can be any string at all. We're telling the ReusableStreamDecode filter to stop when it encounters that string. Then the def, to associate the filtered file object with the /ImageData definition.
That completes the file definition.
We're telling the program that "/ImageData" is defined as the current contents of the program (currentfile), ran through the ReusableStreamDecode filter, up to the string *EOD*. The net effect is that we've turned that EPS into a file in memory named "ImageData".
Here's a completed definition:
%!PS
/ImageData
currentfile
<< /Filter /SubFileDecode
/DecodeParms << /EODCount 0 /EODString (*EOD*) >>
>> /ReusableStreamDecode filter
%% ommitted EPS, could be hundreds of lines!
*EOD*
def
/IDForm
<< /FormType 1
/BBox [0 0 612 792]
/Matrix [ 1 0 0 1 0 0]
/PaintProc
{ pop
/ostate save def
/showpage {} def
/setpagedevice /pop load def
ImageData 0 setfileposition ImageData cvx exec
ostate restore
} bind
>> def
Again, this goes at the top of your program. It embeds the EPS in your program, and also turns it into a file object. That file object is then used inside of a Form Dictionary. Objects in a Form Dictionary are processed ONCE, and then cached.
To use your Form in a program, simply use the "execform" operator, which paints the cached image onto your page.
% Page 1 save 10 500 translate % position to paint the image .5 .5 scale % scale if necessary IDForm execform % draw the cached image restore % rest of the page showpage % Page 2 save 10 500 translate .5 .5 scale IDForm execform restore % rest of the page showpage
Thomas D. Greer has years of experience in the printing business. He held the position of Director of Development for Consolidated Graphics, where he wrote the COIN eCommerce platform. Prior to that he was Vice-President of Technology of a large printing company acquired by Consolidated Graphics, where he was responsible for the development of a completely custom-written plant management system still in use.
Today Thomas provides consulting, development, implementation, and training services to commercial printers. He can be reached on the web at www.tgreer.com.
Perhaps you'd like to read some other technical articles I've written?
If you'd like to discuss this article, or make suggestions for future articles, join my free discussion forum.
My logo was designed by Rus Anderson, a skilled graphic artist with a wealth of experience in user interface and web design. I told Rus I wanted something simple and clean, that conveyed my expertise in document automation technologies. I also wanted an association with PostScript and PDF. I'm very pleased with the result. The "document icon" has become ubiquitous. It's obvious, when viewing the logo, that I'm involved in document production and automation. The red color is associated with Adobe, PostScript, and PDF. Overall, the effect is clean and memorable. Thanks, Rus!