Bug 430175

Summary: Imposition
Product: Ghostscript Reporter: Jack Moffitt <jack>
Component: PDF WriterAssignee: Ken Sharp <ken.sharp>
Status: RESOLVED WONTFIX    
Severity: enhancement Keywords: bountiable
Priority: P5    
Version: master   
Hardware: All   
OS: All   
Customer: Word Size: ---
Attachments: Library file to sequence PDF pages for imposition
Example: impose a simple pdf manual as a folio
Example: another way to create folio (several signatures this time)
Example: fancy folio imposition of the same manual
Example: quarto imposition of a more elaborate pdf
Example: sixmo imposition of the same pdf

Description Jack Moffitt 2001-06-04 17:51:41 UTC
Originally reported by: nobody@users.sourceforge.net
The aim is to take a pdf file and rearrange to page 
order such that a 2-up duplexed print can be folded in 
half to form a booklet.

Commercialware equivilant is Quite Imposing.
Comment 1 Jack Moffitt 2002-02-18 09:26:55 UTC
Comment originally by nobody@users.sourceforge.net
Logged In: NO 

Try www.gdykes.com.
Hope this help.
Comment 2 Alistair Braidwood 2005-04-14 09:46:54 UTC
I don't have time to do this properly, but it's relatively simple and along the
lines of:

1. modify pdfshowpage_setpage in pdf_main.ps change the setpagedevice to
globaldict /MYVAR known {pop} {setpagedevice} ifelse

2. modify endpage in pdf_ops.pdf change the showpage to
globaldict /MYVAR known {pop} {showpage} ifelse

3. use the following postscript to "pair" the pages
0 1 Booksize 1 sub 2 div {
  /i exch def

  << /PageSize [x y] >> setpagedevice

  i 2 mod 0 eq {
    /leftpage Booksize i sub def
    /rightpage i 1 add def
  } {
    /leftpage i 1 add def
    /rightpage Booksize i sub def
  } ifelse

  0 0 translate
  /FirstPage leftpage def
  /LastPage leftpage def
  (multipagefile.pdf) run

  x 2 div 0 translate
  /FirstPage rightpage def
  /LastPage rightpage def
  (multipagefile.pdf) run

  showpage
}for

4. run gs with the command-line options -dMYVAR -sBooksize=<number of pages>
Comment 3 Chapman Flack 2005-09-27 11:54:54 UTC
Created attachment 1701 [details]
Library file to sequence PDF pages for imposition

This file defines one procedure, pdfimpose, that will render
the pages of a PDF in an order that can be concisely specified
for imposition. Depending on the selected output device, the
result can be a reordered pdf, ps, or whatever.

Imposition has two separable issues, sequencing
and geometry; pdfimpose handles the sequencing part, as the
report requested, as once the pages are in proper sequence there
is existing work for n-up pages and duplexing (e.g. gsnup.ps is
already distributed with ghostscript).
Comment 4 Chapman Flack 2005-09-27 11:58:35 UTC
Created attachment 1702 [details]
Example: impose a simple pdf manual as a folio

Example takes a simple pdf manual found in the wild and makes
a folio of it. Creates a folio pdf in one step; uses pdfimpose
for the sequencing, and net.anastigmatix.PageNest for the geometry.
Comment 5 Chapman Flack 2005-09-27 12:01:22 UTC
Created attachment 1703 [details]
Example: another way to create folio (several signatures this time)

Demonstrates a few more possibilities than attachment #1702 [details].
Produces multiple signatures (will fold better than one fat
one) assuming they will be bound as a book somehow.
Comment 6 Chapman Flack 2005-09-27 12:04:14 UTC
Created attachment 1704 [details]
Example: fancy folio imposition of the same manual

This example takes care of the original pdf having the table
of contents in the wrong place, and instead of breaking the
manual into signatures by an arbitrary page count, makes a
logical division at the appendices; also handles the fact that
each appendix starts on an even (should be verso) page.
Comment 7 Chapman Flack 2005-09-27 12:07:05 UTC
Created attachment 1705 [details]
Example: quarto imposition of a more elaborate pdf

The more elaborate pdf of this product manual, also found in the
wild, includes pages with very different native dimensions and
orientations that must be accounted for. It also includes many
pdfmarks that cannot be simply copied into the new pdf because
the page rearrangement would make them nonsense.
Comment 8 Chapman Flack 2005-09-27 12:08:42 UTC
Created attachment 1706 [details]
Example: sixmo imposition of the same pdf

The same elaborate pdf from attachment #1705 [details], this time imposed
as a sixmo to save a little more paper.
Comment 9 Chapman Flack 2005-09-27 12:48:29 UTC
I have an implementation (attachment #1701 [details]) working in GPL Ghostscript
8.15 and I expect it will work on the HEAD.

 {pop} [] [-1 0 1 -2] (file.pdf) pdfimpose

will show the pages of file.pdf in the proper order for a folio (print
2-up duplex, fold once) imposition, the kind most people have in mind
for printing some random article as a booklet. If the pdf does not have
a multiple of 4 pages, a few blank (half-)pages may be generated. A
procedure other than {pop} can be specified to paint something on those
pages, like "This page left blank."

As you can see, the simple folio is only one special case of the
sequencing pdfimpose can do - it has to support arbitrary impositions if
it is to be described as anything close to equivalent of Quite Imposing
etc.

Imposition has two separable issues: sequencing and geometry. pdfimpose
handles the sequencing part, as this report requested; it will put the
pages in the right sequence so they can be combined, with the right
geometry, to get the final result. Used by itself, it will simply output
the original pages in a new order on whatever device is selected, so it
can generate a reordered pdf, reordered ps, or whatever.  Existing tools
like Angus Duggan's psnup from psutils, the gsnup.ps already in the
ghostscript distribution, or net.anastigmatix.PageNest, can be used with
those files to arrange the pages on sheets with the right geometry.

It can be handy to do the sequencing and geometry in one step, as the
attached examples do by using pdfimpose for the sequencing and PageNest
for the geometry (which has enough flexibility to handle the more
elaborate examples). PageNest I had already written, not specifically
for ghostscript, so it is not included in the copyright assignment, but
that should pose no problem for anyone who would like to use it, as it
is already licensed for unrestricted use and redistribution. It should
also be possible to use the gsnup.ps already present for the simpler
imposition geometries; I would have included some examples done with
gsnup but it has a few bugs I'll add to the tracker.

Two enhancements to the underlying PDF processing would simplify this,
and eliminate the need for -dDELAYBIND to get the examples working.

1. pdfshowpage_finish calls showpage (endpage) before restore, rather
   than after, where it belongs.  Both gsnup and PageNest include
   showpage/restore hacks intended to work around that issue in ordinary
   PostScript code, but for them to work in gs library code, DELAYBIND
   is needed.  Fixing pdfshowpage_finish to get the restore and showpage
   in the right order would eliminate this issue; it is not clear to me
   what if anything depends on the current late restore, so I have not
   tried to fix it myself.

2. there is no facility to disable pdfmark with the pdfwrite device, or
   to intercept it with a callback.  When rewriting a pdf to pdf, by
   default all pdfmarks from the original get copied; when the page
   order and dimensions are really being totally rearranged, those
   pdfmarks are worse than useless, and will cause a viewer to display
   the file incorrectly. I get around it with DELAYBIND to bind a
   version of pdfmark that has a callback hook, and completes the action
   only if the callback returns true.  If some similar hook arrangement
   became a standard feature, this use of DELAYBIND would be
   unnecessary. Perhaps a new pdfwrite pseudoparameter could be used to
   specify a pdfmark callback procedure, or it could be a special
   pdfmark or a PUT to a special object:
   [ {gspdfmarkcallback} { dup = false } /PUT pdfmark. Partly a matter
   of taste, so I have not made a decision on my own.

One of the difficulties with gsnup.ps is it blows the execution stack
if DELAYBIND is used; it would need some attention to make sure its
procedures don't become recursive in that case. Everything gets easier
if those two enhancements make the DELAYBIND unnecessary.

There is another issue that is likely to cause the one-step approach in
the examples to fail: transparency.  At present any page that contains a
use of transparency results in a .pushpdf14devicefilter, which seems to
erase anything rendered on the medium to that point. That will be a
problem if an n-up page is being accumulated. A workaround is to go back
to two steps, use pdfimpose just to make a reordered file, use
(hopefully something better than) pswrite to get reordered PostScript,
and use any n-up geometry tool of choice to finish the job.

Is it true that the pdf14 filter just turns everything into an image for
the device below?  Is it possible to make it conditional, so it doesn't
get pushed if the output device is pdfwrite with CompatibilityLevel >=
1.4? (Or does it already do the right thing in that case? I didn't
explore too deeply.)  That would at least make it simple to do pdf->pdf
impositions in one step, even with transparency.

For trying out the examples, PageNest can be downloaded from
http://www.anastigmatix.net/postscript/PageNest.html. Two files
are needed, MetaPre and PageNest, as described on the page.
Comment 10 Chapman Flack 2005-09-28 09:37:47 UTC
A couple documentation errata:

The comments in attachment #1701 [details] fail to document that if seqSpec is empty,
pdfimpose uses blockSpec (exactly once, regardless of its length) as a list
of explicit page numbers to process in order (0 being FirstPage; negative
values are still usable, -1 meaning LastPage); in that way pdfimpose's
calculations can be overridden to do completely arbitrary page ordering.
Attachment #1704 [details] used that feature for the table of contents and the start
of the appendices, so the example would be hard to understand without the
explanation.

In attachment #1705 [details] and attachment #1706 [details], there are two sentences each about
"In principle, the UserBBox could be obtained ..." where there is no longer
any UserBBox or related code. The sentences should have been deleted.  In
attachment #1706 [details], the old code they pertained to is still there, commented out;
it should have been deleted too.
Comment 11 Chapman Flack 2005-09-30 14:58:43 UTC
I've taken the liberty of marking this bug resolved, because (a) I believe
pdfimpose.ps resolves it, (b) I looked at the lifecycle help and thought
perhaps marking it resolved helps it show up as something for QA to look at,
and (c) bugzilla didn't object. I'm sure if you review it and decide there was
something I missed after all, you'll reopen it. Looking forward to hearing
your opinions.
Comment 12 Ray Johnston 2005-09-30 20:21:01 UTC
We generally only close bugs when the fix has been committed.

This will take a few days for us to finish reviewing, but my initial thought
is that this is worthwhile and should be added to the Ghostscript distribution
(committed to CVS).

Once this is committed, then we'll close the bug.
Comment 13 Ray Johnston 2005-09-30 20:21:42 UTC
assigning to myself to do the review and/or commit.
Comment 14 Chapman Flack 2005-10-01 15:32:01 UTC
No problem - didn't mean to step on any toes.  Out of curiosity, is
bugs.ghostscript.com/bug_status.html a reasonable picture of the bug
lifecycle used for ghostscript, or is it a default page installed with
bugzilla that hasn't been locally customized?  That was where I got the
idea the progression would be Resolved (here's a fix, I think) -> Verified
(yep, looks like a fix) -> Closed (it's committed). Sorry if I misunderstood.

One more for the errata: in attachment #1705 [details] and attachment #1706 [details], the
example pdfimpose_setpage procedure should not be considered complete for
the general case. It assumes the CropBox is given in llx lly urx ury form,
which is true for the sample PDF, but the PDF spec for some unfathomable
reason allows any two opposite box corners to be given in any order, so a
general solution needs to normalize the corners. I'm pretty sure there is
already code somewhere in pdf_*.ps for doing that. It also looks only for
CropBox and, if none, falls back to MediaBox. A general solution ought to
look at TrimBox, BleedBox, or ArtBox first; the fallback for each of those
is CropBox, and the ultimate fallback is MediaBox. Which of TrimBox,
BleedBox, or ArtBox to look at is not a purely automatable choice, because
it will depend on the intended use and how the pages will be folded, trimmed,
and finished. TrimBox is a good general purpose choice if making a folio
where nothing will really be trimmed so the printed folded page is already at
its final dimensions. BleedBox is the canonical choice if something is really
going to be trimmed and finished with the traditional methods. ArtBox would be
a good choice if the goal is to enlarge the visible content as much as possible
when fitting to the page, sacrificing margins.
Comment 15 Chapman Flack 2005-10-11 18:35:53 UTC
Examples errata: the example scripts should contain
<< /AutoRotatePages /None >> setdistillerparams  or
<< /AutoRotatePages /All  >> setdistillerparams.

Otherwise, I seem to get a default of /PageByPage, which
can cause the generated PDF file to have nonuniform page
orientations ... not useful for imposition ....
Comment 16 Chapman Flack 2005-10-18 08:31:40 UTC
Have now tried pdfimpose and the examples in GS 8.51 and can confirm they work.
Comment 17 Chapman Flack 2005-12-02 16:51:57 UTC
Hi,

comment #12 suggested several days might be needed to review and/or commit.
Of course the 8.53 release was in the works and must have needed a lot of time
and attention, and maybe there will be a better chance now. I hope not to be a
pest, but if the solution seems to address the requirements, for various utterly
nontechnical reasons it would be convenient for me to process the bounty this
calendar year.  If there seems to be any way it falls short of addressing the
requirements, I would be pleased to know about it.

Thanks!
Comment 18 leonardo 2007-04-08 11:34:56 UTC
Passing to Alex who owns gs/lib . Or maybe it shoyld go to gs/toolbin .
Comment 19 Ken Sharp 2013-06-25 16:27:54 UTC
After discussion amongst the developers we've decided to close this as wontfix because its been dormant for so long.

I'd like to take the opportunity to apologise to everyone concerned about the fact that this was left to rot, I really am terribly sorry.