Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a scanned pdf file which has scanned two pages on one virtual page (page in pdf file).

The resolution is with good quality. The problem is I have to zoom when reading and drag from left to the right.
Is there some command (convert, pdftk, ...) or script that can convert this pdf file with normal pages (one page from book = one page in pdf file)?

share|improve this question

5 Answers 5

up vote 26 down vote accepted

Here's a small Python script using the PyPdf library that does the job neatly. Save it in a script called un2up (or whatever you like), make it executable (chmod +x un2up), and run it as a filter (un2up <2up.pdf >1up.pdf).

#!/usr/bin/env python
import copy, sys
from pyPdf import PdfFileWriter, PdfFileReader
input = PdfFileReader(sys.stdin)
output = PdfFileWriter()
for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
    q = copy.copy(p)
    (w, h) = p.mediaBox.upperRight
    p.mediaBox.upperRight = (w/2, h)
    q.mediaBox.upperLeft = (w/2, h)
    output.addPage(p)
    output.addPage(q)
output.write(sys.stdout)

Ignore any deprecation warning; only the PyPdf maintainers need be concerned with these.

If the input is oriented in an unusual way, you may need to use different coordinates when truncating the pages. See Why my code not correctly split every page in a scanned pdf?


Just in case it's useful, here's my earlier answer which uses a combination of two tools plus some manual intervention:

  • Pdfjam (at least version 2.0), based on the pdfpages LaTeX package, to crop the pages;
  • Pdftk, to put the left and right halves back together.

Both tools are needed because as far as I can tell pdfpages isn't able to apply two different transformations to the same page in one stream. In the call to pdftk, replace 42 by the numer of pages in the input document (2up.pdf).

pdfjam -o odd.pdf --trim '0cm 0cm 14.85cm 0cm' --scale 1.141 2up.pdf
pdfjam -o even.pdf --trim '14.85cm 0cm 0cm 0cm' --scale 1.141 2up.pdf
pdftk O=odd.pdf E=even.pdf cat $(i=1; while [ $i -le 42 ]; do echo O$i E$i; i=$(($i+1)); done) output all.pdf

In case you don't have pdfjam 2.0, it's enough to have a PDFLaTeX installation with the pdfpages package (on Ubuntu: you need texlive-latex-recommended Install texlive-latex-recommended and perhaps (on Ubuntu: texlive-fonts-recommended Install texlive-fonts-recommended), and use the following driver file driver.tex:

\batchmode
\documentclass{minimal}
\usepackage{pdfpages}
\begin{document}
\includepdfmerge[trim=0cm 0cm 14.85cm 0cm,scale=1.141]{2up.pdf,-}
\includepdfmerge[trim=14.85cm 0cm 0cm 0cm,scale=1.141]{2up.pdf,-}
\end{document}

Then run the following commands, replacing 42 by the number of pages in the input file (which must be called 2up.pdf):

pdflatex driver
pdftk driver.pdf cat $(i=1; pages=42; while [ $i -le $pages ]; do echo $i $(($pages+$i)); i=$(($i+1)); done) output 1up.pdf
share|improve this answer
    
The PyPdf library works perfect. I only changed it a little and run it with python conv_pdf.py res.pdf . How would you run your script shebang from commandline? –  xralf May 3 '11 at 8:03
    
I'd like to try the version with pdfjam (because of slight scaling) too, but after the installation of pdfjam package my shell won't recognize pdfjam command. –  xralf May 3 '11 at 8:34
    
@xralf: My python script just reads from standard input and writes to standard output. The pdfjam version requires pdfjam 2.0; it's only a small wrapper around pdfpages, and I've added the bit of LaTeX it generates so you can use that directly. The scaling issue is probably solvable with pypdf, it could be a page size issue (I may or may not be able to help if you give more details on what's happening and especially the page sizes involved). –  Gilles May 3 '11 at 10:22
    
Thank you, the difference is in very slightly worse resolution, but this doesn't matter. I will turn back to it when I know more about Latex (it's too complex for me now and the solution is really good with PyPdf). –  xralf May 3 '11 at 11:10
1  
@Gilles Versy useful script. I've expected to see something like that in pdfjam, pdftk. Anyway, some people may want some modifications to split pages over other axis and use different ordering. This is possible to with changing few lines and using q.mediaBox.lowerRight = (w, h/2) –  ony Feb 26 '12 at 20:44

ImageMagick's Convert command can help you to crop your file in 2 parts. See http://www.imagemagick.org/Usage/crop/

If I were you, I'd write a (shell) script like this:

  1. Split your file with pdfsam: 1 page = 1 file on disk (Format doesn't matter. Choose one that ImageMagick knows. I'd just take PS or PDF.
  2. For each page, crop the first half and put it to a file named ${PageNumber}A

  3. Crop the second half and put it to a file named ${PageNumber}B.

    You get 1A.pdf, 1B.pdf, 2A.pdf, 2B.pdf, etc.

  4. Now, assemble this again in a new PDF. There are many methods to do this.
share|improve this answer
    
Wouldn't using ImageMagick rasterize the files? And you should explain that last part inline, especially for the benefit of the non-francophones in the audience. –  Gilles May 2 '11 at 22:17
    
Because you don't need to understand French. It just show how you can use ImageMagick's convert, pdftk, or ghostscript (gs) alone to achieve this goal. I like using pdftk. "Rastering" doesn't matter as it's a scanned document. –  tiktak May 4 '11 at 9:29

Imagemagick can do it in one step:

$ convert in.pdf -crop 50%x0 +repage out.pdf
share|improve this answer
1  
Thanks. If I add the -density 400 parameter` it has even better quality. –  xralf May 20 '11 at 14:27
3  
It looks like convert uses raster as an intermediate format. That causes blurish look even when original PDF contains vector objects. –  ony Feb 26 '12 at 20:40
    
Does anyone know of a way to do this without rasterizing page contents along the way...or at least to set a higher resolution? –  Tomislav Nakic-Alfirevic Feb 28 '13 at 21:47

Based on answer from Gilles and how to find PDF page count I wrote

#!/bin/bash

pdforiginal=$1
pdfood=$pdforiginal.odd.pdf
pdfeven=$pdforiginal.even.pdf
pdfout=output_$1
margin=${2:-0}
scale=${3:-1}

pages=$(pdftk $pdforiginal dump_data | grep NumberOfPages | awk '{print $2}')

pagesize=$(pdfinfo $pdforiginal | grep "Page size" | awk '{print $5}')
margin=$(echo $pagesize/2-$margin | bc -l)

pdfjam -o $pdfood --trim "0cm 0cm ${margin}pt 0cm" --scale $scale $pdforiginal
pdfjam -o $pdfeven --trim "${margin}pt 0cm 0cm 0cm" --scale $scale  $pdforiginal

pdftk O=$pdfood E=$pdfeven cat $(i=1; while [ $i -le $pages ]; do echo O$i E$i; i=$(($i+1)); done) output $pdfout

rm $pdfood $pdfeven

So I can run

./split.sh my.pdf 50 1.2

where 50 for adjust margin and 1.2 for scale.

share|improve this answer

Here's a variation of the PyPDF code posted by Gilles. This function will work 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()
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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