2

This post is a follow-up of "How do I crop pages 3&4 in a multipage pdf using ghostscript", but it changes the input to an array of data.


The quest: I have a pdf file (a set of drawings) where all pages have the same size and I want to crop some pages in one way and others differently. The following screenshot shows how I generated the data below for cropping:spreadsheet The "left,bottom,right,top" are to be handed over to the postscript /CropBox [934 350 3318 2034] command. Pagenumbers are just consecutive numbers, so they may not rally be needed.

page#,left,bottom,right,top

1   0   0   4252    2384
2   0   0   4252    2384
3   0   0   4252    2384
4   0   0   4252    2384
5   934 350 3318    2034
6   934 350 3318    2034
7   441 0   3811    2384
8   441 0   3811    2384

With the solution in the above mentioned question I was able to crop a specific page in an multipage pdf and it probably is a good starting point for a solution to this question. I just didn't figure it out on my own.

The relevant postscript code which tried to use as a base to solve this problem is (thanks to KenS):

<<
  /EndPage {
    0 eq {
      pop /Page# where {
        /Page# get
        3 eq {
          (page 3) == flush
          [/CropBox [0 0 1612 1792] /PAGE pdfmark 
          true
        }
        {
          (not page 3) == flush
          [/CropBox [500 500 612 792] /PAGE pdfmark
          true
        } ifelse
      }{
        true
      } ifelse
    }
    {
      false
    }
    ifelse
  }
>> setpagedevice

I guess we need some test numbers for "realistic" page sizes for my crazy page size dictionary... just for some fun testing.

/MyCrazyPageSizeDictionary begin
/PageSizeArray [
[0 0 595 842]       % original A4 portrait
[87 123 508 719]    % cut to A5
[149 210 446 631]   % cut to A6
[192 272 403 570]   % cut to A7
[223 316 372 526]   % cut to A8
] def
Community
  • 1
  • 1
JPF
  • 45
  • 4

1 Answers1

2

I'd suggest you place the cropping information for each page in an array, and then add each array to an enclosing array. The problem is likely to be retaining the information.

The best way to do this, probably, is to create the array of page information as a named object in a specific dictionary. If you don't create your own dictionary, then userdict will be used instead.

Then in your EndPage procedure you simply pull the relevant index of the enclosing array, which gives you an array of crop sizes:

So, for example;

%!
/MyCrazyPageSizeDictionary 1 dict def
/MyCrazyPageSizeDictionary begin
/PageSizeArray [
[   0   0   4252    2384]
[   0   0   4252    2384]
[   0   0   4252    2384]
[   0   0   4252    2384]
[   934 350 3318    2034]
[   934 350 3318    2034]
[   441 0   3811    2384]
[   441 0   3811    2384]
] def
end

<<
  /EndPage {
    0 eq {
      pop /Page# where {
        /Page# get                                    % stack - pagenum
        /MyCrazyPageSizeDictionary /PageSizeArray get % stack - pagenum [[]]
        exch                                          % stack - [[]] pagenum
        get                                           % stack - []
        [ /CropBox                                    % stack - [] [ /CropBox
        3 -1 roll                                     % stack - [ /CropBox []
        /Page pdfmark
        true
      }{
        true
      } ifelse
    }
    {
      false
    }
    ifelse
  }
>> setpagedevice

If you put that in a file (named eg crop.ps) then run your PDF file through Ghostscript but put 'crop.ps' as one of the input files before your PDF file:

gs <options....> crop.ps input.pdf

Then it should do what you want. With the caveat that I haven't tested this program in any way......

[Edit, added the corrected program]

/MyCrazyPageSizeDictionary 1 dict def
MyCrazyPageSizeDictionary begin
/PageSizeArray [
[   0   0   4252    2384]
[   0   0   4252    2384]
[   0   0   4252    2384]
[   0   0   4252    2384]
[   934 350 3318    2034]
[   934 350 3318    2034]
[   441 0   3811    2384]
[   441 0   3811    2384]
] def
end

<<
  /EndPage {
    0 eq {
      pop /Page# where {
        /Page# get                                    % stack - pagenum
        1 sub                                         % array index is 0 based, page numbers start at 1
        MyCrazyPageSizeDictionary /PageSizeArray get  % stack - pagenum [[]]
        exch                                          % stack - [[]] pagenum
        1 index length mod                            % get array, find length, clamp page number to length
        get                                           % stack - []
        [ /CropBox                                    % stack - [] [ /CropBox
        3 -1 roll                                     % stack - [ /CropBox []
        /PAGE pdfmark
        true
      }{
        true
      } ifelse
    }
    {
      false
    }
    ifelse
  }
>> setpagedevice
KenS
  • 30,202
  • 3
  • 34
  • 51
  • Thank You KenS! Once more! This looks just like what I was looking for! just tested it and it does not work yet... Error /typecheck in -- begin-- Is there any way to pipe the error message to a text file ( I cannot copypaste from the ghostscript window) – JPF Nov 25 '16 at 15:35
  • **Error /typecheck in -- begin-- current file position is 77** – JPF Nov 25 '16 at 15:40
  • I added some test data to the original post for cutting a portrait A4 gradually down to A8... – JPF Nov 25 '16 at 16:05
  • Sorry typo there, should be MyCrazyPageSizeDictionary begin, ie lose the initial forward slash. Same for the 'get' case as well, we need the dictionary object, not the name object. – KenS Nov 26 '16 at 11:07
  • Thank You KenS. It runs through the pages now but stops with an error **/rangecheck in --.endpage--** _ERROR: A pdfmark destination page 8 points beyond the last page 7_. There is an output file, but none of the pages is cropped... – JPF Nov 28 '16 at 09:06
  • I'm away from my desk for the next week, the rangecheck will probably be because the page number starts at 1, and the array index starts at 0. Should still add a CropBox though. I'm afraid you'll have to hope for someone else to comment for a week.... – KenS Nov 28 '16 at 12:12
  • Thank you anyways, you have been a great help. Have a nice week. – JPF Nov 28 '16 at 13:20
  • KenS, I hope you are having a great pre Christmas season. All the best to you and your family. – JPF Dec 19 '16 at 13:09
  • Yes you're right, I **had** forgotten all about this after the meeting I was at, sorry. :-( The simple answer is you need to subtract 1 from the Page#, but I'll edit my answer and supply a completely rewritten one with all the bugs fixed. And a little safety programming too. – KenS Dec 19 '16 at 14:59
  • Thanks a lot. It is running through the script without errors now but the result in not being cropped :-( – JPF Dec 21 '16 at 11:56
  • I prepared cutting data for a 5page portrait A4 pdf... see above – JPF Dec 21 '16 at 15:08
  • OK so /Page should be /PAGE in the pdfmark. Edited the code. – KenS Dec 22 '16 at 11:00
  • Thanks for this marvellous early Christmas present, KenS! – JPF Dec 22 '16 at 12:23
  • @KenS thank you so much. I was getting in over my head with a PDF file of 600 pages - all with different heights and margins. I'm not very familiar with PS syntax. Is it possible to inject an array of page labels in the same way, and then set PAGELABEL for each page as explained [here](https://bugs.ghostscript.com/show_bug.cgi?id=691889#c2)? I can ask a new question if you want to answer. – Irfan Latif Jan 24 '22 at 14:29