pdfghostscriptpdf-manipulation

Splitting single page into two pages with ghostscript


I have a pdf with something like presentations slides and multiple slides per page. How can I use ghostscript to split the file so that there is one slide per page?


Solution

  • A long time ago I wrote some code for someone on comp.lang.postscript to do this, again it was for PowerPoint slides. This PostScript code assumes that all the 'subpages' (ie slides) are the same size and location on the PDF page and that all the PDF pages are the same size. Save the following as a file called pdf_slice.ps and follow the usage as described in the comments.

    %!PS
    % Copyright (C) 2011 Artifex Software, Inc.  All rights reserved.
    % 
    % This software is provided AS-IS with no warranty, either express or
    % implied.
    % 
    % This software is distributed under license and may not be copied,
    % modified or distributed except as expressly authorized under the terms
    % of the license contained in the file LICENSE in this distribution.
    % 
    % For more information about licensing, please refer to
    % http://www.ghostscript.com/licensing/. For information on
    % commercial licensing, go to http://www.artifex.com/licensing/ or
    % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
    % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
    %
    % Slice up a PDF file
    %
    % usage: gs -sFile=____.pdf  -dSubPagesX= -dSubPagesY= [-dSubPageOrder=] [-dVerbose=]pdf_slice.ps
    %
    % SubPageOrder is a bit field;
    % Default = 0
    % Bit 0 - 0 = top to bottom
    %         1 = bottom to top
    % Bit 1 - 0 = left to right
    %         1 = right to left
    % Bit 3 - 0 = increase x then y
    %       - 1 = increase y then x
    % 
    % 0 - page 1 at top left, increasing left to right, top to bottom
    % 1 - page 1 at bottom left increasing left to right, bottom to top
    % 2 - page 1 at top right, increasing right to left, top to bottom
    % 3 - page 1 at bottom right increasing right to left, bottom to top
    % 4 - page 1 at top left, increasing top to bottom, left to right
    % 5 - page 1 at bottom left increasing bottom to top, left to right
    % 6 - page 1 at top right, increasing top to bottom, right to left 
    % 7 - page 1 at bottom right increasing bottom to top, right to left
    
    %
    % Check the parameters to see they are present and of the correct type
    %
    /Usage {
      (  usage: gs -dNODISPLAY -q -sFile=____.pdf \n) =
      (     -dSubPagesX= -dSubPagesY= [-dSubPageOrder=] pdf_slice.ps \n) =
      (Please see comments in pdf_slice.ps for more details) =
      flush
      quit
    } bind def
    
    /Verbose where not {
      /Verbose false def
    }{
      pop /Verbose true def
    } ifelse
    
    /File where not {
      (\n   *** Missing source file. \(use -sFile=____.pdf\)\n) =
      Usage
    } {
      pop
    }ifelse
    
    /SubPagesX where not {
      (\n   *** SubPagesX not integer! \(use -dSubPagesX=\)\n) =
      Usage
    } {
      Verbose { (SubPagesX ) print } if 
      SubPagesX type 
      Verbose { dup == } if
      /integertype eq not {
        (\n   *** SubPagesX not integer! \(use -dSubPagesX=\)\n) =
        Usage
      }
      pop 
    }ifelse
    
    /SubPagesY where not {
      (\n   *** SubPagesY not integer! \(use -dSubPagesY=\)\n) =
      Usage
    } {
      Verbose { (SubPagesY ) print } if
      SubPagesY type 
      Verbose { dup == } if
      /integertype eq not {
        (\n   *** SubPagesY not integer! \(use -dSubPagesY=\)\n) =
        Usage
      }
      pop 
    }ifelse
    
    /SubPageOrder where not {
      /SubPageOrder 0 def
    } {
      Verbose { (SubPageOrder ) print } if
      SubPageOrder type 
      Verbose { dup == } if
      dup == 
      /integertype eq not {
        (\n   *** SubPageOrder not integer! \(use -dSubPageOrder=\)\n) =
        Usage
      }
      pop 
    }ifelse
    
    % 
    % Turns off most messages
    %
    /QUIET true def     % in case they forgot
    
    %() =
    
    %
    % Open the PDF file and tell the PDF interpreter to start dealing with it
    %
    File dup (r) file runpdfbegin pop
    /PDFPageCount pdfpagecount def
    
    %
    % Set up our bookkeeping
    %
    % First get the size of the page from page 1 of the PDF file
    % We assume that all PDF pages are the same size.
    %
    1 pdfgetpage currentpagedevice
    1 index get_any_box 
    exch pop dup 2 get exch 3 get
    /PDFHeight exch def
    /PDFWidth exch def
    
    %
    % Now get the page size of the current device. We are assuming that
    % this is the size of the individual sub-pages in the original PDF. NB
    % This assumes no margins between sub-pages, all sub-pages the same size.
    %
    currentpagedevice /PageSize get
    dup 0 get /SubPageWidth exch def
    1 get /SubPageHeight exch def
    
    % 
    % Calculate the margins. This is the margin between the page border and
    % the enclosed group of sub-pages, we assume there are no borders
    % between sub pages.
    %
    /TopMargin PDFHeight SubPageHeight SubPagesY mul sub 2 div def
    /LeftMargin PDFWidth SubPageWidth SubPagesX mul sub 2 div def
    
    Verbose {
      (PDFHeight = ) print PDFHeight ==
      (PDFWidth = ) print PDFWidth ==
      (SubPageHeight = ) print SubPageHeight ==
      (SubPageWidth = ) print SubPageWidth ==
      (TopMargin = ) print TopMargin ==
      (LeftMmargin = ) print LeftMargin ==
    } if
    
    %
    % This rouitne calculates and sets the PageOffset in the page device
    % dictionary for each subpage, so that the PDF page is 'moved' in such 
    % a way that the required sub page is under the 'window' which is the current
    % page being imaged.
    %
    /NextPage {
        SubPageOrder 2 mod 0 eq {
            /H SubPagesY SubPageY sub SubPageHeight mul TopMargin add def
        }{
            /H SubPageY 1 sub SubPageHeight mul TopMargin add def
        } ifelse
        SubPageOrder 2 div floor cvi 2 mod 0 eq {
            /W SubPageX 1 sub SubPageWidth mul LeftMargin add def
        }{
            /W SubPagesX SubPageX sub SubPageWidth mul LeftMargin add def
        } ifelse
        << /PageOffset [W neg H neg]>> setpagedevice
    
    Verbose {
      (SubPageX ) print SubPageX ==
      (SubPageY ) print SubPageY ==
      (X Offset ) print W ==
      (Y Offset ) print H == flush
    } if
    
        PDFPage
    } bind def
    
    %
    % The main loop
    % For every page in the original PDF file
    %
    1 1 PDFPageCount 
    {
        /PDFPage exch def
    
        % Do the gross ordering here rather than in
        % NextPage. We eiither process rows and then 
        % columns, or columns then rows, depending on
        % Bit 3 of SubPageorder
        SubPageOrder 3 le {
            1 1 SubPagesY {
                /SubPageY exch def
                1 1 SubPagesX {
                    /SubPageX exch def
                    NextPage
                    pdfgetpage
                    pdfshowpage
                } for
            } for
        } {
            1 1 SubPagesX {
                /SubPageX exch def
                1 1 SubPagesY {
                    /SubPageY exch def
                    NextPage
                    pdfgetpage
                    pdfshowpage
                } for
            } for
        } ifelse
    } for