7

There are several resources on the web explaining how one can split a PDF into many files with on page per file.

But how can you split them into chunks of, say, five pages each? I have looked into the standard tools such as pdftk but could not find an option doing what I want.

12

pdftk is able to cut out a fixed set of pages efficiently. With a bit of scripting glue, this does what I want:

number=$(pdfinfo -- "$file" 2> /dev/null | awk '$1 == "Pages:" {print $2}')
count=$((number / pagesper))
filename=${file%.pdf}

counter=0
while [ "$count" -gt "$counter" ]; do 
  start=$((counter*pagesper + 1));
  end=$((start + pagesper - 1));

  counterstring=$(printf %04d "$counter")
  pdftk "$file" cat "${start}-${end}" output "${filename}_${counterstring}.pdf"

  counter=$((counter + 1))
done

This assumes that you have the number of pages per chunk in $pagesper and the filename of the source PDF in $file.

If you have acroread installed, you can also use

acroread -size a4 -start "$start" -end "$end" -pairs "$file" "${filename}_${counterstring}.ps"

acroread offers the option -toPostScript which may be useful.

| improve this answer | |
  • See here for a more complete implementation. – Raphael May 11 '15 at 20:45
9

See also pdfseparate and pdfunite from poppler-utils. pdfseparate breaks the file into one file per page which makes it relatively easy to reassemble at will later on with pdfunite, manually or (semi-)automatically.

Like with zsh:

autoload zargs

reunite() pdfunite "$@" file-$1-$argv[-1].pdf

pdfseparate file.pdf p%d
zargs -n 5 p<->(n) -- reunite
rm -f p<->

would split file.pdf into file-p1-p5.pdf, file-p6-p10.pdf...

| improve this answer | |
  • Nice. It creates lots of temporary files, though. – Raphael Mar 6 '13 at 6:46
  • 1
    This script worked perfectly with me, after realizing that I should add #!/bin/zsh as a first line. And installing Z Shell, of course... Those details might not be obvious to beginners. – Leonardo Castro Apr 11 '17 at 19:02
3

I find Python with the PyPdf library convenient for those jobs that pdftk doesn't do conveniently (or at all).

#!/usr/bin/env python
import sys
from pyPdf import PdfFileWriter, PdfFileReader

# Command line parsing
if len(sys.argv) < 2 or sys.argv[1][-4:] != '.pdf':
    sys.stderr.writeln('Usage: ' + sys.argv[0] + ''' FILE.pdf N
Split FILE.pdf into chunks of N pages each.''')
    exit(3)
pages_per_file = int(sys.argv[2])

base_name = sys.argv[1][:-4] + '-'
input_pdf = PdfFileReader(open(sys.argv[1]))
output_pdf = PdfFileWriter()
num_pages = input_pdf.getNumPages()
for i in xrange(num_pages):
    output_pdf.addPage(input_pdf.getPage(i))
    if (i + 1) % pages_per_file == 0 or i + 1 == num_pages:
        output_file = open(base_name + str(i / pages_per_file + 1) + '.pdf', "wb")
        output_pdf.write(output_file)
        output_file.close()
        output_pdf = PdfFileWriter()
| improve this answer | |
  • I'm getting this error: Traceback (most recent call last): File "./dividePDF.py", line 23, in <module> if (i + 1) % pages_per_file == 0: flush() File "./dividePDF.py", line 18, in flush output_pdf.write(output_file) UnboundLocalError: local variable 'output_pdf' referenced before assignment – Leonardo Castro Apr 11 '17 at 12:47
  • Before that, I was getting this error: Traceback (most recent call last): File "./dividePDF.py", line 20, in <module> for i in xrange(input_pdf.getNumPages(input_pdf)): TypeError: getNumPages() takes exactly 1 argument (2 given) So I changed input_pdf.getNumPages(input_pdf) to input_pdf.getNumPages() and got the other error. – Leonardo Castro Apr 11 '17 at 12:49
  • 1
    @LeonardoCastro Thanks for the bug report, I fixed the script. – Gilles 'SO- stop being evil' Apr 13 '17 at 0:50
  • I just used this script with N=4, but the first "chunk" always had 3 pages instead of 4. The following chunks were OK. I changed the order of lines "if (i + 1) % pages_per_file == 0: flush()" and "output_pdf.addPage(input_pdf.getPage(i))" and it worked right. – Leonardo Castro Jun 19 '17 at 20:01
  • 1
    @LeonardoCastro Thanks again, I fixed that in a slightly different way and fixed a bug when the last file is shorter because the number of pages is not a multiple of the chunk size. – Gilles 'SO- stop being evil' Jun 19 '17 at 20:18
2

The solution posted by Raphael is flawed: if you have an uneven number of pages, the last ones are just ignored. There it is an improved solution that works also with an uneven number of pages. Again, assumes that you have the number of pages per chunk in $pagesper and the filename of the source PDF in $file.

number=$(pdfinfo -- "$file" 2> /dev/null | awk '$1 == "Pages:" {print $2}')

count=$((($number+$pagesper-1)/$pagesper))
filename=${file%.pdf}

counter=0
while [ "$count" -gt "$counter" ]; do
  start=$((counter*pagesper + 1));
  end=$((start + pagesper - 1));
  if [ $end -gt $number ]; then
    end=$number
  fi

  counterstring=$(printf %04d "$counter")
  pdftk "$file" cat "${start}-${end}" output "${filename}_${counterstring}.pdf"
  counter=$((counter + 1))
done
| improve this answer | |
  • Good catch, thanks! You could just have edited that into my answer, though. – Raphael Jul 4 '14 at 12:00
  • Oh sorry, I tought I couldn't edit someone else answer with low reputation. – unlink Jul 7 '14 at 15:47
  • You can, kind of; the edit will be reviewed by high-reps. Given that you fixed an actual bug, I assume they would have accepted it! (You get +2 rep for accepted edits, too.) – Raphael Jul 7 '14 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.