I would like to convert several TIFF files (document scans) into a single, structured PDF. Each page is saved as a single TIFF file, and each chapter has its own directory. Directories can be nested to arbitrary depth.

Example of directory structure

Is there a way to create a PDF from those images, using the directory names as (hierarchical) bookmarks? In addition to that, it would be even better if I could use a regex to manipulate the bookmark names (e. g., removing the numbered prefixes (/^[0-9}+_//s or something like that)).

I have found several solutions for converting a flat folder of images into a PDF file, but no recursive solution.

It doesn't have to be a stand-alone app, a batch/PowerShell file (I'm on Windows) or a Python script would be fine as well.


So, what I ended up doing was:

First, I used img2pdf to create a PDF from all the images. At the same time, I listed all the images in a separate text file.

import os
import img2pdf

buecher = os.listdir("E:\\")  # each directory under E: contains one book
for buch in buecher:
    with open(f"{buch}.pdf", "wb") as pdf, open(f"{buch}.txt", "w") as contents:
        seiten = []
        seitennr = 0
        for root, dirs, files in os.walk(f"E:\\{buch}"):
            for file in files:
                if file.endswith(".tif") or file.endswith(".tiff"):
                    seitennr += 1
                    path = os.path.join(root,file)
                    contents.write(str(seitennr) + ": " + path + "\n")

Then, I created a tree with all the sections (directory names) and the page numbers where these sections start:

def write_tc(file, toc, level=-1, name=""):
    for key, value in toc.items():
        if key == "page":
            file.write("\t"*level + name + "       " + str(value) + "\n")
            write_tc(file, value, level+1, key)

with open(f"{buch}.txt", "r") as contents:
    tree = {}
    for number, line in enumerate(contents):
        levels = [item for item in line.split("\\")[2:-1]]
        node = tree
        for level in levels:
            node = node.setdefault(level, {})
            if not node:
                node["page"] = number + 1 # pages start from 1

with open(f"{buch}.txt", "w") as toc:
    write_tc(toc, tree)

The resulting text files look like this:

Inhalt und Einleitung       1
Ulm Straßenverzeichnis       5
    Lit A       5
    Lit B       38
    Lit C       59
    Lit D       88
    Gräben       117
    Vor den Thoren       126
Ulm Branchenverzeichnis       128
Ulm Polizeiverordnungen       134
Ulm Fuhrleute       137
Ulm Personenverzeichnis       141

and can be used as input for HandyOutliner which merges the TOC into the PDF file generated in the previous step.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.