Podziel strony w pdf

67

Mam zeskanowany plik pdf, który zeskanował dwie strony na jednej stronie wirtualnej (strona w pliku pdf).

Rozdzielczość jest dobrej jakości. Problem polega na tym, że muszę powiększać podczas czytania i przeciągać od lewej do prawej.
Czy istnieje jakaś komenda ( convert, pdftk...) lub skrypt, który można przekonwertować plik PDF z normalnych stron (jedna strona z książki = jedna strona w pliku PDF)?

xralf
źródło
1
Chociaż nie jest to najbardziej pozytywna odpowiedź, ta naprawdę mnie zaskoczyła. Jest prosty, krótki, szybki i elegancki. Pomyślałem, że warto o tym wspomnieć tutaj, ponieważ czasami jesteśmy zbyt leniwi, aby przewijać w dół do innych odpowiedzi ...
Peque
W przypadku rekordów operację odwrotną (łączenie wielu stron) można uzyskać z wiersza poleceń (zamiast „drukuj do pliku”) za pomocą pdfnup, z pdfjampakietu.
Skippy le Grand Gourou,

Odpowiedzi:

46

Oto mały skrypt Pythona korzystający z biblioteki PyPdf, która dobrze wykonuje to zadanie. Zapisz go w skrypcie o nazwie un2up(lub cokolwiek chcesz), spraw, aby był wykonywalny ( chmod +x un2up) i uruchom go jako 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)

Zignoruj ​​wszelkie ostrzeżenia o wycofaniu; tylko opiekunowie PyPdf muszą się tym zajmować.

Jeśli dane wejściowe są zorientowane w nietypowy sposób, może być konieczne użycie różnych współrzędnych podczas obcinania stron. Zobacz Dlaczego mój kod nie podzielił poprawnie każdej strony na zeskanowanym pliku pdf?


Na wszelki wypadek przydatna jest moja wcześniejsza odpowiedź, która wykorzystuje kombinację dwóch narzędzi plus pewną ręczną interwencję:

  • Pdfjam (przynajmniej wersja 2.0), oparty na pakiecie LaTeX pdfpages , do przycinania stron;
  • Pdftk , aby ponownie połączyć lewą i prawą połówkę.

Oba narzędzia są potrzebne, ponieważ o ile wiem, strony pdf nie są w stanie zastosować dwóch różnych transformacji do tej samej strony w jednym strumieniu. W wywołaniu do pdftkzamień 42 na liczbę stron w dokumencie wejściowym ( 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

Jeśli nie masz pdfjam 2.0, wystarczy mieć instalację PDFLaTeX z pakietem pdfpages (na Ubuntu: potrzebujesz texlive-latex-zalecany Zainstaluj zalecane texlive-latex i być może (na Ubuntu: texlive-fonts-zalecany Zainstaluj zalecane czcionki texlive ), i użyj następującego sterownika plik 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}

Następnie uruchom następujące polecenia, zastępując 42 liczbą stron w pliku wejściowym (które należy wywołać 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
Gilles
źródło
Biblioteka PyPdf działa idealnie. Zmieniłem go tylko trochę i uruchomiłem z python conv_pdf.py res.pdf . Jak uruchomisz skrypt shebang z wiersza poleceń?
xralf
Chciałbym również wypróbować wersję z pdfjam (z powodu niewielkiego skalowania), ale po instalacji pakietu pdfjam moja powłoka nie rozpoznaje pdfjampolecenia.
xralf
@xralf: Mój skrypt Pythona po prostu odczytuje ze standardowego wejścia i zapisuje na standardowe wyjście. Wersja pdfjam wymaga pdfjam 2.0; to tylko małe opakowanie wokół stron pdf, a ja dodałem trochę generowanego LaTeXa, abyś mógł z niego korzystać bezpośrednio. Problem ze skalowaniem jest prawdopodobnie możliwy do rozwiązania w przypadku pypdf, może to być problem z rozmiarem strony (mogę nie być w stanie pomóc, jeśli podasz więcej szczegółów na temat tego, co się dzieje, a zwłaszcza rozmiarów stron).
Gilles
Dziękuję, różnica jest w nieco nieco gorszej rozdzielczości, ale to nie ma znaczenia. Wrócę do niego, gdy dowiem się więcej o lateksie (jest to dla mnie teraz zbyt skomplikowane i rozwiązanie jest naprawdę dobre z PyPdf).
xralf
1
@Gilles Versy przydatny skrypt. Spodziewałem się zobaczyć coś takiego w pdfjam, pdftk. W każdym razie niektóre osoby mogą chcieć modyfikacji w celu podziału stron na inne osie i korzystania z innego porządku. Jest to możliwe po zmianie kilku wierszy i użyciuq.mediaBox.lowerRight = (w, h/2)
tylko
52

Tylko dodatek, ponieważ miałem problemy ze skryptem Pythona (i kilkoma innymi rozwiązaniami): dla mnie mutooldziałało świetnie. Jest to prosty i mały dodatek dostarczany z eleganckim mupdfczytnikiem. Możesz więc spróbować:

mutool poster -y 2 input.pdf output.pdf

Dla podziałów poziomych, wymienić yz x. I oczywiście możesz połączyć te dwa, aby uzyskać bardziej złożone rozwiązania.

Naprawdę się cieszę, że to znalazłem (po latach codziennego użytkowania mupdf :)

mutooljest dostarczany z mupdf od wersji 1.4: http://www.mupdf.com/news


Instalowanie mupdfi mutoolze źródła:

wget http://www.mupdf.com/downloads/mupdf-1.8-source.tar.gz
tar -xvf mupdf-1.8-source.tar.gz
cd mupdf-1.8-source
sudo make prefix=/usr/local install

Lub przejdź do strony pobierania, aby znaleźć nowszą wersję.

martz
źródło
3
Miałem djvu ... Zamieniłem go w postScript (dość szybko), a następnie w pdf (żółw wolny) - i na koniec mutool wyciął go tak szybko, że myślałem, że to nie działa - zadziałało!
Julien Puydt
2
tak, byłem też bardzo zadowolony z prędkości.
martz
3
Ten jest najłatwiejszy i lepszy. mutoolzostał stworzony do tego. Uważaj też -y, myślę, że w większości przypadków to, czego chcesz -x.
fiatjaf
2
To narzędzie jest bardzo szybkie, ale mam problem z kolejnością stron. Polecenie przydziela prawą stronę na pierwszej pozycji, a lewą stronę na drugiej. Czy ktoś może mi pomóc z tym problemem?
garciparedes
16

Imagemagick może to zrobić w jednym kroku:

$ convert in.pdf -crop 50%x0 +repage out.pdf
Tomas
źródło
1
Dzięki. Jeśli dodam -density 400parametr, ma on jeszcze lepszą jakość.
xralf
11
Wygląda na to, że konwersja używa rastra jako formatu pośredniego. Powoduje to rozmazany wygląd, nawet jeśli oryginalny plik PDF zawiera obiekty wektorowe.
ony
Czy ktoś wie, jak to zrobić bez rasteryzacji zawartości strony po drodze ... lub przynajmniej ustawić wyższą rozdzielczość?
Tomislav Nakic-Alfirevic
to renderowało teksty na obrazy i tworzyło pdf z obrazów. Może dobre dla zdjęć, ale bezużyteczne do wydobywania tekstu.
andrej
6

Polecenie Konwertuj ImageMagick może pomóc przyciąć plik na 2 części. Zobacz http://www.imagemagick.org/Usage/crop/

Gdybym był tobą, napisałbym skrypt (powłoki) w następujący sposób:

  1. Podziel plik na pdfsam : 1 strona = 1 plik na dysku (Format nie ma znaczenia. Wybierz taki, który zna ImageMagick. Po prostu wezmę PS lub PDF.
  2. Dla każdej strony przytnij pierwszą połowę i umieść ją w pliku o nazwie $ {PageNumber} A

  3. Przytnij drugą połowę i umieść ją w pliku o nazwie $ {PageNumber} B.

    Otrzymasz 1A.pdf, 1B.pdf, 2A.pdf, 2B.pdf itp.

  4. Teraz złóż to ponownie w nowym pliku PDF. Można to zrobić na wiele sposobów.
TIK Tak
źródło
1
Czy użycie ImageMagick nie rasteryzowałoby plików? I powinieneś wyjaśnić tę ostatnią część inline, szczególnie na korzyść nie-frankofonów na widowni.
Gilles
Ponieważ nie musisz rozumieć francuskiego. To po prostu pokazuje, w jaki sposób można użyć samego programu do konwersji, pdftk lub ghostscript (gs) ImageMagick, aby osiągnąć ten cel. Lubię używać pdftk. „Rasterowanie” nie ma znaczenia, ponieważ jest to zeskanowany dokument.
tiktak
6

Na podstawie odpowiedzi Gillesa i tego, jak znaleźć liczbę stron w formacie PDF, którą napisałem

#!/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

Więc mogę biegać

./split.sh my.pdf 50 1.2

gdzie 50 dla dostosowania marginesu i 1,2 dla skali.

Anton Bessonov
źródło
4

Oto odmiana kodu PyPDF opublikowanego przez Gillesa. Ta funkcja będzie działać bez względu na orientację strony:

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()
moraes
źródło
2

Najlepszym rozwiązaniem było mutool patrz wyżej:

sudo apt install mupdf-tools pdftk

podział:

mutool poster -y 2 input.pdf output.pdf

ale musisz obrócić strony w lewo:

pdftk output.pdf cat 1-endleft output rotated.pdf
Eduard Florinescu
źródło
Nadal się nie pokrywają ...
MUY Belgia
1

Na podstawie odpowiedzi Benjamina z AskUbuntu poleciłbym użycie narzędzia GUI o nazwie gscan2pdf .

  1. Zaimportuj zeskanowany plik PDF do gscan2pdf. Pamiętaj, że pliki PDF inne niż obraz mogą nie działać. Skany są w porządku, więc nie musisz się martwić.

    wprowadź opis zdjęcia tutaj

  2. Może to chwilę potrwać, w zależności od rozmiaru dokumentu. Poczekaj, aż się załaduje.

  3. Naciśnij Ctrl + A, aby zaznaczyć wszystkie strony, a następnie obróć je (Ctrl + Shift + C) , jeśli to konieczne.

    wprowadź opis zdjęcia tutaj

  4. Przejdź do Narzędzia >> Oczyść . Wybierz Układ jako podwójne i # strony wyjściowe = 2 .

    wprowadź opis zdjęcia tutaj

  5. Naciśnij OK i poczekaj, aż zadanie zostanie zakończone.

    wprowadź opis zdjęcia tutaj

  6. Zapisz plik PDF. Gotowy.

Nanashi No Gombe
źródło
Przetestowane, nie powiodło się ze złożonymi dokumentami pdf z ogromną liczbą obrazów.
MUY Belgia
0

Rozwiązanie Moraes nie działało dla mnie. Głównym problemem były obliczenia x5 i x6. W tym przypadku należy wziąć pod uwagę przesunięcie, tj. Jeśli wartość lowerLeft nie jest na (0,0)

Oto kolejna odmiana, z dodatkowymi adaptacjami do użycia PyPDF2 i python 3:

import copy
import math
import PyPDF2
import sys
import io 

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

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

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

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

        x1, x2 = math.floor(x1), math.floor(x2)
        x3, x4 = math.floor(x3), math.floor(x4)

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

        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.lowerLeft = (x1, x6)
            p.mediaBox.upperRight = (x3, x4)

            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()

if __name__ == "__main__":
    if ( len(sys.argv) != 3 ):
        print ('Usage: python3 double2single.py input.pdf output.pdf')
        sys.exit(1)

    split_pages(sys.argv[1], sys.argv[2])
vbar
źródło