Como mesclar 2 arquivos PDF com a ordem das páginas intercaladas?

13

Tenho um documento com várias páginas impressas em frente e verso para digitalizar com um scanner linear em massa. Portanto, como resultado, recebo 2 arquivos PDF: um contendo todas as páginas ímpares e o segundo contendo todas as páginas pares. Eu preciso mesclá-los da maneira natural:

1. <- 1.1. (odd.pdf page 1 to result.pdf page 1)
2. <- 2.1. (even.pdf page 1 to result.pdf page 2)
3. <- 1.2. (odd.pdf page 2 to result.pdf page 3)
4. <- 2.2. (even.pdf page 2 to result.pdf page 4)

etc.

Ivan
fonte
Basta encontrar um analisador de PDF e fazer uma classificação de mesclagem, como outras coisas.
Daisy
1
Se o Stephane não resolver o seu problema, você pode tentar o módulo perl CAM::PDF, darei um script mais tarde. Os dois pdf têm a mesma contagem de páginas?
Daisy30:

Respostas:

7

Veja os comandos pdfseparatee pdfunitede poppler-utils. O primeiro para separar as páginas de cada documento em arquivos individuais e o segundo para mesclá-las na ordem desejada em um novo documento.

Observe também que, como os scanners fornecem imagens rasterizadas de qualquer maneira (que algumas como a sua podem concatenar em arquivos PDF), talvez você possa configurá-lo para gerar imagens (png, tiff ...) e fazer a concatenação em um PDF com ImageMagick.

Stéphane Chazelas
fonte
Isso soa como o que eu preciso, vamos tentar ...
Ivan
1
De fato. Excelente. Simples de usar para fazer o que eu preciso. a propósito, é claro que pesquisei no Google antes de perguntar e as soluções que achei exatamente iguais eram notavelmente mais complexas.
30712 Ivan
Eu tentei isso no Ubuntu 18.04 (com o script útil abaixo do @TCF) e ele transformou dois arquivos de ~ 5,5Mb em um arquivo de 197Mb; portanto, enquanto ele fazia o trabalho, não era utilizável (eu precisava enviar o resultado por e-mail!) .
Reuben Thomas
12

O pdftk possui um comando aleatório que agrupa as páginas:

pdftk A=odd.pdf B=even.pdf shuffle A B output collated.pdf
djao
fonte
1
Isso funcionou bem para mim, mas com um ajuste para inverter as páginas pares (dado que eu as digitalizei sem antes reverter a ordem das páginas): pdftk A = recto.pdf B = verso.pdf shuffle Uma saída do Bend-1. pdf
Reuben Thomas
Fantástico, graças - isso funciona perfeitamente
infomaniac
2

Apenas uma bashfoto rápida usando pdfjam:

Crie uma matriz de argumentos de entrada:

for k in $(seq 1 ${N_PAGES}); do
    PAGES+=(odd.pdf);
    PAGES+=($k);
    PAGES+=(even.pdf);
    PAGES+=($k);
done

Isso deve permitir que você o use como lista de entrada para pdfjoin:

 pdfjoin ${PAGES[@]} --outfile shuffled.pdf
fheub
fonte
2
Deve-se notar que pdfjoiné um script de wrapper em torno do pdfjamqual ele próprio é um script de wrapper em torno do pdfpagespacote LaTeX (e pdflatex); portanto, significa que ele traz o LaTeX como uma dependência.
Stéphane Chazelas 30/10/12
1

Você pode usar o módulo Mix no PDFsam Basic (de código aberto e gratuito) ou on-line usando o recurso Alternate & Mix no Sejda

Andrea Vacondio
fonte
1
Sem dúvida a melhor solução: código aberto, sem necessidade de instalação. 2 cliques e feito;) #
nathan 24/12
0

Eu estava procurando fazer basicamente a mesma coisa, e a resposta de Stéphane Chazelas foi muito útil. Faço isso com frequência suficiente para escrever um script Python simples para automatizar as coisas, usando os comandos que ele sugeriu. Por padrão, ele reverte a ordem das páginas pares, mas isso pode ser suprimido com um sinalizador de linha de comando.

A pergunta é meio antiga, então espero que as necessidades do solicitante original já tenham sido atendidas. No entanto, é possível que o script seja útil para as pessoas que chegarem aqui no futuro, então eu o coloquei abaixo.

#!/usr/bin/python
"""A simple script to merge two PDFs."""

import argparse
from os import listdir
from os.path import join as opjoin
import shutil
from subprocess import check_call, CalledProcessError
import tempfile

SEPARATE = 'pdfseparate %s %s'
MERGE = 'pdfunite %s %s'

def my_exec(command):
    """Execute a command from a shell, ignoring errors."""
    try:
        check_call(command, shell=True)
    except CalledProcessError:
        pass

def run(odd, even, out, reverse_odd=False, reverse_even=True):
    """Interleave odd and even pages from two PDF files."""
    folder = tempfile.mkdtemp()
    my_exec(SEPARATE % (odd, opjoin(folder, 'odd%d.pdf')))
    my_exec(SEPARATE % (even, opjoin(folder, 'even%d.pdf')))
    odd_files = []
    even_files = []
    for curr_file in listdir(folder):
        filepath = opjoin(folder, curr_file)
        if curr_file.startswith('odd'):
            odd_files.append((filepath, int(curr_file[3:-4])))
        elif curr_file.startswith('even'):
            even_files.append((filepath, int(curr_file[4:-4])))
    func = lambda x: x[1]
    odd_files.sort(key=func, reverse=reverse_odd)
    even_files.sort(key=func, reverse=reverse_even)
    parts = []
    for line in zip(odd_files, even_files):
        parts.append(line[0][0])
        parts.append(line[1][0])
    my_exec(MERGE % (' '.join(parts), out))
    shutil.rmtree(folder)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Merge two PDF files.')
    parser.add_argument('odd_pages', help='PDF containing the odd pages.')
    parser.add_argument('even_pages', help='PDF containing the even pages.')
    parser.add_argument('output_file', help='The target output file.')
    parser.add_argument('--reverse-odd', action='store_true', 
                        help='Insert the odd pages in reverse order.')
    parser.add_argument('--no-reverse-even', action='store_true',
                        help='Suppress reversal of the even pages.')
    args = parser.parse_args()
    run(args.odd_pages, args.even_pages, args.output_file,
        args.reverse_odd, not args.no_reverse_even)
TCF
fonte
0

Me deparei com esse script do bash fazendo isso, ele pressupõe que você digitalizou as páginas pares na ordem inversa, mas você pode alterar isso removendo o -rditado na linha evenpages=($(ls "$evenbase-$key-"* | sort -r))(esta é a linha 46)

#!/bin/bash
# Copyright Fabien André <[email protected]>
# Distributed under the MIT license
# This script interleaves pages from two distinct PDF files and produces an
# output PDF file. The odd pages are taken from a first PDF file and the even
# pages are taken from a second PDF file passed respectively as first and second
# argument.
# The first two pages of the output file are the first page of the
# odd pages PDF file and the *last* page of the even pages PDF file. The two
# following pages are the second page of the odd pages PDF file and the
# second to last page of the even pages PDF file and so on.
#
# This is useful if you have two-sided documents scanned each side on a
# different file as it can happen when using a one-sided Automatic Document
# Feeder (ADF)
#
# It does a similar job to :
# https://github.com/weltonrodrigo/pdfapi2/blob/46434ab3f108902db2bc49bcf06f66544688f553/contrib/pdf-interleave.pl
# but only requires bash (> 4.0) and poppler utils.
# Print usage/help message
function usage {
echo "Usage: $0 <PDF-even-pages-file> <PDF-odd-pages-file>"
exit 1
}
# Add leading zeros to pad numbers in filenames matching the pattern
# $prefix$number.pdf. This allows filenames to be easily sorted using
# sort.
# $1 : The prefix of the filenames to consider
function add_leading_zero {
prefix=$1
baseprefix=$(basename $prefix | sed -e 's/[]\/()$*.^|[]/\\&/g')
dirprefix=$(dirname $prefix)
for filename in "$prefix"*".pdf"
do
base=$(basename "$filename")
index=$(echo "$base" | sed -rn "s/$baseprefix([0-9]+).pdf$/\1/p")
newbase=$(printf "$baseprefix%04d.pdf" $index)
mv $filename "$dirprefix/$newbase"
done
}
# Interleave pages from two distinct PDF files and produce an output PDF file.
# Note that the pages from the even pages file (second file) will be used in
# the reverse order (last page first).
# $1 : Odd pages filename
# $2 : Odd pages filename with extension removed
# $3 : Even pages filename
# $4 : Even pages filename with extension removed
# $5 : Unique key used for temporary files
# $6 : Output file
function pdfinterleave {
oddfile=$1
oddbase=$2
evenfile=$3
evenbase=$4
key=$5
outfile=$6
# Odd pages
pdfseparate $oddfile "$oddbase-$key-%d.pdf"
add_leading_zero "$oddbase-$key-"
oddpages=($(ls "$oddbase-$key-"* | sort))
# Even pages
pdfseparate $evenfile "$evenbase-$key-%d.pdf"
add_leading_zero "$evenbase-$key-"
evenpages=($(ls "$evenbase-$key-"* | sort -r))
# Interleave pages
pages=()
for((i=0;i<${#oddpages[@]};i++))
do
pages+=(${oddpages[i]})
pages+=(${evenpages[i]})
done
pdfunite ${pages[@]} "$outfile"
rm ${oddpages[@]}
rm ${evenpages[@]}
}
if [ $# -lt 2 ]
then
usage
fi
if [ $1 == $2 ]
then
echo "Odd pages file and even pages file must be different." >&2
exit 1
fi
if ! hash pdfunite 2>/dev/null || ! hash pdfseparate 2>/dev/null
then
echo "This script requires pdfunite and pdfseparate from poppler utils" \
"to be in the PATH. On Debian based systems, they are found in the" \
"poppler-utils package"
exit 1
fi
oddbase=${1%.*}
evenbase=${2%.*}
odddir=$(dirname $oddbase)
oddfile=$(basename $oddbase)
evenfile=$(basename $evenbase)
outfile="$odddir/$oddfile-$evenfile-interleaved.pdf"
key=$(tr -dc "[:alpha:]" < /dev/urandom | head -c 8)
if [ -e $outfile ]
then
echo "Output file $outfile already exists" >&2
exit 1
fi
pdfinterleave $1 $oddbase $2 $evenbase $key $outfile
# SO - Bash command that prints a message on stderr
# http://stackoverflow.com/questions/2643165/bash-command-that-prints-a-message-on-stderr
# SO - Check if a program exists from a bash script
# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script
# SO - How to debug a bash script?
# http://stackoverflow.com/questions/951336/how-to-debug-a-bash-script
# SO - Escape a string for sed search pattern
# http://stackoverflow.com/questions/407523/escape-a-string-for-sed-search-pattern

Fonte

switch87
fonte