Рубрики
Без рубрики

Манипулирование PDFS с Python и Pypdf

Получите практические, реальные навыки Python на наших ресурсах и пути

Автор оригинала: Mike Driscoll.

Там удобный 3-й партийный модуль называется pypdf Из-за того, что вы можете использовать для объединения документов PDFS, поворотные страницы, разделенные и обрезывания страниц и расшифруете/шифровать документы PDF. В этой статье мы посмотрим на несколько из этих функций, а затем создаем простой графический интерфейс с wxpython Это позволит нам объединить пару PDF.

Pypdf Tour.

Чтобы получить максимум из PypDF, вам нужно изучать свои две основные функции: pdffilereader и pdffileWriter. Это те, которые я использую больше всего. Давайте посмотрим на то, что они могут сделать:

# Merge two PDFs
from pyPdf import PdfFileReader, PdfFileWriter

output = PdfFileWriter()
pdfOne = PdfFileReader(file( "some\path\to\a\PDf", "rb"))
pdfTwo = PdfFileReader(file("some\other\path\to\a\PDf", "rb"))

output.addPage(pdfOne.getPage(0))
output.addPage(pdfTwo.getPage(0))

outputStream = file(r"output.pdf", "wb")
output.write(outputStream)
outputStream.close()

Вышеупомянутый код откроет два PDF, возьмите первую страницу из каждого из каждого PDF и создают третий PDF, присоединившись к двум двум страницам. Обратите внимание, что страницы находятся на нуле, поэтому ноль – это первая страница, одна – это два и т. Д. Я использую этот вид сценария для извлечения одного или нескольких страниц из PDF или для соединения серии PDF. Например, иногда мои пользователи получит кучу отсканированных документов, где каждая страница документа заканчивается в отдельном PDF. Им нужны все отдельные страницы, соединенные в одном PDF, и PypDF позволяет мне сделать это очень просто.

Там не так много приложений для вращающихся функций, которые pypdf дает мне в моем повседневном опыте, но, возможно, у вас есть много пользователей, которые сканируют документы в ландшафте, а не по портрету, и вы в конечном итоге, нуждаетесь в том, чтобы сделать много поворота. К счастью, это довольно безболезненно:

from pyPdf 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 и сокращены для этого примера. Как видите, метод позвонить RotateClockwise или RotateCounterClockwise Отказ Убедитесь, что вы передаете метод количество градусов, чтобы включить страницу.

Теперь давайте посмотрим, какую информацию мы можем потянуть от PDF о себе:

>>> from pyPdf import PdfFileReader
>>> p = r'E:\My Documents\My Dropbox\ebooks\helloWorld book.pdf'
>>> pdf = PdfFileReader(file(p, 'rb'))
>>> pdf.documentInfo
{'/CreationDate': u'D:20090323080712Z', '/Author': u'Warren Sande', '/Producer': u'Acrobat Distiller 8.0.0 (Windows)', '/Creator': u'FrameMaker 8.0', '/ModDate': u"D:20090401124817-04'00'", '/Title': u'Hello World!'}
>>> pdf.getNumPages()
432
>>> info = pdf.getDocumentInfo()
>>> info.author
u'Warren Sande'
>>> info.creator
u'FrameMaker 8.0'
>>> info.producer
u'Acrobat Distiller 8.0.0 (Windows)'
>>> info.title
u'Hello World!'

Как видите, мы можем собрать довольно полезные данные, используя PYPDF. Теперь давайте создадим простой GUI, чтобы проще слияние двух PDF!

Создание приложения слияния PDF WXPYPHON PDF

Я придумал этот сценарий вчера. Используется Tim Golden’s WinShell Модуль, чтобы дать мне легкий доступ к рабочему столу пользователя на Windows. Если вы находитесь на Linux или Mac, то вы захотите изменить эту часть кода для вашей платформы. Я хотел использовать модуль WXPYPHON по стандартизации WXPYPHON, но у него не было функции для получения рабочего стола, которую я мог видеть. Во всяком случае, достаточно разговоров. Давайте посмотрим на какой-нибудь код!

import os
import pyPdf
import winshell
import wx

class MyFileDropTarget(wx.FileDropTarget):
    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window

    def OnDropFiles(self, x, y, filenames):
        self.window.SetInsertionPointEnd()
        
        for file in filenames:
            self.window.WriteText(file)

########################################################################
class JoinerPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        
        self.currentPath = winshell.desktop()
        
        
        lblSize = (70,-1)
        pdfLblOne = wx.StaticText(self, label="PDF One:", size=lblSize)
        self.pdfOne = wx.TextCtrl(self)
        dt = MyFileDropTarget(self.pdfOne)
        self.pdfOne.SetDropTarget(dt)
        pdfOneBtn = wx.Button(self, label="Browse", name="pdfOneBtn")
        pdfOneBtn.Bind(wx.EVT_BUTTON, self.onBrowse)
        
        pdfLblTwo = wx.StaticText(self, label="PDF Two:", size=lblSize)
        self.pdfTwo = wx.TextCtrl(self)
        dt = MyFileDropTarget(self.pdfTwo)
        self.pdfTwo.SetDropTarget(dt)
        pdfTwoBtn = wx.Button(self, label="Browse", name="pdfTwoBtn")
        pdfTwoBtn.Bind(wx.EVT_BUTTON, self.onBrowse)
        
        outputLbl = wx.StaticText(self, label="Output name:", size=lblSize)
        self.outputPdf = wx.TextCtrl(self)
        widgets = [(pdfLblOne, self.pdfOne, pdfOneBtn),
                   (pdfLblTwo, self.pdfTwo, pdfTwoBtn),
                   (outputLbl, self.outputPdf)]
        
        joinBtn = wx.Button(self, label="Join PDFs")
        joinBtn.Bind(wx.EVT_BUTTON, self.onJoinPdfs)
        
        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
        for widget in widgets:
            self.buildRows(widget)
        self.mainSizer.Add(joinBtn, 0, wx.ALL|wx.CENTER, 5)
        self.SetSizer(self.mainSizer)
        
    #----------------------------------------------------------------------
    def buildRows(self, widgets):
        """"""
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        for widget in widgets:
            if isinstance(widget, wx.StaticText):
                sizer.Add(widget, 0, wx.ALL|wx.CENTER, 5)
            elif isinstance(widget, wx.TextCtrl):
                sizer.Add(widget, 1, wx.ALL|wx.EXPAND, 5)
            else:
                sizer.Add(widget, 0, wx.ALL, 5)
        self.mainSizer.Add(sizer, 0, wx.EXPAND)
        
    #----------------------------------------------------------------------
    def onBrowse(self, event):
        """
        Browse for PDFs
        """
        widget = event.GetEventObject()
        name = widget.GetName()
        
        wildcard = "PDF (*.pdf)|*.pdf"
        dlg = wx.FileDialog(
            self, message="Choose a file",
            defaultDir=self.currentPath, 
            defaultFile="",
            wildcard=wildcard,
            style=wx.OPEN | wx.CHANGE_DIR
            )
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if name == "pdfOneBtn":
                self.pdfOne.SetValue(path)
            else:
                self.pdfTwo.SetValue(path)
            self.currentPath = os.path.dirname(path)
        dlg.Destroy()
        
    #----------------------------------------------------------------------
    def onJoinPdfs(self, event):
        """
        Join the two PDFs together and save the result to the desktop
        """
        pdfOne = self.pdfOne.GetValue()
        pdfTwo = self.pdfTwo.GetValue()
        if not os.path.exists(pdfOne):
            msg = "The PDF at %s does not exist!" % pdfOne
            dlg = wx.MessageDialog(None, msg, 'Error', wx.OK|wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            return
        if not os.path.exists(pdfTwo):
            msg = "The PDF at %s does not exist!" % pdfTwo
            dlg = wx.MessageDialog(None, msg, 'Error', wx.OK|wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            return
        
        outputPath = os.path.join(winshell.desktop(), self.outputPdf.GetValue()) + ".pdf"
        output = pyPdf.PdfFileWriter()

        pdfOne = pyPdf.PdfFileReader(file(pdfOne, "rb"))
        for page in range(pdfOne.getNumPages()):
            output.addPage(pdfOne.getPage(page))
        pdfTwo = pyPdf.PdfFileReader(file(pdfTwo, "rb"))
        for page in range(pdfTwo.getNumPages()):
            output.addPage(pdfTwo.getPage(page))

        outputStream = file(outputPath, "wb")
        output.write(outputStream)
        outputStream.close()
        
        msg = "PDF was save to " + outputPath
        dlg = wx.MessageDialog(None, msg, 'PDF Created', wx.OK|wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()
        
        self.pdfOne.SetValue("")
        self.pdfTwo.SetValue("")
        self.outputPdf.SetValue("")
        
########################################################################
class JoinerFrame(wx.Frame):
 
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, 
                          "PDF Joiner", size=(550, 200))
        panel = JoinerPanel(self)
        
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = JoinerFrame()
    frame.Show()
    app.MainLoop()

Вы заметите, что рамка и панель имеют дописные имена. Не стесняйтесь менять их. Это Python в конце концов! MyFileDropTarget Класс используется для включения функциональности перетаскивания на первых двух элементах управления текстом. Если пользователь хочет, они могут перетащить PDF на один из этих текстовых элементов управления, и путь будет вставлен волшебным образом. В противном случае они могут использовать кнопки «Обзор», чтобы найти PDF (ы) их выбора. Как только они будут выбраны PDF, им нужно ввести имя вывода PDF, которое идет в третьем текстовом управлении. Вам даже не нужно добавлять расширение «.pdf», поскольку это приложение сделает это для вас.

Последний шаг – нажать кнопку «Присоединиться к PDFS». Это добавит второй PDF до конца первого, затем отобразите диалог, если он был успешно создан. Для этого правильно функционировать, нам нужно перейти на все страницы каждого PDF и добавить их на выход в порядке.

Было бы забавно улучшить это приложение с каким-то интерфейсом перетаскивания, где пользователь мог видеть страницы PDF и переставить их, перетаскивая их вокруг. Или просто способность указать несколько страниц из каждого PDF, чтобы добавить, а не присоединиться к ним во всей их полноте. Я оставлю теми, как упражнения для читателя, хотя.

Я надеюсь, что вы нашли эту статью интересную и что она зажечь ваши творческие соки. Если вы пишете что-нибудь круто с этими идеями, обязательно опубликуйте комментарий, поэтому я вижу это!