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 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 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