Skip to main content
Skip table of contents

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

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

TEXT
  (%%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).

TEXT
  <<
    /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.

TEXT
    /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.

TEXT
    /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
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.