Архив метки: pyPDF

PyPDF2: новый форк pyPdf (Перевод)

Сегодня узнал, проект pyPDF НЕ умер, как я думал раньше. На самом деле он перешёл в PyPDF2 (видите небольшую разницу в написании?). Есть так же вероятность того, что кто-то занимается и оригинальной версией проекта. При желании, за судьбой PyPDF2 можно следить на reddit. Тем временем я решил посмотреть, чем же PyPDF2 отличается от оригинала. Так что если у Вас есть пара свободных минут — милости просим.

Введение в PyPDF2

Два года назад я уже  писал про pyPDF, а совсем недавно мне как раз пришлось погрузиться в различные библиотеки для работы с PDF на Python, так что появление нового форка пришлось кстати. Мы возьмём несколько моих старых примеров, запустим их в PyPDF2 и посмотрим, как они сработают.
# Соединяем два PDF
from PyPDF2 import PdfFileReader, PdfFileWriter
 
output = PdfFileWriter
()
pdfOne = PdfFileReader
(open( "somepathtoaPDf", "rb"))
pdfTwo = PdfFileReader
(open("someotherpathtoaPDf", "rb"))
 
output.
addPage(pdfOne.getPage(0))
output.
addPage(pdfTwo.getPage(0))
 
outputStream =
open(r"output.pdf", "wb")
output.
write(outputStream)
outputStream.
close()
На моём Windows 7 это сработало без проблем. Как Вы можете предположить, всё, что этот код делает — создаёт два объекта PdfFileReader и прочитывает в каждом первую страницу. После этого, он добавляет эти две страницы в наш PdfFileWriter. И, наконец, мы открываем новый файл и записываем в него PDF. Вот и всё! Мы только что создали новый документ из двух разных PDF!
Теперь давайте попробуем скрипт для поворота страницы из другой моей страницы:
from PyPDF2 import PdfFileWriter, PdfFileReader
 
output = PdfFileWriter()
input1 = PdfFileReader(file("document1.pdf", "rb"))
output.addPage(input1.getPage(1).rotateClockwise(90))
# output.addPage(input1.getPage(2).rotateCounterClockwise(90))
 
outputStream = file("output.pdf", "wb")
output.write(outputStream)
outputStream.close()
Этот скрипт так же сработал на моей машине. Очень даже хорошо. Мой последний тест на соответствие должен проверить, можем ли мы вытаскивать данные так же, как мог оригинальный pyPdf. Давайте попробуем прочитать метаданные:
>>> from PyPDF2 import PdfFileReader
 
>>> p = r'C:UsersmdriscollDocumentsreportlab-userguide.pdf'
 
>>> pdf = PdfFileReader(open(p, 'rb'))
 
>>> pdf.documentInfo
 
{'/ModDate': u'D:20120629155504', '/CreationDate': u'D:20120629155504', '/Producer': u'GPL Ghostscript 8.15', '/Title': u'reportlab-userguide.pdf', '/Creator': u'Adobe Acrobat 10.1.3', '/Author': u'mdriscoll'}
>>> pdf.getNumPages()
 
120
>>> info = pdf.getDocumentInfo()
 
>>> info.author
 
u'mdriscoll'
>>> info.creator
 
u'Adobe Acrobat 10.1.3'
>>> info.producer
 
u'GPL Ghostscript 8.15'
>>> info.title
 
u'reportlab-userguide.pdf'
Тоже очень хорошо, кроме поля автора. Я определённо не автор этого документа и я не знаю, почему PyPDF2  решил, что я им являюсь. Всё остальное сработало верно. Теперь давайте посмотрим, что тут нового.

Что нового в PyPDF2

Одна из вещей, которую я сразу заметил как только взглянул на исходники PyPDF2, это то, что он добавляет несколько новых методов в PdfFileReader и PdfFileWriter. Кроме того, я заметил, что появился совершенно новый модуль merger.py, который содержит класс PdfFileMerger. Поскольку никакой нормальной документации нет — придётся лезть «под капот». Единственный новый метод, который был добавлен в reader — это getOutlines, который позволяет получить эскизы документа (outlines), если они есть. В writer появилась возможность добавить bookmarks и named destinations. Не так уж и много, но дарёному коню в зубы не смотрят. Но больше всего меня вдохновил новый класс PdfFileMerger, который мне напомнил почти погибший проект Stapler. PdfFileMerger позволяет нам объединить несколько PDF в один, используя соединение, вставку и вырезку и их комбинации.
Давайте попробуем?
import PyPDF2
 
path = open('path/to/hello.pdf', 'rb')
path2 = open('path/to/another.pdf', 'rb')
 
merger = PyPDF2.PdfFileMerger()
 
merger.merge(position=0, fileobj=path2)
merger.merge(position=2, fileobj=path)
merger.write(open("test_out.pdf", 'wb'))
Тут мы соединяем два файла вместе. В первый файл вместо третьей страницы будет добавлен второй файл, а как только содержание второго файла закончится будет продолжен первый файл. Это проще, чем проходиться по страницам двух документов и соединять их. Команда merge имеет следующую сигнатуру и строку документации, которая хорошо всё это описывает:
>>> merge(position, file, bookmark=None, pages=None, import_bookmarks=True)
 
Сливает страницы из исходного документа, определённого в
"file" в файл вывода на место, определённое в "position".
 
Опционально Вы можете определить закладку, которая будет установлена на начало этого файла. Для этого надо передать текст закладки в параметре
"bookmark".
 
Вы можете запретить импорт закладок из исходного документа если передадите значение False параметру
"import_bookmarks".
 
Вы можете так же использовать параметр "pages" для того, чтобы добавить только некоторые страницы исходного файла. Для этого надо задать их диапазон.
Есть так же метод append, который аналогичен команде merge, но вместо того, чтобы сливать файлы, он добавляет их в конец исходного файла. Вот скрипт для примера:
import PyPDF2
 
path = open('path/to/hello.pdf', 'rb')
path2 = open('path/to/another.pdf', 'rb')
 
merger = PyPDF2.PdfFileMerger()
 
merger.append(fileobj=path2)
merger.append(fileobj=path)
merger.write(open("test_out2.pdf", 'wb'))
И совсем не больно!

Подводим итоги

Мне кажется, это хорошая альтернатива для работы с PDF. Я могу комбинировать и разделять PDF при помощи PyPDF2 даже проще, чем с оригинальным pyPdf. Кроме того, я надеюсь, что PyPDF не умрёт, так как у него есть спонсоры, оплачивающие его разработку. Согласно потокам reddit есть даже шанс, что оригинальный pyPdf будет переработан и в конце концов оба эти проекта сольются в дружеском экстазе. Но, вне зависимости от того, чем всё закончится, я рад, что разработка его возобновилась и надеюсь, что она не скоро прекратится.

Домашнее чтение

Автор: Ishayahu Lastov

Быстрое введение в pdfrw (Перевод)

Я всегда наблюдаю за библиотеками для Pytho для работы с  PDF и в один прекрасный день я столкнулся с pdfrw. Это похоже на аналог pyPDF, так как позволяет Вам читать и записывать PDFы, объединять их и использовать Reportlab для пометки их водяными знаками, кроме всего прочего. Проект немного мёртв, так как последнее обновление было в 2011 году, но с учётом того, что pyPDF обновлялся в 2010 — это не так уж и плохо. В этой  статье мы проведём небольшой тест-драйв pdfrw и посмотрим, на что он годен. Поехали!
Заметка об установке: К сожалению у этой библиотеки нет скрипта setup.py, так что Вам придётся получить исходники с Google Code а затем скопировать папку pdfrw в site-packages или в ваш virtualenv.

Соединяем PDFы при помощи pdfrw

Достаточно простая задача:
from pdfrw import PdfReader, PdfWriter
 
pages = PdfReader(r'C:UsersmdriscollDesktop1.pdf', decompress=False).pages
other_pages = PdfReader(r'C:UsersmdriscollDesktop2.pdf', decompress=False).pages
 
writer = PdfWriter()
writer.addpages(pages)
writer.addpages(other_pages)
writer.write(r'C:UsersmdriscollDesktopout.pdf')
Что мне показалось интересным — так это возможность добавить метаданные в файл перед тем, как Вы его сохраните:
writer.trailer.Info = IndirectPdfDict(
Title = 'My Awesome PDF',
Author = 'Mike',
Subject = 'Python Rules!',
Creator = 'myscript.py',
)
Вот пример того, как соединить PDFы при помощи pdfrw и reportlab:
# http://code.google.com/p/pdfrw/source/browse/trunk/examples/rl1/subset.py
import sys
import os
 
from reportlab.pdfgen.canvas import Canvas
 
import find_pdfrw
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl
 
 
def go(inpfn, firstpage, lastpage):
firstpage, lastpage = int(firstpage), int(lastpage)
outfn = 'subset_%s_to_%s.%s' % (firstpage, lastpage, os.path.basename(inpfn))
 
pages = PdfReader(inpfn, decompress=False).pages
pages = [pagexobj(x) for x in pages[firstpage-1:lastpage]]
canvas = Canvas(outfn)
 
for page in pages:
canvas.setPageSize(tuple(page.BBox[2:]))
canvas.doForm(makerl(canvas, page))
canvas.showPage()
 
canvas.save()
 
if __name__ == '__main__':
inpfn, firstpage, lastpage = sys.argv[1:]
go(inpfn, firstpage, lastpage)
На мой взгляд — так это клёво. У Вас есть несколько альтернатив pyPDF’у. Кроме того, в пакете Вы найдёте ещё несколько интересных примеров, например:
  1. Как использовать pdf (одна страница) для фона для других страниц при помощи platypus.
  2. Как добавить водяной знак
Я думаю, у этого проекта большой потенциал. К счастью, мы можем проявить к нему достаточно интереса, чтобы снова запустит его, ну или найти что-то новенькое.

Автор: Ishayahu Lastov