Skip to content

Commit 0cfd8e5

Browse files
lkalka-berlinLucas-C
authored
add new tutorial how to create PDF/A files with fpdf2 (#1383)
* chore: new tutorial for PDF/A creation * chore: just to please black with tuto7 * chore: just to please black * chore: black ignore import * chore: test noqa: E0401 with black * Update tuto7.py disable Pylonen message * Update tuto7.py disable Import error with # pylint: disable=import-error * Update tutorial/tuto7.py Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> * Update tutorial/tuto7.py Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> * Update tutorial/tuto7.py Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> * Update CHANGELOG.md Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> * Update tutorial/tuto7.py Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> * chore: removed assets directory, moved sRGB2014.icc to tutorial directory; enhanced tutorials with language and subject comment --------- Co-authored-by: Lka <herbert@lischka-berlin.de> Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com>
1 parent e7f5161 commit 0cfd8e5

File tree

6 files changed

+227
-0
lines changed

6 files changed

+227
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
1818

1919
## [2.8.3] - Not released yet
2020
### Added
21+
* added tutorial "tuto7" (in [English](https://py-pdf.github.io/fpdf2/Tutorial.html#tuto-7-creating-pdfa-documents) and [German](https://py-pdf.github.io/fpdf2/Tutorial-de.html#tuto-7-ein-pdfa-dokument-erstellen)) with documentation to create PDF/A files with fpdf2
2122
* support for [Output Intents](https://py-pdf.github.io/fpdf2/Images.html#output-intents) on document level
2223
* support for [shading patterns (gradients)](https://py-pdf.github.io/fpdf2/Patterns.html) - thanks to @andersonhc - [PR #1334](https://github.com/py-pdf/fpdf2/pull/1334)
2324
* support for [setting a minimal row height in tables](https://py-pdf.github.io/fpdf2/Tables.html#setting-row-height)

docs/Tutorial-de.md

+57
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,60 @@ Um einen internen Link hinzuzufügen, der auf die zweite Seite verweist, nutzen
188188
Um einen externen Link mit Hilfe eines Bildes zu erstellen, verwenden wir [`image()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image). Es besteht die Möglichkeit, der Methode ein Linkziel als eines ihrer Argumente zu übergeben. Der Link kann sowohl einer interner als auch ein externer sein.
189189

190190
Eine weitere Möglichkeit, den Schriftstil zu ändern und Links hinzuzufügen, stellt die Verwendung der Methode `write_html()` dar. Sie ist ein HTML-Parser, der das Hinzufügen von Text, Änderung des Schriftstils und Erstellen von Links mittels HTML ermöglicht.
191+
192+
## Tuto 7 - Ein PDF/A Dokument erstellen ##
193+
194+
### PDF/A Standards ###
195+
196+
<b>PDF/A-1</b> basiert auf der PDF-Version 1.4. Alle Ressourcen (Bilder, Grafiken, Fonts) müssen im Document eingebettet werden. Erforderlich sind präzise und Plattform unabhängig kodierte Farbangaben mittels ICC-Profilen sowie die Verwendung von XMP für die Dokument-Metadata.
197+
198+
<b>PDF/A-2</b> basiert auf PDF-Version 1.7. Es erlaubt die Kompression mit JPEG2000, transparente Elemente, OpenType Fonts and digitale Signaturen.
199+
200+
Die einzige Erweiterung für <b>PDF/A-3</b> besteht aus der Möglichkeit, beliebige Dateien einzubetten.
201+
202+
### Conformance Classes ###
203+
204+
Stufe A (Zugänglichkeit) umfasst sämtliche Anforderungen des Standards inklusive Abbildung der inhaltlichen Struktur und korrekter Lesereihenfolge des Dokumentinhalts. Textinhalte müssen extrahierbar sein und die Struktur muss die natürliche Leseabfolge abbilden.
205+
206+
Stufe B (Basic) garantiert eine eindeutige visuelle Reproduzierbarkeit der Inhalte. Stufe B lässt sich meist einfacher generieren als Stufe A, gewährleistet aber nicht zu 100 Prozent Textextraktion oder -durchsuchbarkeit. Eine problemlose Wiederverwendung des Inhalts ist nicht unbedingt gegeben.
207+
208+
Hier ein kleines Beispiel um das zu erreichen:
209+
210+
```python
211+
{% include "../tutorial/tuto7.py" %}
212+
```
213+
214+
[Resulting PDF](https://github.com/py-pdf/fpdf2/raw/master/tutorial/tuto7.pdf) -
215+
[fpdf2-logo](https://raw.githubusercontent.com/py-pdf/fpdf2/master/docs/fpdf2-logo.png)
216+
217+
218+
```python
219+
pdf = PDF()
220+
```
221+
222+
Die Klasse PDF fügt die benötigten Fonts mit Hilfe der Funktion
223+
[add_font()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.add_font)
224+
in das Dokument ein.
225+
226+
Dann fügt es ein ICC Profil ein und erstellt mit Hilfe der Funktion
227+
[add_output_intent()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.output_intent)
228+
das Output Intents Verzeichnis.
229+
230+
Nachdem wir eine erste Seite einegfüllt, den eingebetteten Font ausgewählt, und etwas Text erzeugt haben, erstellen wir das PDF mit der Funktion:
231+
```python
232+
pdf.create_pdf_with_metadata(
233+
filename="tuto7.pdf",
234+
language="en-US",
235+
title="Tutorial7",
236+
subject="Example for PDFA",
237+
creator=["John Dow", "Jane Dow"],
238+
description="this is my description of this file",
239+
keywords="Example Tutorial7"
240+
)
241+
```
242+
243+
Dabei benutzen wir pikepdf um die nötigen Metadata zu erzeugen und den Typen auf PDF/A-3B zu setzen.
244+
245+
In der Funktion `create_pdf_with_metadata` setzen wir 'language' und 'subject' ausserhalb der Metadata bevor wir pikepdf aufrufen um, die Konformität zu erreichen.
246+
247+
Bitte benutzen Sie ein Programm, wie z.B. verapdf, um die Konformität des erstellten PDF zu sicherzustellen.

docs/Tutorial.md

+57
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,60 @@ To create the external link using an image, we used
233233
As an alternative, another option to change the font style and add links is to
234234
use the `write_html()` method. It is an html parser, which allows adding text,
235235
changing font style and adding links using html.
236+
237+
## Tuto 7 - Creating PDF/A Documents ##
238+
239+
### PDF/A Standards ###
240+
241+
<b>PDF/A-1</b> uses PDF-Version 1.4. All resources (pictures, graphics, fonts) must be embedded in the document. The color management must be precise and platform independently specified with ICC-Profiles and the document metadata must be given with XMP-Metadata.
242+
243+
<b>PDF/A-2</b> uses PDF-Version 1.7. It allows compression with JPEG2000, transparent elements, open type fonts and digital signatures.
244+
245+
The only extension for <b>PDF/A-3</b> is the possibility to embed any possible file.
246+
247+
### Conformance Classes ###
248+
249+
Level A (accessible) encompasses all the requirements of the standard, including mapping the content structure and the correct reading order of the document content. Text content must be extractable, and the structure must reflect the natural reading sequence.
250+
251+
Level B (Basic) guarantees a clear visual reproducibility of the content. Level B is generally easier to generate than Level A, but it does not ensure 100 percent text extraction or searchability. The hassle-free reuse of the content is not necessarily given.
252+
253+
To achieve this, here a little example:
254+
255+
```python
256+
{% include "../tutorial/tuto7.py" %}
257+
```
258+
259+
[Resulting PDF](https://github.com/py-pdf/fpdf2/raw/master/tutorial/tuto7.pdf) -
260+
[fpdf2-logo](https://raw.githubusercontent.com/py-pdf/fpdf2/master/docs/fpdf2-logo.png)
261+
262+
263+
```python
264+
pdf = PDF()
265+
```
266+
267+
The class PDF adds the needed embedded fonts using the
268+
[add_font()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.add_font)
269+
method for each style.
270+
271+
Then it adds the ICC profile object to the output intents array using the
272+
[add_output_intent()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.output_intent)
273+
method.
274+
275+
After adding first page, using the embedded font, writing some text, we create the pdf:
276+
```python
277+
pdf.create_pdf_with_metadata(
278+
filename="tuto7.pdf",
279+
language="en-US",
280+
title="Tutorial7",
281+
subject="Example for PDFA",
282+
creator=["John Dow", "Jane Dow"],
283+
description="this is my description of this file",
284+
keywords="Example Tutorial7"
285+
)
286+
```
287+
288+
Here we use pikepdf to create the needed metadata and set the type to PDF/A-3B.
289+
290+
In the function `create_pdf_with_metadata` we need to set 'language' and 'subject' outside the metadata before we use pikepdf to achieve conformance.
291+
292+
Please use something like verapdf to check conformance of resulting PDF.

tutorial/sRGB2014.icc

2.95 KB
Binary file not shown.

tutorial/tuto7.pdf

18.5 KB
Binary file not shown.

tutorial/tuto7.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from pathlib import Path
2+
from fpdf import FPDF
3+
from fpdf.enums import OutputIntentSubType
4+
from fpdf.output import PDFICCProfileObject
5+
from fpdf import FPDF_VERSION
6+
from datetime import datetime, timezone
7+
import pikepdf # pylint: disable=import-error
8+
9+
10+
DIR = Path(__file__).parent
11+
FONT_DIR = DIR / ".." / "test" / "fonts"
12+
13+
14+
class PDF(FPDF):
15+
16+
def create_pdf_with_metadata(
17+
self,
18+
filename: str,
19+
language: str = None,
20+
title: str = None,
21+
subject: str = None,
22+
creator: list = None,
23+
description: str = None,
24+
keywords: str = None,
25+
):
26+
if language:
27+
self.set_lang(language)
28+
if subject:
29+
self.set_subject(subject)
30+
31+
# create pdf
32+
self.output(filename)
33+
34+
with pikepdf.open(filename, allow_overwriting_input=True) as inner_pdf:
35+
with inner_pdf.open_metadata(set_pikepdf_as_editor=False) as meta:
36+
if title:
37+
meta["dc:title"] = title
38+
if creator:
39+
meta["dc:creator"] = creator
40+
if description:
41+
meta["dc:description"] = description
42+
if keywords:
43+
meta["pdf:Keywords"] = keywords
44+
meta["pdf:Producer"] = f"py-pdf/fpdf{FPDF_VERSION}"
45+
meta["xmp:CreatorTool"] = __file__
46+
meta["xmp:CreateDate"] = datetime.now(timezone.utc).isoformat()
47+
meta["pdfaid:part"] = "3"
48+
meta["pdfaid:conformance"] = "B"
49+
inner_pdf.save()
50+
51+
52+
pdf = PDF()
53+
54+
# import and embed TTF Font to use in text
55+
pdf.add_font("dejavu-sans", style="", fname=FONT_DIR / "DejaVuSans.ttf")
56+
pdf.add_font(
57+
"dejavu-sans",
58+
style="b",
59+
fname=FONT_DIR / "DejaVuSans-Bold.ttf",
60+
)
61+
pdf.add_font(
62+
"dejavu-sans",
63+
style="i",
64+
fname=FONT_DIR / "DejaVuSans-Oblique.ttf",
65+
)
66+
pdf.add_font(
67+
"dejavu-sans",
68+
style="bi",
69+
fname=FONT_DIR / "DejaVuSans-BoldOblique.ttf",
70+
)
71+
# set Output Intents
72+
with open(DIR / "sRGB2014.icc", "rb") as iccp_file:
73+
icc_profile = PDFICCProfileObject(
74+
contents=iccp_file.read(), n=3, alternate="DeviceRGB"
75+
)
76+
pdf.add_output_intent(
77+
OutputIntentSubType.PDFA,
78+
"sRGB",
79+
"IEC 61966-2-1:1999",
80+
"http://www.color.org",
81+
icc_profile,
82+
"sRGB2014 (v2)",
83+
)
84+
# First page:
85+
pdf.add_page()
86+
# use the font imported
87+
# and set style and size for H1
88+
pdf.set_font("dejavu-sans", "B", size=20)
89+
pdf.write(text="Header 1")
90+
# print empty lines
91+
pdf.ln()
92+
pdf.ln()
93+
# reset style and set size for normal Text
94+
pdf.set_font(None, "", size=12)
95+
pdf.write(text="this is an example")
96+
# print empty lines
97+
pdf.ln()
98+
pdf.ln()
99+
# set style for Text 2 to italic
100+
pdf.set_font(None, "I")
101+
pdf.write(text="this is the second example")
102+
103+
# create pdf with metadata
104+
pdf.create_pdf_with_metadata(
105+
filename="tuto7.pdf",
106+
language="en-US",
107+
title="Tutorial7",
108+
subject="Example for PDFA",
109+
creator=["John Dow", "Jane Dow"],
110+
description="this is my description of this file",
111+
keywords="Example Tutorial7",
112+
)

0 commit comments

Comments
 (0)