33

I have a large number of PDF files which have two slides to a page (for printing).

The format is A4 pages each with two slides setup like so:

-----------
| slide 1 |
-----------
| slide 2 |
-----------

How can I generate a new PDF file with one slide per page?

Happy to use GUI, CLI, scripts or even interface with a language's PDF library; but I do need the text on the slides to still be selectable.

stackoverflowuser95
  • 1,992
  • 3
  • 20
  • 30

10 Answers10

20

PDF Scissors allowed me to bulk split (crop) all pages in a PDF.

Nick
  • 2,827
  • 4
  • 29
  • 39
stackoverflowuser95
  • 1,992
  • 3
  • 20
  • 30
16

mutool works brillantly for this. The example below will chop each page of input.pdf into 3 horizontal and 8 vertical parts (thus creating 24 pages of output for each 1 of input):

mutool poster -x 3 -y 8 input.pdf output.pdf

To install mutool, just install mupdf, which is probably packaged with most GNU/Linux distributions.

(Credits to marttt.)

On debian based linux systems like ubuntu, you can install it using

sudo apt install mupdf
sudo apt install mupdf-tools
jaggi
  • 357
  • 1
  • 4
  • 17
Skippy le Grand Gourou
  • 6,976
  • 4
  • 60
  • 76
  • mutool is a very powerful little program. I recommend taking a look at it's manual page (http://manpages.ubuntu.com/manpages/trusty/man1/mutool.1.html). – Waldir Leoncio Jun 17 '16 at 16:09
  • When I tried using this command (in my case mutool poster -y 2 input.pdf output.pdf) the resulting output.pdf had its pages sorted incorrectly. Is there any way to fix this? I couldn't find it in the man page – kaslusimoes Dec 15 '17 at 11:58
  • 2
    @kaslusimoes I guess your input file orientation is not consistent with `mutool` expectations, in which case you could just use e.g. `pdf180` (from `pdfjam`) on your input file before feeding `mutool` with it. If on the other hand your input file ordering is more complicated, you could just resort pages manually with `mutool clean input.pdf output.pdf 2,1,3,4,6,5` where `2,1,3,4,6,5` is the new ordering you'd like. – Skippy le Grand Gourou Dec 18 '17 at 13:24
12

You can use a Python library called PyPDF. This function will split double pages no matter what the page orientation is:

import copy
import math
import pyPdf

def split_pages(src, dst):
    src_f = file(src, 'r+b')
    dst_f = file(dst, 'w+b')

    input = pyPdf.PdfFileReader(src_f)
    output = pyPdf.PdfFileWriter()

    for i in range(input.getNumPages()):
        p = input.getPage(i)
        q = copy.copy(p)
        q.mediaBox = copy.copy(p.mediaBox)

        x1, x2 = p.mediaBox.lowerLeft
        x3, x4 = p.mediaBox.upperRight

        x1, x2 = math.floor(x1), math.floor(x2)
        x3, x4 = math.floor(x3), math.floor(x4)
        x5, x6 = math.floor(x3/2), math.floor(x4/2)

        if x3 > x4:
            # horizontal
            p.mediaBox.upperRight = (x5, x4)
            p.mediaBox.lowerLeft = (x1, x2)

            q.mediaBox.upperRight = (x3, x4)
            q.mediaBox.lowerLeft = (x5, x2)
        else:
            # vertical
            p.mediaBox.upperRight = (x3, x4)
            p.mediaBox.lowerLeft = (x1, x6)

            q.mediaBox.upperRight = (x3, x6)
            q.mediaBox.lowerLeft = (x1, x2)

        output.addPage(p)
        output.addPage(q)

    output.write(dst_f)
    src_f.close()
    dst_f.close()
xilopaint
  • 699
  • 1
  • 7
  • 16
moraes
  • 13,213
  • 7
  • 45
  • 59
10

Briss is "a simple cross-platform (Linux, Windows, Mac OSX) application for cropping PDF files. A simple user interface lets you define exactly the crop-region by fitting a rectangle on the visually overlaid pages." It's open source (GPL).

Works well for me. The GUI is minimal, but functional. It can also be used from the command line.

Nicolas Payette
  • 14,847
  • 1
  • 27
  • 37
8

Thanks to Matt Gumbley for his Python Script. I have modified that Python script such that it now also works with PDFs that contain portrait and landscape pages and cropped pages:

# -*- coding: utf-8 -*-
"""
Created on Thu Feb 26 08:49:39 2015

@author: Matt Gumbley  (stackoverflow)
changed by Hanspeter Schmid to deal with already cropped pages
"""

import copy
import math
from PyPDF2 import PdfFileReader, PdfFileWriter

def split_pages2(src, dst):
    src_f = file(src, 'r+b')
    dst_f = file(dst, 'w+b')

    input = PdfFileReader(src_f)
    output = PdfFileWriter()

    for i in range(input.getNumPages()):
        # make two copies of the input page
        pp = input.getPage(i)
        p = copy.copy(pp)
        q = copy.copy(pp)
        
        # the new media boxes are the previous crop boxes
        p.mediaBox = copy.copy(p.cropBox)
        q.mediaBox = copy.copy(p.cropBox)
                
        x1, x2 = p.mediaBox.lowerLeft
        x3, x4 = p.mediaBox.upperRight
        
        x1, x2 = math.floor(x1), math.floor(x2)
        x3, x4 = math.floor(x3), math.floor(x4)
        x5, x6 = x1+math.floor((x3-x1)/2), x2+math.floor((x4-x2)/2)

        if (x3-x1) > (x4-x2):
            # horizontal
            q.mediaBox.upperRight = (x5, x4)
            q.mediaBox.lowerLeft = (x1, x2)

            p.mediaBox.upperRight = (x3, x4)
            p.mediaBox.lowerLeft = (x5, x2)
        else:
            # vertical
            p.mediaBox.upperRight = (x3, x4)
            p.mediaBox.lowerLeft = (x1, x6)

            q.mediaBox.upperRight = (x3, x6)
            q.mediaBox.lowerLeft = (x1, x2)


        p.artBox = p.mediaBox
        p.bleedBox = p.mediaBox
        p.cropBox = p.mediaBox

        q.artBox = q.mediaBox
        q.bleedBox = q.mediaBox
        q.cropBox = q.mediaBox
        
        output.addPage(q)
        output.addPage(p)
        

    output.write(dst_f)
    src_f.close()
    dst_f.close()
xilopaint
  • 699
  • 1
  • 7
  • 16
2

Here is how I did it with pdfrw:

import sys, os, pdfrw
writer = pdfrw.PdfWriter()
for page in pdfrw.PdfReader('input.pdf').pages:
    for y in [0, 0.5]:
        newpage = pdfrw.PageMerge()    
        newpage.add(page, viewrect=(0, y, 1, 0.5))
        writer.addpages([newpage.render()])
writer.write('output.pdf')

Short and working!

If you want it rotated (example: input A4 portrait, output 2 A5 portrait and not landscape):

import sys, os, pdfrw
writer = pdfrw.PdfWriter()
for page in pdfrw.PdfReader('input.pdf').pages:
    for y in [0, 0.5]:
        newpage = pdfrw.PageMerge()    
        newpage.add(page, viewrect=(0, y, 1, 0.5))
        p = newpage.render()
        p.Rotate = 270
        writer.addpages([p])
writer.write('output.pdf')
xilopaint
  • 699
  • 1
  • 7
  • 16
Basj
  • 41,386
  • 99
  • 383
  • 673
1

Try BRISS.

alt text

It lets you split each page into as many subpages as you want by defining regions with a GUI. It groups all similar pages into groups for you, so you can define regions for that group once.

It's cross-platform, free, and open-source.

(copy-pasted from https://superuser.com/a/235327/35237)

Community
  • 1
  • 1
Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
0

If using a Java or .Net library is ok for you, you can use iText / iTextSharp.

An example for tiling an existing document can be found in the book iText in Action, 2nd edition, in the freely available chapter 6: TilingHero.java / TilingHero.cs.

mkl
  • 90,588
  • 15
  • 125
  • 265
0

In my case, the resulting PDF looked fine in Adobe Reader and Mac preview, but did not appear to have been split into separate pages at all when viewing on iOS.

I used Python 2.7.8 and PyPDF2, and modified the script as follows, which worked fine (and reordered the pages left/right, rather than right/left).

import copy
import math
from PyPDF2 import PdfFileReader, PdfFileWriter

def split_pages(src, dst):
    src_f = file(src, 'r+b')
    dst_f = file(dst, 'w+b')

    input = PdfFileReader(src_f)
    output = PdfFileWriter()

    for i in range(input.getNumPages()):
        p = input.getPage(i)
        q = copy.copy(p)
        q.mediaBox = copy.copy(p.mediaBox)

        x1, x2 = p.mediaBox.lowerLeft
        x3, x4 = p.mediaBox.upperRight

        x1, x2 = math.floor(x1), math.floor(x2)
        x3, x4 = math.floor(x3), math.floor(x4)
        x5, x6 = math.floor(x3/2), math.floor(x4/2)

        if x3 > x4:
            # horizontal
            p.mediaBox.upperRight = (x5, x4)
            p.mediaBox.lowerLeft = (x1, x2)

            q.mediaBox.upperRight = (x3, x4)
            q.mediaBox.lowerLeft = (x5, x2)
        else:
            # vertical
            p.mediaBox.upperRight = (x3, x4)
            p.mediaBox.lowerLeft = (x1, x6)

            q.mediaBox.upperRight = (x3, x6)
            q.mediaBox.lowerLeft = (x1, x2)

        p.artBox = p.mediaBox
        p.bleedBox = p.mediaBox
        p.cropBox = p.mediaBox
    
        q.artBox = q.mediaBox
        q.bleedBox = q.mediaBox
        q.cropBox = q.mediaBox

        output.addPage(q)
        output.addPage(p)

    output.write(dst_f)
    src_f.close()
    dst_f.close()
double-beep
  • 5,031
  • 17
  • 33
  • 41
Matt Gumbley
  • 307
  • 2
  • 8
-1

With mupdf-1.8-windows-x64, in win10 CMD, you need to have 'poster ' (followed by space and without quotes) before the horizontal parameter (-x ). For example for a double-paged scan to PDF:

mutool poster -x 2 -y 1 C:\Users\alfie\Documents\SNM\The_Ultimate_Medicine.pdf C:\Users\alfie\Documents\ebooks\The_Ultimate_Medicine.pdf

What a wonderful tool! Merci infiniment !.. (and the output file ~9MB is only 52KB bigger than the original!)

ketan
  • 19,129
  • 42
  • 60
  • 98
Gepi
  • 1