mirror of
https://github.com/jsvine/pdfplumber.git
synced 2026-08-29 16:40:24 +08:00
77 lines
3.3 KiB
Markdown
77 lines
3.3 KiB
Markdown
# Structure Tree
|
|
|
|
Since PDF 1.3 it is possible for a PDF to contain logical structure,
|
|
contained in a *structure tree*. In conjunction with PDF 1.2 [marked
|
|
content sections](#marked-content-sections) this forms the basis of
|
|
Tagged PDF and other accessibility features.
|
|
|
|
Unfortunately, since all of these standards are optional and variably
|
|
implemented in PDF authoring tools, and are frequently not enabled by
|
|
default, it is not possible to rely on them to extract the structure
|
|
of a PDF and associated content. Nonetheless they can be useful as
|
|
features for a heuristic or machine-learning based system, or for
|
|
extracting particular structures such as tables.
|
|
|
|
Since `pdfplumber`'s API is page-based, the structure is available for
|
|
a particular page, using the `structure_tree` attribute:
|
|
|
|
with pdfplumber.open(pdffile) as pdf:
|
|
for element in pdf.pages[0].structure_tree:
|
|
print(element["type"], element["mcids"])
|
|
for child in element.children:
|
|
print(child["type"], child["mcids"])
|
|
|
|
The `type` field contains the type of the structure element - the
|
|
standard structure types can be seen in section 10.7.3 of [the PDF 1.7
|
|
reference
|
|
document](https://ghostscript.com/~robin/pdf_reference17.pdf#page=898),
|
|
but usually they are rather HTML-like, if created by a recent PDF
|
|
authoring tool (notably, older tools may simply produce `P` for
|
|
everything).
|
|
|
|
The `mcids` field contains the list of marked content section IDs
|
|
corresponding to this element.
|
|
|
|
The `lang` field is often present as well, and contains a language
|
|
code for the text content, e.g. `"EN-US"` or `"FR-CA"`.
|
|
|
|
The `alt_text` field will be present if the author has helpfully added
|
|
alternate text to an image. In some cases, `actual_text` may also be
|
|
present.
|
|
|
|
There are also various attributes that may be in the `attributes`
|
|
field. Some of these are quite useful indeed, such as ``BBox` which
|
|
gives you the bounding box of a `Table`, `Figure`, or `Image`. You
|
|
can see a full list of these [in the PDF
|
|
spec](https://ghostscript.com/~robin/pdf_reference17.pdf#page=916).
|
|
Note that the `BBox` is in PDF coordinate space with the origin at the
|
|
bottom left of the page. To convert it to `pdfplumber`'s space you
|
|
can do, for example:
|
|
|
|
x0, y0, x1, y1 = element['attributes']['BBox']
|
|
top = page.height - y1
|
|
bottom = page.height - y0
|
|
doctop = page.initial_doctop + top
|
|
bbox = (x0, top, x1, bottom)
|
|
|
|
It is also possible to get the structure tree for the entire document.
|
|
In this case, because marked content IDs are specific to a given page,
|
|
each element will also have a `page_number` attribute, which is the
|
|
number of the page containing (partially or completely) this element,
|
|
indexed from 1 (for consistency with `pdfplumber.Page`).
|
|
|
|
You can also access the underlying `PDFStructTree` object for more
|
|
flexibility, including visual debugging. For instance to plot the
|
|
bounding boxes of the contents of all of the `TD` elements on the
|
|
first page of a document:
|
|
|
|
page = pdf.pages[0]
|
|
stree = PDFStructTree(pdf, page)
|
|
img = page.to_image()
|
|
img.draw_rects(stree.element_bbox(td) for td in table.find_all("TD"))
|
|
|
|
The `find_all` method works rather like the same method in
|
|
[BeautifulSoup](https://beautiful-soup-4.readthedocs.io/en/latest/#searching-the-tree) -
|
|
it takes an element name, a regular expression, or a matching
|
|
function.
|