Loading repository data…
Loading repository data…
pmaupin / repository
pdfrw is a pure Python library that reads and writes PDFs
:Author: Patrick Maupin
.. contents:: :backlinks: none
.. sectnum::
pdfrw is a Python library and utility that reads and writes PDF files:
reportlab__
to reuse existing PDFs in new onespdfrw will faithfully reproduce vector formats without rasterization, so the rst2pdf package has used pdfrw for PDF and SVG images by default since March 2010.
pdfrw can also be used in conjunction with reportlab, in order to re-use portions of existing PDFs in new PDFs created with reportlab.
The library comes with several examples that show operation both with and without reportlab.
The examples directory has a few scripts which use the library. Note that if these examples do not work with your PDF, you should try to use pdftk to uncompress and/or unencrypt them first.
4up.py__ will shrink pages down and place 4 of them on
each output page.alter.py__ shows an example of modifying metadata, without
altering the structure of the PDF.booklet.py__ shows an example of creating a 2-up output
suitable for printing and folding (e.g on tabloid size paper).cat.py__ shows an example of concatenating multiple PDFs together.extract.py__ will extract images and Form XObjects (embedded pages)
from existing PDFs to make them easier to use and refer to from
new PDFs (e.g. with reportlab or rst2pdf).poster.py__ increases the size of a PDF so it can be printed
as a poster.print_two.py__ Allows creation of 8.5 X 5.5" booklets by slicing
8.5 X 11" paper apart after printing.rotate.py__ Rotates all or selected pages in a PDF.subset.py__ Creates a new PDF with only a subset of pages from the
original.unspread.py__ Takes a 2-up PDF, and splits out pages.watermark.py__ Adds a watermark PDF image over or under all the pages
of a PDF.rl1/4up.py__ Another 4up example, using reportlab canvas for output.rl1/booklet.py__ Another booklet example, using reportlab canvas for
output.rl1/subset.py__ Another subsetting example, using reportlab canvas for
output.rl1/platypus_pdf_template.py__ Another watermarking example, using
reportlab canvas and generated output for the document. Contributed
by user asannes.rl2__ Experimental code for parsing graphics. Needs work.subset_booklets.py__ shows an example of creating a full printable pdf
version in a more professional and pratical way ( take a look at
http://www.wikihow.com/Bind-a-Book )__ https://github.com/pmaupin/pdfrw/tree/master/examples/4up.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/alter.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/booklet.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/cat.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/extract.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/poster.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/print_two.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/rotate.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/subset.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/unspread.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/watermark.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/rl1/4up.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/rl1/booklet.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/rl1/subset.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/rl1/platypus_pdf_template.py __ https://github.com/pmaupin/pdfrw/tree/master/examples/rl2/ __
Reorganizing pages and placing them two-up
A printer with a fancy printer and/or a full-up copy of Acrobat can
easily turn your small PDF into a little booklet (for example, print 4
letter-sized pages on a single 11" x 17").
But that assumes several things, including that the personnel know how
to operate the hardware and software. `booklet.py`__ lets you turn your PDF
into a preformatted booklet, to give them fewer chances to mess it up.
__ https://github.com/pmaupin/pdfrw/tree/master/examples/booklet.py
Adding or modifying metadata
The cat.py__ example will accept multiple input files on the command
line, concatenate them and output them to output.pdf, after adding some
nonsensical metadata to the output PDF file.
__ https://github.com/pmaupin/pdfrw/tree/master/examples/cat.py
The alter.py__ example alters a single metadata item in a PDF,
and writes the result to a new PDF.
__ https://github.com/pmaupin/pdfrw/tree/master/examples/alter.py
One difference is that, since cat is creating a new PDF structure, and alter is attempting to modify an existing PDF structure, the PDF produced by alter (and also by watermark.py) should be more faithful to the original (except for the desired changes).
For example, the alter.py navigation should be left intact, whereas with cat.py it will be stripped.
Rotating and doubling
If you ever want to print something that is like a small booklet, but
needs to be spiral bound, you either have to do some fancy rearranging,
or just waste half your paper.
The `print_two.py`__ example program will, for example, make two side-by-side
copies each page of of your PDF on a each output sheet.
__ https://github.com/pmaupin/pdfrw/tree/master/examples/print_two.py
But, every other page is flipped, so that you can print double-sided and
the pages will line up properly and be pre-collated.
Graphics stream parsing proof of concept
The copy.py__ script shows a simple example of reading in a PDF, and
using the decodegraphics.py module to try to write the same information
out to a new PDF through a reportlab canvas. (If you know about reportlab,
you know that if you can faithfully render a PDF to a reportlab canvas, you
can do pretty much anything else with that PDF you want.) This kind of
low level manipulation should be done only if you really need to.
decodegraphics is really more than a proof of concept than anything
else. For most cases, just use the Form XObject capability, as shown in
the examples/rl1/booklet.py demo.
__ https://github.com/pmaupin/pdfrw/tree/master/examples/rl2/copy.py
The philosophy of the library portion of pdfrw is to provide intuitive functions to read, manipulate, and write PDF files. There should be minimal leakage between abstraction layers, although getting useful work done makes "pure" functionality separation difficult.
A key concept supported by the library is the use of Form XObjects, which allow easy embedding of pieces of one PDF into another.
Addition of core support to the library is typically done carefully and thoughtfully, so as not to clutter it up with too many special cases.
There are a lot of incorrectly formatted PDFs floating around; support for these is added in some cases. The decision is often based on what acroread and okular do with the PDFs; if they can display them properly, then eventually pdfrw should, too, if it is not too difficult or costly.
Contributions are welcome; one user has contributed some decompression filters and the ability to process PDF 1.5 stream objects. Additional functionality that would obviously be useful includes additional decompression filters, the ability to process password-protected PDFs, and the ability to output linearized PDFs.
The philosophy of the examples is to provide small, easily-understood examples that showcase pdfrw functionality.
In general, PDF files conceptually map quite well to Python. The major objects to think about are:
The apparent primary difficulty in mapping PDF files to Python is the PDF file concept of "indirect objects." Indirect objects provide the efficiency of allowing a single piece of data to be referred to from more than one containing object, but probably more importantly, indirect objects provide a way to get around the chicken and egg problem of circular object references when mapping arbitrary data structures to files. To flatten out a circular reference, an indirect object is referred to instead of being directly included in another object. PDF files have a global mechanism for locating indirect objects, and they all have two reference numbers (a reference number and a "generation" number, in case you wanted to append to the PDF file rather than just rewriting the whole thing).
pdfrw automatically handles indirect references on reading in a PDF file. When pdfrw encounters an indirect PDF file object, the corresponding Python object it creates will have an 'indirect' attribute with a value of True. When writing a PDF file, if you have created arbitrary data, you just need to make sure that circular references are broken up by putting an attribute named 'indirect' which evaluates to True on at least one object in every cycle.
Another PDF file concept that doesn't quite map to regular Python is a "stream". Streams are dictionaries which each have an associated unformatted data block. pdfrw handles streams by placing a special attribute on a subclassed dictionary.
The usage model for pdfrw treats most objects as strings (it takes their string representation when writing them to a file). The two main exceptions are the PdfArray object and the PdfDict object.
PdfArray is a subclass of list with two special features. First, an 'indirect' attribute allows a PdfArray to be written out as an indirect PDF object. Second, pdfrw reads files lazily, so PdfArray knows about, and resolves references to other indirect objects on an as-needed basis.
PdfDict is a subclass of dict that also has an indirect attribute and lazy reference resolution as well. (And the subclassed IndirectPdfDict has indirect automatically set True).
But PdfDict also has an optional associated stream. The stream object defaults to None, but if you assign a stream to the dict, it will automatically set the PDF /Length attribute for the dictionary.
Finally, since PdfDict instances are indexed by PdfName objects (which always start with a /) and since most (all?) standard Adobe PdfName objects use names formatted like "/CamelCase", it makes sense to allow access to dictionary elements via object attribute accesses as well as object index accesses. So usage of PdfDict objects is normally via attribute access, although non-standard names (though still with a leading slash) can be accessed via dictionary index lookup.
Reading PDFs
The PdfReader object is a subclass of PdfDict, which allows easy access
to an entire document::
>>> from pdfrw import PdfReader
>>> x = PdfReader('source.pdf')
>>> x.keys()
['/Info', '/Size', '/Root']
>>>