pdffill 2026.6.19.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pdffill-2026.6.19.0/PKG-INFO +40 -0
- pdffill-2026.6.19.0/README.md +20 -0
- pdffill-2026.6.19.0/pdffill.egg-info/PKG-INFO +40 -0
- pdffill-2026.6.19.0/pdffill.egg-info/SOURCES.txt +9 -0
- pdffill-2026.6.19.0/pdffill.egg-info/dependency_links.txt +1 -0
- pdffill-2026.6.19.0/pdffill.egg-info/entry_points.txt +5 -0
- pdffill-2026.6.19.0/pdffill.egg-info/requires.txt +3 -0
- pdffill-2026.6.19.0/pdffill.egg-info/top_level.txt +1 -0
- pdffill-2026.6.19.0/pdffill.py +169 -0
- pdffill-2026.6.19.0/pyproject.toml +40 -0
- pdffill-2026.6.19.0/setup.cfg +4 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdffill
|
|
3
|
+
Version: 2026.6.19.0
|
|
4
|
+
Summary: Command line utility to manipulate PDF fields. It can list, rename, fill-in or delete PDF fields.
|
|
5
|
+
Author-email: Ernesto Alfonso <erjoalgo@gmail.com>
|
|
6
|
+
Maintainer-email: Ernesto Alfonso <erjoalgo@gmail.com>
|
|
7
|
+
License-Expression: GPL-3.0-or-later
|
|
8
|
+
Project-URL: Homepage, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
|
|
9
|
+
Project-URL: Documentation, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill/README.md
|
|
10
|
+
Project-URL: Repository, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/erjoalgo/dotfiles/issues
|
|
12
|
+
Keywords: pdf,fields,fill
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: pypdf
|
|
18
|
+
Requires-Dist: fillpdf
|
|
19
|
+
Requires-Dist: PyMuPDF
|
|
20
|
+
|
|
21
|
+
This is a command line utility to manipulate a PDF's fields.
|
|
22
|
+
|
|
23
|
+
$ pip install pdffill
|
|
24
|
+
|
|
25
|
+
# List field names
|
|
26
|
+
$ pdffill input.pdf -l
|
|
27
|
+
|
|
28
|
+
# Rename some fields
|
|
29
|
+
$ pdffill.py input.pdf -r text_3uwum=seller text_4vpsr=buyer text_5ovhg=address
|
|
30
|
+
|
|
31
|
+
# Fill in some fields, write to a separate output file
|
|
32
|
+
$ pdffill.py input.pdf -o filled.pdf -f "seller=Wollam Bonnie C Estate" "buyer=John Doe" address=20235 Majestic Street, Orlando, Fl, 32833
|
|
33
|
+
|
|
34
|
+
# Delete some fields, write to a separate output file
|
|
35
|
+
$ pdffill.py input.pdf -o slim.pdf -d balance-to-close -d purchase-price-other-item -d purchase-price-other-item-value
|
|
36
|
+
|
|
37
|
+
# Fill in all fields with their own names, helpful for seeing where fields are on the page.
|
|
38
|
+
$ pdffill.py input.pdf -o debug.pdf -F
|
|
39
|
+
|
|
40
|
+
This utility doesn't handle checkboxes well, and it is recommended to use plain text fields instead.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
This is a command line utility to manipulate a PDF's fields.
|
|
2
|
+
|
|
3
|
+
$ pip install pdffill
|
|
4
|
+
|
|
5
|
+
# List field names
|
|
6
|
+
$ pdffill input.pdf -l
|
|
7
|
+
|
|
8
|
+
# Rename some fields
|
|
9
|
+
$ pdffill.py input.pdf -r text_3uwum=seller text_4vpsr=buyer text_5ovhg=address
|
|
10
|
+
|
|
11
|
+
# Fill in some fields, write to a separate output file
|
|
12
|
+
$ pdffill.py input.pdf -o filled.pdf -f "seller=Wollam Bonnie C Estate" "buyer=John Doe" address=20235 Majestic Street, Orlando, Fl, 32833
|
|
13
|
+
|
|
14
|
+
# Delete some fields, write to a separate output file
|
|
15
|
+
$ pdffill.py input.pdf -o slim.pdf -d balance-to-close -d purchase-price-other-item -d purchase-price-other-item-value
|
|
16
|
+
|
|
17
|
+
# Fill in all fields with their own names, helpful for seeing where fields are on the page.
|
|
18
|
+
$ pdffill.py input.pdf -o debug.pdf -F
|
|
19
|
+
|
|
20
|
+
This utility doesn't handle checkboxes well, and it is recommended to use plain text fields instead.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdffill
|
|
3
|
+
Version: 2026.6.19.0
|
|
4
|
+
Summary: Command line utility to manipulate PDF fields. It can list, rename, fill-in or delete PDF fields.
|
|
5
|
+
Author-email: Ernesto Alfonso <erjoalgo@gmail.com>
|
|
6
|
+
Maintainer-email: Ernesto Alfonso <erjoalgo@gmail.com>
|
|
7
|
+
License-Expression: GPL-3.0-or-later
|
|
8
|
+
Project-URL: Homepage, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
|
|
9
|
+
Project-URL: Documentation, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill/README.md
|
|
10
|
+
Project-URL: Repository, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/erjoalgo/dotfiles/issues
|
|
12
|
+
Keywords: pdf,fields,fill
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: pypdf
|
|
18
|
+
Requires-Dist: fillpdf
|
|
19
|
+
Requires-Dist: PyMuPDF
|
|
20
|
+
|
|
21
|
+
This is a command line utility to manipulate a PDF's fields.
|
|
22
|
+
|
|
23
|
+
$ pip install pdffill
|
|
24
|
+
|
|
25
|
+
# List field names
|
|
26
|
+
$ pdffill input.pdf -l
|
|
27
|
+
|
|
28
|
+
# Rename some fields
|
|
29
|
+
$ pdffill.py input.pdf -r text_3uwum=seller text_4vpsr=buyer text_5ovhg=address
|
|
30
|
+
|
|
31
|
+
# Fill in some fields, write to a separate output file
|
|
32
|
+
$ pdffill.py input.pdf -o filled.pdf -f "seller=Wollam Bonnie C Estate" "buyer=John Doe" address=20235 Majestic Street, Orlando, Fl, 32833
|
|
33
|
+
|
|
34
|
+
# Delete some fields, write to a separate output file
|
|
35
|
+
$ pdffill.py input.pdf -o slim.pdf -d balance-to-close -d purchase-price-other-item -d purchase-price-other-item-value
|
|
36
|
+
|
|
37
|
+
# Fill in all fields with their own names, helpful for seeing where fields are on the page.
|
|
38
|
+
$ pdffill.py input.pdf -o debug.pdf -F
|
|
39
|
+
|
|
40
|
+
This utility doesn't handle checkboxes well, and it is recommended to use plain text fields instead.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pdffill
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""Fill, rename or list a PDF's fields."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
from pypdf import PdfReader, PdfWriter
|
|
10
|
+
from pypdf.generic import NameObject, create_string_object
|
|
11
|
+
|
|
12
|
+
from fillpdf import fillpdfs
|
|
13
|
+
|
|
14
|
+
import fitz
|
|
15
|
+
|
|
16
|
+
def list_fields(input_pdf):
|
|
17
|
+
"""List the fields in input_pdf."""
|
|
18
|
+
reader = PdfReader(input_pdf)
|
|
19
|
+
return (reader.get_fields() or {}).keys()
|
|
20
|
+
|
|
21
|
+
def rename_fields(input_pdf, output_pdf, renames):
|
|
22
|
+
"""Rename the fields in input_pdf."""
|
|
23
|
+
with open(input_pdf, "rb") as fh:
|
|
24
|
+
writer = PdfWriter(fileobj=fh)
|
|
25
|
+
|
|
26
|
+
for page in writer.pages:
|
|
27
|
+
for annot in (page.get("/Annots") or []):
|
|
28
|
+
full_annot = annot.get_object()
|
|
29
|
+
if "/T" not in full_annot:
|
|
30
|
+
continue
|
|
31
|
+
current_name = full_annot["/T"]
|
|
32
|
+
if "checkbox" in current_name:
|
|
33
|
+
continue
|
|
34
|
+
new_name = renames.get(current_name)
|
|
35
|
+
if new_name:
|
|
36
|
+
full_annot[NameObject("/T")] = create_string_object(new_name)
|
|
37
|
+
|
|
38
|
+
for field in writer.root_object['/AcroForm']["/Fields"]:
|
|
39
|
+
full_field = field.get_object()
|
|
40
|
+
curr_name = full_field.get("/T")
|
|
41
|
+
if "checkbox" in curr_name:
|
|
42
|
+
continue
|
|
43
|
+
new_name = renames.get(curr_name)
|
|
44
|
+
if new_name:
|
|
45
|
+
full_field[NameObject("/T")] = create_string_object(new_name)
|
|
46
|
+
|
|
47
|
+
with open(output_pdf, "wb") as f:
|
|
48
|
+
writer.write(f)
|
|
49
|
+
|
|
50
|
+
def fill_pdf_pypdf(input_pdf, output_pdf, data_dict):
|
|
51
|
+
"""Fill in the fields in input_pdf."""
|
|
52
|
+
with open(input_pdf, "rb") as fh:
|
|
53
|
+
writer = PdfWriter(fileobj = fh)
|
|
54
|
+
|
|
55
|
+
for i, page in enumerate(writer.pages):
|
|
56
|
+
# non_checkboxes = {k: v for k, v in data_dict.items() if "checkbox" not in k}
|
|
57
|
+
non_checkboxes = data_dict
|
|
58
|
+
logging.debug(f"on page %s{i+1}")
|
|
59
|
+
writer.update_page_form_field_values(
|
|
60
|
+
page, non_checkboxes,
|
|
61
|
+
auto_regenerate=False)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
with open(output_pdf, "wb") as output_stream:
|
|
65
|
+
writer.write(output_stream)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def print_fields(input_pdf):
|
|
69
|
+
"""Print the field names in the pdf."""
|
|
70
|
+
field_names = fillpdfs.get_form_fields(input_pdf)
|
|
71
|
+
for (name, value) in field_names.items():
|
|
72
|
+
print(f"{name} = {value}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def list_to_map(arr):
|
|
76
|
+
"""Convert a list of key=value strings into a dictionary."""
|
|
77
|
+
d = {}
|
|
78
|
+
for kv in arr:
|
|
79
|
+
if "=" not in kv:
|
|
80
|
+
logging.info("warn: skipping mapping with no = sign: %s", kv)
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
k, v = kv.split("=")
|
|
84
|
+
if not v:
|
|
85
|
+
logging.info("warn: skipping mapping with empty value: %s", kv)
|
|
86
|
+
continue
|
|
87
|
+
d[k] = v
|
|
88
|
+
return d
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def delete_fields(input_pdf, output_pdf, fields_to_delete):
|
|
92
|
+
"""Delete the given fields and write to output_pdf."""
|
|
93
|
+
doc = fitz.open(input_pdf)
|
|
94
|
+
for page in doc:
|
|
95
|
+
# Get all interactive form widgets on the page
|
|
96
|
+
for widget in page.widgets():
|
|
97
|
+
if widget.field_name in fields_to_delete:
|
|
98
|
+
# 1. Get the internal object reference number
|
|
99
|
+
xref = widget.xref
|
|
100
|
+
|
|
101
|
+
# 2. Delete the visual widget widget from the page
|
|
102
|
+
page.delete_widget(widget)
|
|
103
|
+
|
|
104
|
+
# 3. Completely clear the internal object definitions
|
|
105
|
+
doc.update_object(xref, "<<>>")
|
|
106
|
+
|
|
107
|
+
# Save the updated PDF
|
|
108
|
+
doc.save(output_pdf, incremental=True,
|
|
109
|
+
encryption=fitz.PDF_ENCRYPT_KEEP)
|
|
110
|
+
doc.close()
|
|
111
|
+
|
|
112
|
+
def main():
|
|
113
|
+
"""Main function."""
|
|
114
|
+
parser = argparse.ArgumentParser()
|
|
115
|
+
parser.add_argument("input", help="input PDF")
|
|
116
|
+
parser.add_argument("-o", "--output", help="output file")
|
|
117
|
+
parser.add_argument("-l", "--list", action="store_true",
|
|
118
|
+
help="""list the PDF fields""")
|
|
119
|
+
parser.add_argument("-r", "--rename",
|
|
120
|
+
help="""rename the given fields.
|
|
121
|
+
example: old_name1=new_name1 old_name2=new_name_2""",
|
|
122
|
+
nargs="+")
|
|
123
|
+
parser.add_argument("-f", "--fill",
|
|
124
|
+
help="""fill in the given fields.
|
|
125
|
+
example: old_name1=new_name1 old_name2=new_name_2""",
|
|
126
|
+
nargs="+")
|
|
127
|
+
parser.add_argument("-F", "--fill_all",
|
|
128
|
+
help="""fill in all text fields with their own field names.""",
|
|
129
|
+
action="store_true")
|
|
130
|
+
parser.add_argument("-d", "--delete", nargs="+",
|
|
131
|
+
help="""delete the given fields""")
|
|
132
|
+
parser.add_argument("-v", "--verbose", action="store_true",
|
|
133
|
+
help="""verbose logging""")
|
|
134
|
+
|
|
135
|
+
args= parser.parse_args()
|
|
136
|
+
|
|
137
|
+
logging.basicConfig(level=logging.DEBUG
|
|
138
|
+
if args.verbose else logging.INFO)
|
|
139
|
+
|
|
140
|
+
if args.list:
|
|
141
|
+
print_fields(args.input)
|
|
142
|
+
|
|
143
|
+
if not args.output:
|
|
144
|
+
logging.warning("warn: making modifications in-place")
|
|
145
|
+
args.output = args.input
|
|
146
|
+
|
|
147
|
+
if args.rename:
|
|
148
|
+
renames = list_to_map(args.rename)
|
|
149
|
+
assert args.output
|
|
150
|
+
rename_fields(args.input, args.output, renames)
|
|
151
|
+
print_fields(args.output)
|
|
152
|
+
|
|
153
|
+
fill_pdf_fn = fill_pdf_pypdf
|
|
154
|
+
if args.fill:
|
|
155
|
+
fills = list_to_map(args.fill)
|
|
156
|
+
assert args.output
|
|
157
|
+
fill_pdf_fn(args.input, args.output, fills)
|
|
158
|
+
|
|
159
|
+
if args.fill_all:
|
|
160
|
+
fields = list_fields(args.input)
|
|
161
|
+
fills = {name: name for name in fields}
|
|
162
|
+
fill_pdf_fn(args.input, args.output, fills)
|
|
163
|
+
|
|
164
|
+
if args.delete:
|
|
165
|
+
delete_fields(args.input, args.output, args.delete)
|
|
166
|
+
print_fields(args.output)
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
main()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pdffill"
|
|
7
|
+
version = "2026.06.19.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"pypdf",
|
|
10
|
+
"fillpdf",
|
|
11
|
+
"PyMuPDF",
|
|
12
|
+
]
|
|
13
|
+
requires-python = ">=3.7"
|
|
14
|
+
authors = [
|
|
15
|
+
{name = "Ernesto Alfonso", email = "erjoalgo@gmail.com"},
|
|
16
|
+
]
|
|
17
|
+
maintainers = [
|
|
18
|
+
{name = "Ernesto Alfonso", email = "erjoalgo@gmail.com"},
|
|
19
|
+
]
|
|
20
|
+
description = """Command line utility to manipulate PDF fields. It can list, rename, fill-in or delete PDF fields."""
|
|
21
|
+
|
|
22
|
+
readme = "README.md"
|
|
23
|
+
license = "GPL-3.0-or-later"
|
|
24
|
+
keywords = ["pdf", "fields", "fill"]
|
|
25
|
+
classifiers = [
|
|
26
|
+
"Development Status :: 4 - Beta",
|
|
27
|
+
"Programming Language :: Python"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill"
|
|
32
|
+
Documentation = "https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill/README.md"
|
|
33
|
+
Repository = "https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill"
|
|
34
|
+
"Bug Tracker" = "https://github.com/erjoalgo/dotfiles/issues"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
pdffill = "pdffill:main"
|
|
38
|
+
|
|
39
|
+
[project.entry-points."pdffill.pdffill"]
|
|
40
|
+
pdffill = "pdffill:pdffill"
|