(v13) Extended example: packing a film
This page applies to Harlequin v13.1r0 and later; both Harlequin Core and Harlequin MultiRIP.
This example takes the approach of fixing an output page size, and putting as many input pages onto it as will fit. To do this it records the page size requested by the job (if any), but then overrides it on each occasion with the actual page size. The example catches the page size requested by the job. This example could easily be extended to produce a sheet of thumbnails with suitable scaling set up for each page in the BeginPage
procedure.
Packing a film
First we set up a global dictionary to store the state. This must be global because when the position of the next page is calculated in EndPage
and stored here, it is often in a save
/ restore
(as in the section above, for example).
currentglobal true setglobal
userdict /SW-Page-Imposition 32 dict put setglobal
SW-Page-Imposition begin % for temporary variables statusdict /mediasize get exec % width height
% 0 media size means unrestricted, so use page size instead dup 0 eq { pop currentpagedevice /PageSize get 1 get } if
/MediaHeight exch def
dup 0 eq { pop currentpagedevice /PageSize get 0 get } if
/MediaWidth exch def
% default the input page size to letter (8.5 x 11 inches)
/PageWidth 8.5 72 mul def
/PageHeight 11 72 mul def
/LookingForPageSize 1 def
/CurrentX 0 def
/CurrentY 0 def
/PageDeactivation 2 def
/PageX 0 def /PageY 0 def
Now set up comment parsing procedures to catch a page size from the BoundingBox
or PageBoundingBox
comments. Note that this example does not take account of constructions such as %%PageBoundingBox: (at end)
and that BoundingBox
may have question marks rather than numbers after it, as in %%BoundingBox: ? ? ? ?
. See (v13) Comment parsing for details of the comment parsing mechanism.
(%%dict) load begin (%%actions) load begin
/BoundingBox: { % (x1 y1 x2 y2)
//SW-Page-Imposition begin LookingForPageSize 1 le {
dup (?) search { pop pop pop pop
}{
pop
cvx exec
index sub exch
index sub exch
<< /PageSize [5 -2 roll] >> setpagedevice
/PageY exch def
/PageX exch def
} ifelse
} if end
} bind def
/PageBoundingBox: { % (x1 y1 x2 y2)
//SW-Page-Imposition begin LookingForPageSize 1 le {
cvx exec
index sub exch
index sub exch
<< /PageSize [5 -2 roll] >> setpagedevice
/PageY exch def
/PageX exch def
} if end
} bind def end end
Now we set up the page device. The SensePageDevice
procedure catches page sizes set up by calls to setpagedevice
(and therefore setpage
and setpageparams
). SensePageDevice
is a RIP extension to the page device (see (v13) Configuring the page device).
<<
/Imposition true
/SensePageDevice [
currentpagedevice /SensePageDevice get /exec load
1 index null eq { pop pop } if
{
//SW-Page-Imposition begin currentpagedevice /PageSize get aload pop
2 copy MediaHeight ne exch MediaWidth ne and {
/PageHeight exch def
/PageWidth exch def
/PageX 0 def /PageY 0 def
/LookingForPageSize LookingForPageSize 1 add def
/PageSize [MediaWidth MediaHeight]
} {pop pop} ifelse end
} bind /exec load
] cvx
The BeginPage
procedure in this example is quite simple: it just translates the page to its position on the output, and clips to its size. It works from the top down, hence the subtraction from MediaHeight
less PageHeight
. On the first page of each activation of the page device, the offsets are reset to zero to avoid extra blank pages being produced.
/BeginPage {
//SW-Page-Imposition begin
0 eq {
/CurrentX 0 def /CurrentY 0 def
} if
CurrentX PageX sub
MediaHeight PageHeight sub CurrentY PageY sub sub translate
PageX neg PageY neg PageWidth PageHeight rectclip end
} bind
The EndPage
procedure does most of the hard work here. In the normal case it increments the offset in x
by the width of each input page until it would go off the right hand edge, at which point it resets to the left margin and increments in the y
direction. When the page goes off the top (or actually off the bottom, since BeginPage
is inverting it), we reset to the origin and print the page by returning true
.
On deactivation, we deliver a page if we are not at the origin: that is, if we have not just reset to the origin at the end of the previous page, which would imply that nothing had been done to the page yet.
/EndPage { % showpagecount code -> bool exch pop
//SW-Page-Imposition begin
//PageDeactivation eq {
CurrentX 0 ne CurrentY 0 ne or
}{
/CurrentX CurrentX PageWidth add def CurrentX PageWidth add MediaWidth gt dup {
pop
/CurrentY CurrentY PageHeight add def
/CurrentX 0 def
CurrentY PageHeight add MediaHeight gt dup {
/CurrentY 0 def if
if
} ifelse end
} bind
>> setpagedevice
end % SW-Page-Imposition
userdict /SW-Page-Imposition undef % for neatness’ sake