tinkelman@ccavax.camb.com (08/14/90)
A week or so ago, I responded to a comp.lang.postscript posting, saying something like: ``Printing every other page of a PostScript document? That shouldn't be hard. I'll just write a showpage-replacement that'll eat every other page. It should work with any (well almost any) PostScript file...'' (Me and my big mouth!) So, I eventually got around to writing it. It wasn't too hard, and it worked on my own handwritten PostScript. [Usual comments apply here about debugging == `training it to work on the test data'.] It worked on the PostScript produced by the program (PSPRINT) we use to convert TeX DVI files into PostScript. It even layered on top of DEC's ScriptPrinter software, eg. using PARAM=NUMBER_UP=2 (though the utility of this is questionable). So far so good. I even mailed it out to a few people who had sent me mail-requests. So much for the good news. Now for the bad news. It worked with almost no other program-produced PostScript that I've tried since. I looked around our system for PostScript files that had been produced by various packages, some of which we don't run here. Without exception, they have all implemented `next page' in a way that thwarts many types of showpage-layering. I've appended some excerpts. I'll also append my odd.ps file (as it's pretty short). But beware, from my testing it very well might not work with your PostScript. Now my request to the net: Am I doing something dumb? Are the programs that produced the attached PostScript doing something bad? Do the Adobe specs/guidelines cover this area explicitly enough to say? And, if you do happen to try the attached every-other-page code, I would appreciate mail reporting the results. Thanks. -- Bob Tinkelman, Cambridge Computer Associates, Inc., 212-425-5830 bob@camb.com or ...!{uupsi,uunet}!camb.com!bob -------------------------------------------------------------------------------- %%%%%%%%%% The following lines excerpted from eroff output %%%%%%%%%% %%%%%%%%%% The sequence save-...-showpage-restore defeats %%%%%%%%%% %%%%%%%%%% any layered showpage which wants to retain state. %%%%%%%%%% %%Creator: user@host with Eroff/eps release 2.2C %[lots of stuff deleted] %[The following is at the page break between pages 1 and 2; others are similar] showpage PageState8620 restore %%PageFonts: Times-Bold Times-Roman Helvetica Symbol %%Page: label 2 %%PageFonts: (atend) /PageState8620 save def %%%%%%%%%% The following lines excerpted from psprint output %%%%%%%%%% %%%%%%%%%% The sequence showpage-save-...-restore allows a %%%%%%%%%% %%%%%%%%%% layering of a showpage with retained state, but %%%%%%%%%% %%%%%%%%%% the `initgraphics' seems scary. %%%%%%%%%% /@bop1 % begin setting DVI page n { pop % throw away page number initgraphics % start with a clean slate mtrx setmatrix % switch to our TeX coordinate system /prepageVM save def % save state of VM at start of page } def /@eop % end DVI page n { pop % throw away page number prepageVM restore % restore VM to state at start of page showpage } def %[lots of stuff deleted] @eop 2 @bop0 2 @bop1 %%%%%%%%%% The following lines excerpted from softquad troff output %%%%%%%%%% %%%%%%%%%% The gsave-showpage-grestore is less harmful than the %%%%%%%%%% %%%%%%%%%% same sequence with save/restore, but it still seems to %%%%%%%%%% %%%%%%%%%% disallow showpage-layering to things like 2-up, where %%%%%%%%%% %%%%%%%%%% you need to do things like define a new clip path... %%%%%%%%%% %%Creator: SoftQuad Troff % @(#)preamble 1.37 88/03/18 Copyright 1986, 1987, 1988 SoftQuad Inc. %[lots of stuff deleted] /endofpage { /#copies exch def gsave showpage grestore }def %[lots of stuff deleted] 1791(Cambridge)s 2006(Computer)s 1 endofpage %%PageFonts: Times-Roman sqr %%Page: 2 2 %%PageFonts: (atend) sqs 2 2 1 startofpage %%%%%%%%%% The following lines excerpted from wordperfect output. %%%%%%%%%% %%%%%%%%%% This is a showpage-restore-save-... sequence, which %%%%%%%%%% %%%%%%%%%% (again) kills layered showpages which retain state. %%%%%%%%%% /_bp {save 2 setmiterlimit .06 .06 scale 0 0 moveto} bdef /_ep {showpage restore 0 0 moveto} bdef %[lots of stuff deleted] _u _ep _bp /Times-RomanR 507 _ff 0 13200 10200 _ornt 3954 11712 _m (AGREEMENT)_S 62 _rm (FOR)_S 62 _rm (SERVICES)_S 3693 11543 _m %%%%%%%%%%%%% And finally, the following was my `odd pages' try. %%%%%%%%%%%%% %%%%%%%%%%%%% (You need to change only one line to make even.ps) %%%%%%%%%%%%% %---------------------------------- CUT HERE ---------------------------------- % Odd.ps % % Define a replacement showpage module which prints every other page. % It is written so it can be `nested' with other showpage replacements. % % Revision history: % 12-Aug-1990 Original Version: Bob Tinkelman <bob@camb.com> % % Limitations: % Cannot be used `after' (layered on top of) other `showpage % replacements' which paint a background for the next page. % (eg DRAFT). For cases like this, it must be used `before'. % % Logic overview: On alternate invocations, it will: % (1) Invoke the `real' showpage % (2) Erase everything written since the previous call. /showpage { 0 begin % Use local dictionary (inserted for `0' below) % page_no 2 mod 0 eq % See if even; if so, need a real showpage page_no 2 mod 1 eq % See if odd; if so, need a real showpage { page_no 0 ne {s} if % Do a real showpage (unless page 0) gsave % Save graphics state for grestore after } % our `client' has drawn page we'll erase { page_no 0 ne {grestore} if% Restore saved graphics state c % Set current path to clippath 1 currentgray sub setgray % Reverse current gray fill % Fill (erase) the clippath bounded region 1 currentgray sub setgray % Set the gray back to the way it was } ifelse /page_no page_no 1 add def % Increment the page number end } bind dup 0 % Stack: /showpage {...} {...} 0 % Make new showpages's local dict 4 dict dup begin % Stack: /showpage {...} {...} 0 showpage-dict put % Stack: /showpage {...} /page_no 0 def % Used for even/odd check and 1st page check /c /clippath load def % Get current definition of clippath /s /showpage load def % Get definition of current showpage end % Stack: /showpage {...} % Define the new showpage and `do page zero' def % Define new showpage. showpage %---------------------------------- CUT HERE ----------------------------------
heiney@wsl.dec.com (Bob Heiney) (08/14/90)
The best way to achieve what you want would be to exploit the page comments that a good PostScript file gives you. By putting "%!-PS-Adobe-2.0" (or other version #) at the top, documents claim that they will follow a set of conventions that would easily give you the tools you need. You can get "struct.ps" from the Adobe file server if you want to see what's in the lastest version of the conventions. Unfortunately, in the words of Brian Reid (who came up with the original commenting conventions): "They're one of those things that everyone agrees is a great idea, easy easy to do, etc. -- but no one follows them." I foolishly whipped up an awk script to do segmentation of large files. I was at Berkeley at the time, and was constantly annoyed by people printing HUGE ps files. My 1000 byte job was always next in the queue after one of those monsters. So, since I occasionally need to print big ps files too, I decided to write a segmenter that would split the ps file into n page chunks. That way no one would curse my name when I printed large documents. Unfortunately, the absolute worst thing about this whole matter is that while few (I can count them on one hand... :-( ) applications *actually* follow the document structuring (a.k.a. commenting) conventions, almost *ALL* claim they do by putting "%!-PS-Adobe-2.0" at the top of their code. This the requires artificial intelligence from the paging software to have it figure out what's going on. The most common problem is that pages are not independent like they're supposed to be. On the Mac, for example, the first time a font is used, a revectoring is done. Since this revectoring is crucial, and only done once, if you don't execute the page that the revectoring occurs on, you'll get an error. I wish I had some more helpful advice, but since messing around with showpage is bound to be hairy, and since people don't follow the commenting conventions, I think this is one of those "fix it by hand when you really have to do it" kind of problems. That or you can write really smart software. In the end, I think the best solution would be for all applications to either generate properly structured code, or stop claiming that they are compliant when they're not. Bob Heiney Graphics Consultant
heiney@wsl.dec.com (Bob Heiney) (08/15/90)
First, sorry to all (including me) who suffered through miswrapped text on my previous posting. I didn't realize my window was more than 80 columns wide. Anyway, I looked at version 2.1 of the Document Structuring Conventions from Adobe and found the following relevant quotes: (Section 4, "Conforming Files", p. 5) ... If these structuring conventions are to be employed, care should be taken to use them correctly and in accordance with their intended goals. Failure to do so may result in unexpected behavior of document files within some document handling systems. (p. 6) If the showpage operator is used with save and restore, the showpage operator shall occur after the page-level restore operation. The motivation for this is to be able to handily redefine the showpage operator to have side effects in the printer VM such as maintaining page counts for printing n-up copies on a single sheet of paper. If the showpage is executed within the confines of a page-level save/restore, then attempts to redefine showpage to perform extra operations will not work as intended. Thus, the original poster can see that his software *ought* to work. If only every file that claimed to be well-behaved actually was. Bob Heiney Graphics Consultant heiney@dec.com
tinkelman@ccavax.camb.com (08/16/90)
A number of people have responded to my question about showpage-layering, both via news and via mail. In article <1990Aug15.163702.15828@wrl.dec.com>, heiney@wsl.dec.com (Bob Heiney) wrote: > Thus, the original poster can see that his software *ought* to work. > If only every file that claimed to be well-behaved actually was. and he quoted version 2.1 of Adobe's Document Structuring Conventions > If the showpage operator is used with save and restore, the > showpage operator shall occur after the page-level restore > operation. The motivation for this is to be able to handily > redefine the showpage operator to have side effects in the > printer VM such as maintaining page counts for printing n-up > copies on a single sheet of paper. An interesting point was made in an e-mail response that I received from James Clark <uupsi!relay.EU.net!jclark!jjc> > I tried your code with two drivers I have written (dvitops and groff), > and it worked fine with both. But I had this sort of showpage-layering > in mind when I wrote them. > > The document structuring conventions (version 2.1) specifically forbid > enclosing showpage within save/restore; but I can't find anything that > forbids enclosing it with gsave/grestore. The reason he mentioned gsave/grestore, is that I'd used gsave and grestore in order to obtain (at the end of the page I wanted to skip) the clippath that had been in effect (at the start of that page). In fact, in one of the cases where my routine broke, it was because the program generating the PostScript document had enclosed showpages within gsave-grestore pairs! [I guess I could make the usually-true assumption that clippaths will be rectangles and save the bounding box values at `start of page', but it feels kludgy.] Incidentally, James Clark also pointed something out to me that I thought I should pass along: > I think the technique of writing a dictionary into a procedure after > definining it is no longer thought to be advisable because it doesn't > work when setpacking is true. A number of other people responded with helpful suggestions about getting around specific problems. For example, Brian Thomson <thomson@hub.toronto.edu> suggested a clever trick to preserve variables across a restore: > eg. if you want to save the value of "x" across a restore, > > /restore { x exch restore /x exch def } bind def Of course, this makes a lot of assumptions about the environment, such as you've chosen a unique name `x' that will not conflict with any body else's. I would like to thank all who responded, both in news and mail. -- Bob Tinkelman, Cambridge Computer Associates, Inc., 212-425-5830 bob@camb.com or ...!{uupsi,uunet}!camb.com!bob