Как я могу объединить PDF-файлы, чтобы каждый файл начинался с нечетного номера страницы?

11

Мне нужно объединить несколько дозированных PDF-файлов, и я хочу, чтобы все входные PDF-файлы начинались на нечетной странице выходного PDF-файла.

Пример: A.pdfимеет 3 страницы, B.pdfимеет 4 страницы. Я не хочу, чтобы мой вывод содержал 7 страниц. Мне нужен 8-страничный PDF, в котором страницы 1-3 взяты A.pdf, страница 4 пуста, а страницы 5-8 взяты B.pdf. Как я могу это сделать?

Я знаю о pdftk, но я не нашел такой опции на странице руководства.

Ян Вархол
источник

Ответы:

6

Библиотека PyPdf делает такие вещи легкими, если вы хотите написать немного на Python. Сохраните приведенный ниже код в скрипте с именем pdf-cat-even(или как вам угодно), сделайте его исполняемым ( chmod +x pdf-cat-even) и запустите его как фильтр ( ./pdf-cat-even a.pdf b.pdf >concatenated.pdf). Вам нужен pyPdf ≥1.13 для addBlankPageметода.

#!/usr/bin/env python
import copy, sys
from pyPdf import PdfFileWriter, PdfFileReader
output = PdfFileWriter()
output_page_number = 0
alignment = 2           # to align on even pages
for filename in sys.argv[1:]:
    # This code is executed for every file in turn
    input = PdfFileReader(open(filename))
    for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
        # This code is executed for every input page in turn
        output.addPage(p)
        output_page_number += 1
    while output_page_number % alignment != 0:
        output.addBlankPage()
        output_page_number += 1
output.write(sys.stdout)
Жиль "ТАК - перестань быть злым"
источник
Спасибо, это сработало для меня! Поскольку я предпочитаю читать имена файлов PDF из файла, я немного изменил ваш код и опубликовал его как отдельный ответ .
Ян Вархол
@JanekWarchol Если имена ваших файлов не содержат специальных символов оболочки, таких как пробел:./pdf-cat-even $(cat list-of-file-names.txt) >concatenated.pdf
Жиль "ТАК - перестать быть злым"
К сожалению, они содержат пробелы. Но, тем не менее, спасибо - я не осознавал, что это можно сделать таким образом.
Ян Вархол
@JanekWarchol Тогда вы можете использовать<list-of-file-names.txt tr '\n' '\0' | xargs -0 ./pdf-cat-even >concatenated.pdf
Жиль "ТАК - перестань быть злым"
3

Первый шаг - создать PDF-файл с пустой страницей. Вы можете легко сделать это с помощью множества программ (LibreOffice / OpenOffice, inkscape, (La) TeX, scribus и т. Д.)

Затем просто включите эту пустую страницу, где это необходимо:

pdftk A.pdf empty_page.pdf B.pdf output result.pdf 

Если вы хотите сделать это автоматически с помощью скрипта, вы можете использовать, например, pdftk file.pdf dump_data | grep NumberOfPages | egrep -o '[0-9]*'чтобы извлечь количество страниц.

jofel
источник
Это похоже на взлом. Хотя, если это работает, это работает, я полагаю.
Сэм Уитед
Этот подход почти сработал для меня: я написал скрипт, который создавал список pdf с добавлением epmtyPage.pdf, где это необходимо, но я не мог заставить pdftk правильно проанализировать этот список, если имена файлов содержали пробелы. Я пытался изменить значение IFS, используя кавычки, но безрезультатно - возможно, это ошибка pdftk. В любом случае, ответ с использованием pypdf работал для меня.
Ян Вархол
@JanekWarchol Какую версию pdftk вы использовали? По крайней мере pdftk 1.44 и новее, кажется, поддерживают пробелы в именах файлов.
Джофель
@jofel pdftk --versionвозвращает pdftk 1.44. Я помню, что мои более подкованные друзья провели, по крайней мере, 15 минут, пробуя разные вещи, чтобы получить эту работу, и бросили.
Ян Вархол
1

Ответ Жиля сработал для меня, но, поскольку мне нужно объединить много файлов, мне удобнее читать их имена из текстового файла. Я немного изменил код Жиля, чтобы сделать это, может быть, это поможет кому-то еще:

#!/usr/bin/env python

# requires PyPdf library, version 1.13 or above -
# its homepage is http://pybrary.net/pyPdf/
# running: ./this-script-name file-with-pdf-list > output.pdf

import copy, sys
from pyPdf import PdfFileWriter, PdfFileReader
output = PdfFileWriter()
output_page_number = 0

# every new file should start on (n*alignment + 1)th page
# (with value 2 this means starting always on an odd page)
alignment = 2

listoffiles = open(sys.argv[1]).read().splitlines()
for filename in listoffiles:
    # This code is executed for every file in turn
    input = PdfFileReader(open(filename))
    for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
        # This code is executed for every input page in turn
        output.addPage(p)
        output_page_number += 1
    while output_page_number % alignment != 0:
        output.addBlankPage()
        output_page_number += 1
output.write(sys.stdout)
Ян Вархол
источник
1

Вы также можете использовать LaTeX для этого (хотя я знаю, что это, вероятно, не то, что вы хотите). Должно работать что-то вроде следующего:

\documentclass{book}

\usepackage{pdfpages}

\begin{document}

\includepdf[pages=-]{A}
\cleardoublepage % Make sure we clear to an odd page
\includepdf[pages=-]{B} % This inserts all pages. Or you can specify specific pages, a range, or `{}` for a blank page

\end{document}

Обратите внимание, что \cleardoublepageвставляется только пустая страница с классами, созданными для двусторонней печати (например, книга)

Больше опций и информации pdfpagesможно найти на CTAN .

Сэм Уитед
источник
2
Чтобы включить все страницы автоматически, вы можете использовать \includepdf[pages=-]{...}.
Джофель
@jofel Спасибо, исправил вопрос. Я думаю, что это по умолчанию для всех страниц, я просто вставил его туда, чтобы показать, что можно было выбрать определенные страницы.
Сэм Уитед
@jofel Также \cleardoublepageвставляет пустую страницу, только если вы используете класс, созданный для двусторонней печати. Я использовал статью, которая не работает; Я исправил это и обновил вопрос, чтобы отразить это.
Сэм Уитед
\includepdfпо умолчанию включает только первую страницу (не все страницы). \documentclass[twoside]{article}работает также.
Джофель
Из того, что я вижу, я должен был бы явно написать все файлы, которые должны быть включены, так что это не достаточно хорошо для меня. Но все равно спасибо.
Ян Вархол
0

Вот код с PyPDF2 и python3

#!/usr/bin/env python


# requires PyPdf2 library, version 1.26 or above -
# its homepage is https://pythonhosted.org/PyPDF2/index.html
# running: ./this-script-name output.pdf file-with-pdf-list

import copy, sys
from PyPDF2 import PdfFileWriter, PdfFileReader
output = PdfFileWriter()
output_page_number = 0

# every new file should start on (n*alignment + 1)th page
# (with value 2 this means starting always on an odd page)
alignment = 2

for filename in sys.argv[2:]:
    # This code is executed for every file in turn
    input = PdfFileReader(open(filename, "rb"))
    output.appendPagesFromReader(input)
    output_page_number += input.getNumPages()

    while output_page_number % alignment != 0:
        output.addBlankPage()
        output_page_number += 1

output.write(open(sys.argv[1], "wb"))
Loren
источник