Hi,

One problem that people mention on comp.graphics.app.gimp quite
regularly is that gimp says "load failed" on some EPS files.

This happens when the EPS file doesn't have a "showpage" command on
the end of it.

Actually, EPS files probably shouldn't use an explicit showpage, since
they're supposed to be embedded.  But users like to be able to just
"lpr foo.eps" and have some output generated, and Adobe's Encapsulated
PostScript File Format Specification (version 3.0, 1 May 1992) says
that showpage is allowed (see page 10, section "Redefining showpage").
So in a bid to reduce the number of confused users, I think gimp
should continue to produce EPS files with a showpage at the end (and
rely on the embedding application to correctly define away showpage).

However, this still leaves the question of how to correctly load an
EPS file.  Currently, we just present the file to gs pretty much
verbatim (ie, with no embedding).  This works only for EPS files that
have an explicit showpage in them.  Some don't, eg those produced by
Aldus Freehand 8 on Mac.

The correct way to get gs to render the EPS file is to provide it with
a prologue, the file itself, then finally an epilogue.

The reccommended code (again from Adobe's EPS standard, pg 17), is:

 1 /b4_inc_state save def
 2 /dict_count countdictstact def
 3 /op_count count 1 sub def
 4 userdict begin
 5 /showpage { } def
 6 0 setgray 0 setlinecap
 7 1 setlinewidth 0 setlinejoin
 8 10 setmiterlimit [ ] 0 setdash newpath
 9 /languagelevel where
10 {pop languagelevel
11 1 ne
12   {false setstrokeadjust false setoverprint
13   } if
14 } if

15 <EPS file goes here>

16 count op_count sub {pop} repeat
17 countdictstack dict_count sub {end} repeat
18 b4_Inc_state restore

Line 1 saves the memory arena, so it can be later restored by line
18.  We don't need this, since we don't need to do further processing
after the EPS file.

Lines 2, 3 save the stack sizes for operand and dictionary stacks, and
lines 16 and 17 then pop any extra crap the EPS left lying around on
those stacks.  Again, we don't need that, but could be vulnerable to
malicious EPS files that deliberately popped more than they push.  Not
much we can do about that, short of starting with an empty stack.

Line 4 makes sure the EPS file puts any temporary defs into the user
dictionary, rather than any application one in use.  We should
probably do this, not so much to protect our dictionary (we don't
care if it gets trashed) but more so that the topmost dictionary is
large enough for the EPS file's use.

Line 5 redefines showpage to be harmless, so the EPS cannot output
stuff at inopportune moments.

Lines 6 to 8 restore the graphics state to the default.  gs should
initialise to this anyway, so we don't need this.  Lines 9 to 14 to
the same for portions of the graphics state only present in PostScript
level 2 interpreters.  Note that "languagelevel" is itself a level 2
feature, hence the rather convoluted way of using it.

In addition to this, we need to add:

4.5 /saved-showpage /showpage where pop /showpage get def

to squirrel away a safe version of showpage before blowing it way,
and:

19 saved-showpage

to actually print the EPS out.  This last solves the problem with EPS
files not loading correctly.  (Hmm, actually, might need to put the
saved-showpage in a fresh dictionary to make sure that malicious EPS
code can't redefine saved-showpage).

Now, the only question remains how to add this harness code around the
EPS we want to load.  The simplest is just to copy the EPS to a
temporary location, sticking the prologue and epilogue on as we go.
This is tedious, since people often want to load large bits of
PostScript, and we don't want the overhead (in terms of both time and
space) of copying the thing.

Luckily, gs allows multiple files to be listed on the command line.

So, where's a good place to put a couple of plugin-specific data
files, namely: eps-loader-prologue.ps and eps-loader-epilogue.ps ?

Austin
(phew)

Reply via email to