Overlay two postscript files (command line approac

2020-02-26 09:58发布

I'm aware that similar questions have been answered here before:

... however, as they don't directly answer my specific problem, I'll try asking again.

 

I would like to know, how I can overlay two postscript files: one - a logo:

... on top of the other - a graphic background:

.... using a command line approach in Linux.

 

It is of importance here, that the graphic background preserves its original contents to the greatest extent possible. Therefore, I'd probably be happiest if I could somehow concatenate the two original postscript file contents unchanged (see below) - but other than that, I'd like to know how command-line tools like ghostscript could be used for the purpose.

 

The problem - logo on top of PCB .ps printout

Here is the problem in more detail - I want to add a logo on top of a PCB board print. I use kicad to develop the PCB print; once done, I export a postscript document with the individual layers. Usually, I want to have the front copper layer "mirrored"; I have often experimented with loading the .ps output into, say, inkscape, and then trying to do a mirroring there. Using inkscape was also convenient, because one can easily add a logo there (and then mirror the print and the logo together).

However, using inkscape to process postscript output is an expencive operation (because it takes a while for inkscape to load, and do the mirroring, and the saving)... Although, the main show stopper here is that: after processing, some of the dimensions may be slightly changed in the output file by inkscape (and it makes a lot of difference, when the target is printing of tracks less than a millimeter wide).

 

So, given that kicads "Plot" command has an option for mirroring - it is, of course, much better for me to "mirror" the layer print directly from kicads "Plot" command; the output is again a postscript file. tmp-Front.ps is an example of such a (mirrored) postscript file. Note that typically, the "copper" part is filled with black - and I'd basically like to have a white logo on top of it.

Now, since this print is already "mirrored" - if I want to add a logo on top of it, I better have the logo mirrored as well. So I fire up inkscape; and:

  • add a text for the logo;
  • set up via Document Properties:
    • that the document size matches the logo size, and
    • that the document should have a black background
  • Then change the logo text to have white fill;
  • do Object/Flip Horizontal on the logo text; and then
  • do File/Save a Copy;
    • choose PostScipt (*.ps) as output;
    • on the dialog choose PostScript level 2, and
    • select "Convert text to paths" before exporting.

This is how logo.ps linked above was generated (note that - for these kind of small logos: without 'text to paths', the .ps file (with fonts) can be up to 20 kB; as opposed to 5 kB for paths only).

One problem, though, is that postscript doesn't really support something like a "document background" color - apparently you need to define a filled rectangle yourself:

... therefore if you open logo.ps, you will not see anything - since it contains white letters on white background.

Viewers

If in logo.ps, the 1 g line is replaced with 0.5 g; the logo becomes gray (and visible), and here it is rendered under evince, gs raw viewer, and gv:

view-logo.png

Here is the same comparison for tmp-Front.ps:

view-tmp-Front.png

Notably, the raw ghostscript viewer ignores bounding box and page orientation - and even more problematic is, if you use Ubuntu Gnome on a netbook, then the top and bottom bar may cut a bit of the ghostscript viewer window - enough so that the logo in bottom left corner is invisible; and since "... the raw ghostscript viewer gs ... has no real user interface", a gs window which started up with the logo cropped, cannot be set to show it afterwards.

 

Concatenating .ps file contents for overlay

By looking at these references:

... I'm guessing that, in principle, it should be possible to concatenate the file contents of two postscript files; and if there is only a single showpage command in the merged file - then, in principle, one should obtain an overlay (?!) of the two. However, I tried that, and I cannot really get it to work.

If this is possible, I'd like to somehow just copy/paste the postscript file contents (and thereby avoid any problems with document dimensions/sizes/resolutions) - and then possibly use the translate postscript command (see Postscript Editing in Gnuplot) to adjust the position of the logo. Having the 'overlaid' (merged) .ps opened in evince, would refresh the document display each time the translate parameters are changed in a text editor - so it should be relatively easy to handle the logo positioning in that way.

 

However, I can foresee some problems here too: for one, the graphic (tmp-Front.ps) contains:

%%BoundingBox: 0 0 596 843
%%DocumentMedia: A4 595 842 0 () ()
...
0.0072 0.0072 scale
...
30085 54415 moveto
...

... while logo.ps contains:

%%BoundingBox: 0 0 31 13
...
%%DocumentMedia: 11x4mm 31 13 0 () ()
...
25.539 9.536 m(oveto) ...
...

... thus there are two main differences:

  • Document size is not the same for the files
  • Scale (or rather resolution/coordinate system) is not the same either

Since I couldn't get concatenation of file contents to work at all - I'm not really sure if these differences would have an influence on the overlay ... I'd certainly hope that they are somehow rendered independently; and the translate would just help to properly set up their relative position :)

 

So - how would I go about, if I wanted to achieve an overlay by concatenating postscript file contents? And if that is too troublesome - how could I use a tool such as ghostscript (or any other), in order to set up an overlay?

 

Many thanks in advance for any answers,
Cheers!

 


For reference, here are copies of the mentioned postscript files (as they are not too big):

tmp-Front.ps:

%!PS-Adobe-3.0
%%Creator: PCBNEW-PS
%%CreationDate: Thu Mar 22 09:50:52 2012
%%Title: /tmp-Front.ps
%%Pages: 1
%%PageOrder: Ascend
%%BoundingBox: 0 0 596 843
%%DocumentMedia: A4 595 842 0 () ()
%%Orientation: Landscape
%%EndComments
%%Page: 1 1
/line {
    newpath
    moveto
    lineto
    stroke
} bind def
/cir0 { newpath 0 360 arc stroke } bind def
/cir1 { newpath 0 360 arc gsave fill grestore stroke } bind def
/cir2 { newpath 0 360 arc gsave fill grestore stroke } bind def
/arc0 { newpath arc stroke } bind def
/arc1 { newpath 4 index 4 index moveto arc closepath gsave fill grestore stroke } bind def
/arc2 { newpath 4 index 4 index moveto arc closepath gsave fill grestore stroke } bind def
/poly0 { stroke } bind def
/poly1 { closepath gsave fill grestore stroke } bind def
/poly2 { closepath gsave fill grestore stroke } bind def
/rect0 { rectstroke } bind def
/rect1 { rectfill } bind def
/rect2 { rectfill } bind def
/linemode0 { 0 setlinecap 0 setlinejoin 0 setlinewidth } bind def
/linemode1 { 1 setlinecap 1 setlinejoin } bind def
/dashedline { [50 50] 0 setdash } bind def
/solidline { [] 0 setdash } bind def
gsave
0.0072 0.0072 scale
linemode1
82670 0 translate 90 rotate
60 setlinewidth
60 setlinewidth
newpath
30085 54415 moveto
30085 52585 lineto
31915 52585 lineto
31915 54415 lineto
30085 54415 lineto
poly1
newpath
87950 54930 moveto
32094 54930 lineto
32094 54474 lineto
32094 54415 lineto
32094 52525 lineto
32071 52470 lineto
32029 52428 lineto
31974 52406 lineto
31915 52406 lineto
30025 52406 lineto
29970 52429 lineto
29928 52471 lineto
29906 52526 lineto
29906 52585 lineto
29906 54475 lineto
29929 54530 lineto
29971 54572 lineto
30026 54594 lineto
30085 54594 lineto
31975 54594 lineto
32030 54571 lineto
32072 54529 lineto
32094 54474 lineto
32094 54930 lineto
28300 54930 lineto
28300 17800 lineto
87950 17800 lineto
87950 54930 lineto
poly1
100 setlinewidth
newpath
87950 54930 moveto
32094 54930 lineto
32094 54474 lineto
32094 54415 lineto
32094 52525 lineto
32071 52470 lineto
32029 52428 lineto
31974 52406 lineto
31915 52406 lineto
30025 52406 lineto
29970 52429 lineto
29928 52471 lineto
29906 52526 lineto
29906 52585 lineto
29906 54475 lineto
29929 54530 lineto
29971 54572 lineto
30026 54594 lineto
30085 54594 lineto
31975 54594 lineto
32030 54571 lineto
32072 54529 lineto
32094 54474 lineto
32094 54930 lineto
28300 54930 lineto
28300 17800 lineto
87950 17800 lineto
87950 54930 lineto
poly0
1 1 1 setrgbcolor
60 setlinewidth
31000 53500 170 cir1
0 0 0 setrgbcolor
showpage
grestore
%%EOF

logo.ps:

%!PS-Adobe-3.0
%%Creator: cairo 1.10.2 (http://cairographics.org)
%%CreationDate: Thu Mar 22 10:07:46 2012
%%Pages: 1
%%BoundingBox: 0 0 31 13
%%DocumentData: Clean7Bit
%%LanguageLevel: 2
%%DocumentMedia: 11x4mm 31 13 0 () ()
%%EndComments
%%BeginProlog
/languagelevel where
{ pop languagelevel } { 1 } ifelse
2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto
  (This print job requires a PostScript Language Level 2 printer.) show
  showpage quit } if
/q { gsave } bind def
/Q { grestore } bind def
/cm { 6 array astore concat } bind def
/w { setlinewidth } bind def
/J { setlinecap } bind def
/j { setlinejoin } bind def
/M { setmiterlimit } bind def
/d { setdash } bind def
/m { moveto } bind def
/l { lineto } bind def
/c { curveto } bind def
/h { closepath } bind def
/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
      0 exch rlineto 0 rlineto closepath } bind def
/S { stroke } bind def
/f { fill } bind def
/f* { eofill } bind def
/n { newpath } bind def
/W { clip } bind def
/W* { eoclip } bind def
/BT { } bind def
/ET { } bind def
/pdfmark where { pop globaldict /?pdfmark /exec load put }
    { globaldict begin /?pdfmark /pop load def /pdfmark
    /cleartomark load def end } ifelse
/BDC { mark 3 1 roll /BDC pdfmark } bind def
/EMC { mark /EMC pdfmark } bind def
/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
/Tj { show currentpoint cairo_store_point } bind def
/TJ {
  {
    dup
    type /stringtype eq
    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
  } forall
  currentpoint cairo_store_point
} bind def
/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
/Tf { pop /cairo_font exch def /cairo_font_matrix where
      { pop cairo_selectfont } if } bind def
/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
      /cairo_font where { pop cairo_selectfont } if } bind def
/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
/g { setgray } bind def
/rg { setrgbcolor } bind def
/d1 { setcachedevice } bind def
%%EndProlog
%%Page: 1 1
%%BeginPageSetup
%%PageMedia: 11x4mm
%%PageBoundingBox: 0 0 31 13
%%EndPageSetup
q 0 0 31 13 rectclip q
1 g
25.539 9.536 m 25.539 7.567 l 27.227 7.567 l 27.227 3.817 l 27.227 
3.055 27.211 2.606 27.18 2.473 c 27.152 2.348 27.078 2.243 26.961 2.161 
c 26.848 2.087 26.707 2.052 26.539 2.052 c 26.324 2.052 25.992 2.13 
25.555 2.286 c 25.336 0.364 l 25.922 0.118 26.574 -0.011 27.289 -0.011 
c 27.738 -0.011 28.145 0.063 28.508 0.208 c 28.863 0.36 29.125 0.559 
29.289 0.802 c 29.457 1.04 29.574 1.364 29.633 1.77 c 29.688 2.048 
29.711 2.63 29.711 3.505 c 29.711 7.567 l 30.852 7.567 l 30.852 9.536 l 
29.711 9.536 l 29.711 11.395 l 27.227 12.833 l 27.227 9.536 l h
18.535 3.177 m 16.082 2.77 l 16.395 1.864 16.898 1.169 17.582 0.692 c 
18.262 0.223 19.117 -0.011 20.145 -0.011 c 21.77 -0.011 22.969 0.52 
23.738 1.583 c 24.355 2.434 24.66 3.509 24.66 4.802 c 24.66 6.352 
24.262 7.567 23.457 8.442 c 22.648 9.313 21.621 9.755 20.379 9.755 c 
18.996 9.755 17.902 9.294 17.098 8.38 c 16.297 7.462 15.914 6.055 
15.941 4.161 c 22.129 4.161 l 22.121 3.43 21.926 2.86 21.551 2.458 c 
21.168 2.052 20.688 1.848 20.113 1.848 c 19.73 1.848 19.406 1.95 19.145 
2.161 c 18.875 2.368 18.672 2.708 18.535 3.177 c h
18.395 5.677 m 18.418 6.391 18.605 6.934 18.957 7.302 c 19.312 7.673 
19.742 7.864 20.238 7.864 c 20.781 7.864 21.227 7.665 21.566 7.27 c 
21.922 6.884 22.098 6.352 22.098 5.677 c h
15.02 2.864 m 12.535 3.255 l 12.434 2.774 12.219 2.407 11.895 2.161 c 
11.574 1.911 11.125 1.786 10.551 1.786 c 9.906 1.786 9.422 1.899 9.098 
2.13 c 8.891 2.294 8.785 2.512 8.785 2.786 c 8.785 2.97 8.844 3.13 
8.957 3.255 c 9.082 3.368 9.359 3.477 9.785 3.583 c 11.777 4.016 13.039 
4.419 13.566 4.786 c 14.309 5.282 14.676 5.989 14.676 6.895 c 14.676 
7.696 14.359 8.372 13.723 8.927 c 13.078 9.477 12.09 9.755 10.754 9.755 
c 9.477 9.755 8.527 9.544 7.91 9.13 c 7.289 8.712 6.855 8.095 6.613 
7.286 c 8.941 6.848 l 9.047 7.212 9.242 7.489 9.52 7.677 c 9.793 7.872 
10.188 7.973 10.707 7.973 c 11.355 7.973 11.82 7.884 12.098 7.708 c 
12.285 7.571 12.379 7.403 12.379 7.208 c 12.379 7.028 12.297 6.876 
12.129 6.755 c 11.914 6.587 11.145 6.352 9.832 6.052 c 8.523 5.759 
7.598 5.391 7.066 4.958 c 6.559 4.52 6.301 3.907 6.301 3.13 c 6.301 
2.274 6.664 1.532 7.379 0.911 c 8.09 0.294 9.148 -0.011 10.551 -0.011 c 
11.824 -0.011 12.828 0.247 13.566 0.77 c 14.309 1.29 14.793 1.989 15.02 
2.864 c h
0.066 9.536 m 0.066 7.567 l 1.754 7.567 l 1.754 3.817 l 1.754 3.055 
1.738 2.606 1.707 2.473 c 1.68 2.348 1.605 2.243 1.488 2.161 c 1.375 
2.087 1.234 2.052 1.066 2.052 c 0.852 2.052 0.52 2.13 0.082 2.286 c 
-0.137 0.364 l 0.449 0.118 1.102 -0.011 1.816 -0.011 c 2.266 -0.011 
2.672 0.063 3.035 0.208 c 3.391 0.36 3.652 0.559 3.816 0.802 c 3.984 
1.04 4.102 1.364 4.16 1.77 c 4.215 2.048 4.238 2.63 4.238 3.505 c 4.238 
7.567 l 5.379 7.567 l 5.379 9.536 l 4.238 9.536 l 4.238 11.395 l 1.754 
12.833 l 1.754 9.536 l h
0.066 9.536 m f
Q Q
showpage
%%Trailer
%%EOF

EDIT: Re: luser droog's answer; if I try to open combo.ps as written in evince, I get:

$ evince combo.ps
invalidfileaccess -9

This is probably related to #414002 - gs -dSAFER: /invalidfileaccess with "run" operator - Debian Bug report logs... If I try to add the PostScript header "%!" at start, I get:

$ nano combo.ps # added %! at start
$ evince combo.ps
undefined -21
undefined -21

I also tried running ps2ps - this is what comes out:

$ ps2ps combo.ps comboB.ps
Error: /undefined in --load--
Operand stack:
   Oldshowpage
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   1910   1   3   %oparray_pop   1909   1   3   %oparray_pop   1893   1   3   %oparray_pop   1787   1   3   %oparray_pop   --nostringval--   %errorexec_pop   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--
Dictionary stack:
   --dict:1159/1684(ro)(G)--   --dict:0/20(G)--   --dict:77/200(L)--
Current allocation mode is local
Current file position is 30
GPL Ghostscript 9.02: Unrecoverable error, exit code 1

3条回答
Fickle 薄情
2楼-- · 2020-02-26 10:12

Ok, here is what works for me, thanks to @luserdroog's answer, with unchanged files, and "directly" in evince.

First of all, get tmp-Front.ps, logo.ps and @luserdroog combo.ps (modded below) in a directory. The first problem is that if evince encounters %%EOF, it will stop parsing whatever comes next. So, we first want to get rid of those directives in tmp-Front.ps and logo.ps:

sed -i 's/%%EOF/% %EOF/' logo.ps
sed -i 's/%%EOF/% %EOF/' tmp-Front.ps

Second, if evince doesn't encounter %%Orientation and similar directives at the very beginning, then it will not show the document in landscape (as the original tmp-Front.ps is). Thus, we should extract these directives from tmp-Front.ps, and add them at the beginning of combo.ps - and save all that as new file, combopg.ps:

cat <(echo '%!') <(grep '%%Pages\|%%PageOrder\|%%BoundingBox\|%%DocumentMedia\|%%Orientation' tmp-Front.ps) <(echo) combo.ps > combopg.ps

Here I use the following modification of combo.ps:

/Oldshowpage /showpage load def
/showpage {} def
gsave
    (tmp-Front.ps) run
grestore
    %additional scaling and translation to place the graphic?
    1 1 scale
    300 300 translate
    0 0 moveto

    (logo.ps) run
Oldshowpage

Finally, since evince doesn't recognize the run directive, I use this modification of psinc, psinc.pl to "include" the contents of the files:

cat combopg.ps | perl ./psinc.pl > combopgout.ps

 

Now, you can finally open combopgout.ps in evince - and simultaneously in a text editor, where you can look for the line 300 300 translate; editing these arguments in the text editor and saving the file will cause evince to reload the .ps file and show the latest position - it would look like this for the default:

combopgout.ps.png

(Note the logo is rotated as per landscape orientation)

 

Well, I guess this solves it - thanks for the answers!!

查看更多
\"骚年 ilove
3楼-- · 2020-02-26 10:19

A similar approach to KenS's would be to put the "composition" code in a single file and call the component files with the run operator. It amounts to the same thing but with a little less shell-work. A limitation is that the -dSAFER option (which is ON by default in most Distiller installations) disables the run operator.

combo.ps:

/Oldshowpage /showpage load def
/showpage {} def
gsave
    (tmp-Front.ps) run
grestore
    %additional scaling and translation to place the graphic?
    (logo.ps) run
Oldshowpage
查看更多
来,给爷笑一个
4楼-- · 2020-02-26 10:24

In order to 'concatenate' the two files, you would need to disable the 'showpage' operator, as otherwise both files will emit their pages separately. But you need to maintain the original definition so that you can emit the final document. Somethign liek:

/Oldshowpage showpage load def
/showpage {} def

...
file1
...
...
file2
...
Oldshowpage

So if you saved the redefinitions in a file, and the final execution in another file you might cat 'prolog.ps file1.ps file2.ps epilog.ps'

Neither of your files executes a media request (you can ignore the %% lines, those are comments only).

However, as you rightly say you don't want scaling and transforms to persist between jobs. So you need to save and restore the graphics state. So in this case you also want a 'middle' file.

So prolog.ps contains:

/Oldshowpage showpage load def
/showpage {} def
gsave

middle.ps contains

grestore

and epilog.ps contains

Oldshowpage

cat all 5 files together and it ought to work. It does something sensible for me, but I should perhaps mention that your 'logo.ps' produces an empty page for me with Ghostscript and with Adobe Distiller.

查看更多
登录 后发表回答