diff --git a/.all-contributorsrc b/.all-contributorsrc
index 0eeaba446..8a9467266 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -374,7 +374,16 @@
"avatar_url": "https://avatars.githubusercontent.com/u/24730417?v=4",
"profile": "https://github.com/Mridulbirla13",
"contributions": [
- "doc"
+ "translation"
+ ]
+ },
+ {
+ "login": "digidigital",
+ "name": "digidigital",
+ "avatar_url": "https://avatars.githubusercontent.com/u/28964886?v=4",
+ "profile": "https://github.com/digidigital",
+ "contributions": [
+ "translation"
]
}
],
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c68dd76f..ccdfbd20a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,16 +19,22 @@ and [PEP 440](https://www.python.org/dev/peps/pep-0440/).
5. [Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables)
6. [Creating links and mixing text styles](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-6-creating-links-and-mixing-text-styles)
-- New translation of the tutorial in Hindi, thanks to @Mridulbirla13: [हिंदी संस्करण](https://pyfpdf.github.io/fpdf2/Tutorial-हिंदी.html)
+- New translation of the tutorial in Hindi, thanks to @Mridulbirla13: [हिंदी संस्करण](https://pyfpdf.github.io/fpdf2/Tutorial-हिंदी.html); and [Deutsche](https://pyfpdf.github.io/fpdf2/Tutorial-de.html), thanks to @digidigital
- While images transparency is still handled by default through the use of `SMask`,
this can be disabled by setting `pdf.allow_images_transparency = False`
in order to allow compliance with [PDF/A-1](https://en.wikipedia.org/wiki/PDF/A#Description)
+- [`FPDF.arc`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.arc): new method added.
+ It enables to draw arcs in a PDF document.
+- [`FPDF.solid_arc`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.solid_arc): new method added.
+ It enables to draw solid arcs in a PDF document. A solid arc combines an arc and a triangle to form a pie slice.
### Fixed
- The exception making the "x2" template field optional for barcode elements did not work correctly, fixed by @gmischler
### Changed
- All template elements now have a transparent default background instead of white, thanks to @gmischler
- To reduce the size of generated PDFs, no `SMask` entry is inserted for images that are fully opaque
(= with an alpha channel containing only 0xff characters)
+- The `rect`, `ellipse` & `circle` all have a `style` parameter in common.
+ They now all properly accept a value of `"D"` and raise a `ValueError` for invalid values.
### Deprecated
- `dashed_line()` is now deprecated in favor of `set_dash_pattern()`
@@ -71,7 +77,7 @@ and [PEP 440](https://www.python.org/dev/peps/pep-0440/).
- `Template` `background` property is now properly supported - [#203](https://github.com/PyFPDF/fpdf2/pull/203)
⚠️ Beware that its default value changed from `0` to `0xffffff`, as a value of **zero would render the background as black**.
- `Template.parse_csv`: preserving numeric values when using CSV based templates - [#205](https://github.com/PyFPDF/fpdf2/pull/205)
-- the code snippet to generate Code 39 barcodes in the documentation was missing the start & end `*` characters.
+- the code snippet to generate Code 39 barcodes in the documentation was missing the start & end `*` characters.
This has been fixed, and a warning is now triggered by the [`FPDF.code39`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.code39) method when those characters are missing.
### Fixed
- Detect missing `uni=True` when loading cached fonts (page numbering was missing digits)
diff --git a/README.md b/README.md
index d58d3d0ed..715167f86 100644
--- a/README.md
+++ b/README.md
@@ -81,7 +81,7 @@ Documentation:
--------------
- [Documentation Home](https://pyfpdf.github.io/fpdf2/)
-- Tutorial in several languages: [English](https://pyfpdf.github.io/fpdf2/Tutorial.html) - [Spanish](https://pyfpdf.github.io/fpdf2/Tutorial-es.html) - [हिंदी](https://pyfpdf.github.io/fpdf2/Tutorial-हिंदी.html)
+- Tutorial in several languages: [English](https://pyfpdf.github.io/fpdf2/Tutorial.html) - [Deutsche](https://pyfpdf.github.io/fpdf2/Tutorial-de.html) - [Spanish](https://pyfpdf.github.io/fpdf2/Tutorial-es.html) - [हिंदी](https://pyfpdf.github.io/fpdf2/Tutorial-हिंदी.html)
- Release notes: [CHANGELOG.md](https://github.com/PyFPDF/fpdf2/blob/master/CHANGELOG.md)
You can also have a look at the `tests/`, they're great usage examples!
@@ -146,7 +146,8 @@ This library could only exist thanks to the dedication of many volunteers around
 Tabarnhack 💻 |
-  Mridul Birla 📖 |
+  Mridul Birla 🌍 |
+  digidigital 🌍 |
diff --git a/docs/Shapes.md b/docs/Shapes.md
index c7ed4139b..e02cb509e 100644
--- a/docs/Shapes.md
+++ b/docs/Shapes.md
@@ -71,3 +71,29 @@ coords = ((100, 0), (5, 69), (41, 181), (159, 181), (195, 69))
pdf.polygon(coords, fill=True)
pdf.output("polygon.pdf")
```
+
+## Arc ##
+
+```python
+from fpdf import FPDF
+
+pdf = FPDF()
+pdf.add_page()
+pdf.set_line_width(2)
+pdf.set_fill_color(r=255, g=0, b=0)
+pdf.arc(x=75, y=75, a=25, b=25, start_angle=30, end_angle=130, style="FD")
+pdf.output("arc.pdf")
+```
+
+## Solid arc ##
+
+```python
+from fpdf import FPDF
+
+pdf = FPDF()
+pdf.add_page()
+pdf.set_line_width(2)
+pdf.set_fill_color(r=255, g=0, b=0)
+pdf.solid_arc(x=75, y=75, a=25, b=25, start_angle=30, end_angle=130, style="FD")
+pdf.output("solid_arc.pdf")
+```
\ No newline at end of file
diff --git a/docs/Tutorial-de.md b/docs/Tutorial-de.md
new file mode 100644
index 000000000..285bad54c
--- /dev/null
+++ b/docs/Tutorial-de.md
@@ -0,0 +1,214 @@
+# Kurzanleitung #
+
+English version: [Tutorial](Tutorial.md)
+
+Versión en español: [Tutorial-es](Tutorial-es.md)
+
+हिंदी संस्करण: [Tutorial-हिंदी](Tutorial-हिंदी.md)
+
+Vollständige Dokumentation der Methoden: [`fpdf.FPDF` API doc](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF)
+
+[TOC]
+
+## Lektion 1 - Minimalbeispiel ##
+
+Beginnen wir mit dem Klassiker:
+
+```python
+{% include "../tutorial/tuto1.py" %}
+```
+
+[Erzeugtes PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto1.pdf)
+
+Nachdem wir die Bibliothek eingebunden haben, erstellen zuerst wir ein `FPDF` Objekt. Der
+[`FPDF`](fpdf/fpdf.html#fpdf.fpdf.FPDF) Konstruktor wird hier mit den Standardwerten verwendet: Das Seitenformat wird auf A4-Hochformat gesetzt und als Maßeinheit Millimeter festgelegt.
+
+Diese Werte hätten wir auch explizit angegeben können:
+
+```python
+pdf = FPDF(orientation="P", unit="mm", format="A4")
+```
+Es ist auch möglich, eine PDF-Datei im Querformat zu erstellen (`L`), sowie andere Seitenformate
+(`Letter` und `Legal`) und Maßeinheiten (`pt`, `cm`, `in`) zu verwenden.
+
+Bisher haben wir dem Dokument noch keine Seite hinzugefügt. Um eine Seite hinzuzufügen, verwenden wir [`add_page`](fpdf/fpdf.html#fpdf.fpdf.FPDF.add_page).
+Der Ursprung der Koordinaten liegt in der oberen linken Ecke und die aktuelle Schreibposition ist standardmäßig jeweils 1 cm von den Rändern entfernt. Diese Randabstände können mit [`set_margins`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_margins) angespasst werden.
+
+Bevor wir Text hinzufügen können, müssen wir zuerst mit [`set_font`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_font) eine Schriftart festlegen, um ein gültiges Dokument zu erzeugen.
+Wir wählen Helvetica, fett in Schriftgröße 16 pt:
+
+```python
+pdf.set_font('helvetica', 'B', 16)
+```
+
+Anstelle von `B` hätten wir mit `I` kursiv , `U` unterstichen oder durch die Übergabe einer leeren Zeichenkette einen "normale" Textstil wählen können. Beliebige Kombinationen der drei Werte sind zulässig. Beachte, dass die Schriftgröße in Punkt und nicht in Millimetern (oder einer anderen durch den Benutzer bei der Erstellung mit `unit=` festgelegten Maßeinheit) angegeben wird.
+Dies ist die einzige Ausnahme vom Grundsatz, dass immer die durch den Benutzer gewählte Maßeinheit bei der Festlegung von Positions- oder Größenangaben genutzt wird. Neben `Helvetica` stehen `Times`, `Courier`, `Symbol` und `ZapfDingbats` als Standardschriftarten zur Verfügung.
+
+Wir können jetzt eine erste Textzelle mit [`cell`](fpdf/fpdf.html#fpdf.fpdf.FPDF.cell) einfügen. Eine Zelle ist ein rechteckiger
+Bereich - optional umrahmt - der Text enthalten kann. Sie wird an der jeweils aktuellen Schreibposition gerendert. Wir können die Abmessungen der Zelle, den Text und dessen Formatierung (zentriert oder ausgerichtet), einen ggf. gewünschten Rahmen und die Festlegung der neuen Schreibposition nach dem Schreiben der Zelle (rechts, unten oder am Anfang der nächsten Zeile) bestimmen.
+
+Um einen Rahmen hinzuzufügen, würden wir die Methode folgendermaßen einbinden:
+
+```python
+pdf.cell(40, 10, 'Hello World!', 1)
+```
+
+Um eine neue Zelle mit zentriertem Text hinzuzufügen und anschließend in die nächste Zeile zu springen, können wir Folgendes schreiben:
+
+```python
+pdf.cell(60, 10, 'Powered by FPDF.', ln=1, align='C')
+```
+
+**Anmerkung**: Der Zeilenumbruch kann auch mit [`ln`](fpdf/fpdf.html#fpdf.fpdf.FPDF.ln) erfolgen. Diese
+Methode erlaubt es, zusätzlich die Höhe des Umbruchs anzugeben.
+
+Schließlich wird das Dokument mit [`output`](fpdf/fpdf.html#fpdf.fpdf.FPDF.output) geschlossen und unter dem angegebenen Dateipfad gespeichert.
+Ohne Angabe eines Parameters liefert `output()` den PDF `bytearray`-Puffer zurück.
+
+## Lektion 2 - Kopfzeile, Fußzeile, Seitenumbruch und Bild ##
+
+Hier ein zweiseitiges Beispiel mit Kopfzeile, Fußzeile und Logo:
+
+```python
+{% include "../tutorial/tuto2.py" %}
+```
+
+[Erzeugtes PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto2.pdf)
+
+Dieses Beispiel verwendet die Methoden [`header`](fpdf/fpdf.html#fpdf.fpdf.FPDF.header) und
+[`footer`](fpdf/fpdf.html#fpdf.fpdf.FPDF.footer), um Kopf- und Fußzeilen zu verarbeiten. Sie
+werden jeweils automatisch aufgerufen. Die Methode 'header' direkt nach dem Hinzugügen einer neuen Seite, die Methode 'footer' wenn die Bearbeitung einer Seite durch das Hinzufügen einer weiteren Seite oder das Abspeichern des Dokuments abgeschlossen wird.
+Die Methoden existieren bereits in der Klasse FPDF, sind aber leer. Um sie zu nutzen, müssen wir die Klasse erweitern und sie überschreiben.
+
+Das Logo wird mit der Methode [`image`](fpdf/fpdf.html#fpdf.fpdf.FPDF.image) eingebunden, und auf der Seite durch die Angabe der Position der linken oberen Ecke und die gewünschte Bildbreite platziert. Die Höhe wird automatisch berechnet, um die Proportionen des Bildes zu erhalten.
+
+Um die Seitenzahl einzufügenn, übergeben wir zuerst der Zelle einen Nullwert als Breite der Zelle. Das bedeutet,
+dass die Zelle bis zum rechten Rand der Seite reichen soll. Das ist besonders praktisch, um
+Text zu zentrieren. Die aktuelle Seitenzahl wird durch
+die Methode [`page_no`](fpdf/fpdf.html#fpdf.fpdf.FPDF.page_no) ermittelt und in die Zelle geschrieben.
+Die Gesamtseitenzahl wird mit Hilfe des speziellen Platzhalterwertes `{nb}` ermittelt,
+der beim Schließen des Dokuments ersetzt wird (vorausgesetzt, du hast vorher
+[`alias_nb_pages`](fpdf/fpdf.html#fpdf.fpdf.FPDF.alias_nb_pages)) aufgerufen.
+Beachte die Verwendung der Methode [`set_y`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_y), mit der du die
+vertikale Schreibposition an einer absoluten Stelle der Seite - von oben oder von
+unten aus - setzen kannst.
+
+Eine weitere interessante Funktion wird hier ebenfalls verwendet: der automatische Seitenumbruch. Sobald
+eine Zelle eine festgelegte Grenze in der Seite überschreitet (standardmäßig 2 Zentimeter vom unteren Rand), wird ein
+Seitenumbruch durchgeführt und die Einstellungen der gewahlten Schrift auf der nächsten Seite automatisch beibehalten. Obwohl die Kopf- und
+Fußzeilen ihre eigene Schriftart (`Helvetica`) wählen, wird im Textkörper `Times` verwendet.
+Dieser Mechanismus der automatischen Übernahme der Einstellungen nach Seitenumbruch gilt auch für Farben und Zeilenbreite.
+Der Grenzwert, der den Seitenumbruch auslöst, kann mit [`set_auto_page_break`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_auto_page_break) festgelegt werden .
+
+## Lektion 3 - Zeilenumbrüche und Farben ##
+
+Fahren wir mit einem Beispiel fort, das Absätze im Blocksatz ausgibt. Es demonstriert auch die Verwendung von Farben.
+
+```python
+{% include "../tutorial/tuto3.py" %}
+```
+
+[Resulting PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto3.pdf)
+
+[Jules Verne text](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/20k_c1.txt)
+
+Die Methode [`get_string_width`](fpdf/fpdf.html#fpdf.fpdf.FPDF.get_string_width) ermöglicht die Bestimmung
+die Breite des übergebenen Textes in der aktuellen Schriftart. Das Beispiel nutzt sie zur Berechnung der
+Position und der Breite des Rahmens, der den Titel umgibt. Anschließend werden die Farben mit [`set_draw_color`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_draw_color), [`set_fill_color`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_fill_color) und
+und [`set_text_color`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_text_color) gesetzt und die Linienstärke mit [`set_line_width`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_line_width) auf 1 mm (Abweichend vom Standardwert von 0,2) festgelegt. Schließlich geben wir die Zelle aus
+(Der letzte Parameter True zeigt an, dass der Hintergrund gefüllt werden muss).
+
+Zur Erstellung von Absätzen wir die Methode [`multi_cell`](fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) genutzt.
+Jedes Mal, wenn eine Zeile den rechten Rand der Zelle erreicht oder ein Zeilenumbruchzeichen `\\n` im Text erkannt wird,
+wird ein Zeilenumbruch durchgeführt und automatisch eine neue Zelle unterhalb der aktuellen Zelle erstellt.
+Der Text wird standardmäßig im Blocksatz ausgerichtet.
+
+Es werden zwei Dokumenteigenschaften definiert: Titel
+([`set_title`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_title)) und Autor
+([`set_author`](fpdf/fpdf.html#fpdf.fpdf.FPDF.set_author)). Dokumenteneigenschaften können auf zwei Arten eingesehen werden.
+Man kann das Dokument mit dem Acrobat Reader öffnen und im Menü **Datei** die Option **Dokumenteigenschaften** auswählen.
+Alternativ kann man auch mit der rechten Maustaste auf das Dokument klicken und die Option Dokumenteigenschaften wählen.
+
+## Lektion 4 - Mehrspaltiger Text ##
+
+ Dieses Beispiel ist eine Abwandlung des vorherigen Beispiels und zeigt, wie sich Text über mehrere Spalten verteilen lässt.
+
+```python
+{% include "../tutorial/tuto4.py" %}
+```
+
+[Erzeugtes PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto4.pdf)
+
+[Jules Verne Text](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/20k_c1.txt)
+
+Der Hauptunterschied zur vorherigen Lektion ist die Verwendung der Methoden
+[`accept_page_break`](fpdf/fpdf.html#fpdf.fpdf.FPDF.accept_page_break) und `set_col`.
+
+Wird [`accept_page_break`](fpdf/fpdf.html#fpdf.fpdf.FPDF.accept_page_break) verwendet, wird die aktuelle Spaltennummer überprüft, sobald
+die Zelle den zur Auslösung eines Seitenumbruchs festgelegten Abstand zum unteren Seitenrand (Standard 2cm) überschreitet. Ist die Spaltennummer kleiner als 2 (wir haben uns entschieden, die Seite in drei Spalten zu unterteilen), wird die Methode `set_col` aufgerufen. Sie erhöht die Spaltennummer auf die nächsthöhere und setzt die Schreibposition auf den Anfang der nächsten Spalte, damit der Text dort fortgesetzt werden kann.
+
+Sobald det Text der dritten den oben beschriebenen Abstand zum Seitenende erreicht, wird durch die Methode [`accept_page_break`](fpdf/fpdf.html#fpdf.fpdf.FPDF.accept_page_break) ein Seitenumbruch ausgelöst und die aktive Spalte sowie Schreibposition zurückgesetzt.
+
+## Lektion 5 - Tabellen erstellen ##
+
+In dieser Lektion zeigen wir, wie man auf einfache Weise Tabellen erstellen kann.
+
+Der Code wird drei verschiedene Tabellen erstellen, um zu zeigen, welche Effekte wir mit einigen einfachen Anpassungen erzielen können.
+
+```python
+{% include "../tutorial/tuto5.py" %}
+```
+
+[Erzeugtes PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) -
+[Länder](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt)
+
+Da eine Tabelle lediglich eine Sammlung von Zellen darstellt, ist es naheliegend, eine Tabelle aus den bereits bekannten Zellen aufzubauen.
+
+Das erste Beispiel wird auf die einfachste Art und Weise realisiert. Einfach gerahmte Zellen, die alle die gleiche Größe haben und linksbündig ausgerichtet sind. Das Ergebnis ist rudimentär, aber sehr schnell zu erzielen.
+
+Die zweite Tabelle bringt einige Verbesserungen: Jede Spalte hat ihre eigene Breite,
+ die Überschriften sind zentriert und die Zahlen rechtsbündig ausgerichtet. Außerdem wurden die horizontalen Linien
+ entfernt. Dies geschieht mit Hilfe des Randparameters der Methode `cell()`, der angibt, welche Seiten der Zelle gezeichnet werden müssen.
+ Im Beispiel wählen wir die linke (L) und die rechte (R) Seite. Jetzt muss nur noch das Problem der horizontalen Linie
+ zum Abschluss der Tabelle gelöst werden. Es gibt zwei Möglichkeiten, es zu lösen: In der Schleife prüfen, ob wir uns in der letzten Zeile befinden und dann "LRB" als Rahmenparameter übergeben oder, wie hier geschehen, eine abschließende Zelle separat nach dem Durchlaufen der Schleife einfügen.
+
+Die dritte Tabelle der zweiten sehr ähnlich, verwendet aber zusätzlich Farben. Füllung, Text und
+ Linienfarben werden einfach mit den entsprechenden Methoden gesetzt. Eine wechselnde Färbung der Zeilen wird durch die abwechselnde Verwendung transparenter und gefüllter Zellen erreicht.
+
+## Lektion 6 - Links erstellen und Textstile mischen ##
+
+In dieser Lektion werden verschiedene Möglichkeiten der Erstellung interner und externer Links beschrieben.
+
+Es wird auch gezeigt, wie man verschiedene Textstile (fett, kursiv, unterstrichen) innerhalb eines Textes verwenden kann.
+
+```python
+{% include "../tutorial/tuto6.py" %}
+```
+
+[Erzeugtes PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto6.pdf) -
+[fpdf2-logo](https://raw.githubusercontent.com/PyFPDF/fpdf2/master/docs/fpdf2-logo.png)
+
+Die hier gezeigte neue Methode zur Einbindung von Text lautet
+ [`write()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write). Sie ähnelt der bereits bekannten
+ [`multi_cell()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell). Die wichtigsten Unterschiede sind:
+
+- Das Ende der Zeile befindet sich am rechten Rand und die nächste Zeile beginnt am linken
+ Rand.
+- Die aktuelle Position wird an das Textende gesetzt.
+
+Die Methode ermöglicht es uns somit, zuerst einen Textabschnitt zu schreiben, dann den Schriftstil zu ändern
+und genau an der Stelle fortzufahren, an der wir aufgehört haben.
+Der größte Nachteil ist jedoch, dass die von [`multi_cell()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) bekannte Möglichkeit zur Festlegung der Textausrichtung fehlt.
+
+Auf der ersten Seite des Beispiels nutzen wir [`write()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write).
+Der Anfang des Satzes wird in "normalem" Stil geschrieben, dann mit der Methode
+ [`set_font()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_font) auf Unterstreichung umgestellt und der Satz beendet.
+
+Um einen internen Link hinzuzufügen, der auf die zweite Seite verweist, nutzen wir die Methode
+ [`add_link()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.add_link), die einen anklickbaren Bereich erzeugt,
+ den wir "link" nennen und der auf eine andere Stelle innerhalb des Dokuments verweist. Auf der zweiten Seite verwenden wir
+ [`set_link()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_link), um den Zielbereich für den soeben erstellten Link zu definieren.
+
+Um einen externen Link mit Hilfe eines Bildes zu erstellen, verwenden wir [`image()`](https://pyfpdf.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.
+
+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.
diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index 11df474c1..a311b2f40 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -2,6 +2,8 @@
Version en français : [Tutorial-fr](Tutorial-fr.md)
+Deutsche Version: [Tutorial-de](Tutorial-de.md)
+
Versión en español: [Tutorial-es](Tutorial-es.md)
हिंदी संस्करण: [Tutorial-हिंदी](Tutorial-हिंदी.md)
diff --git a/docs/index.md b/docs/index.md
index c73ddd409..5f4d419c7 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -48,6 +48,7 @@ FPDF original features:
## Tutorials ##
* [English](https://pyfpdf.github.io/fpdf2/Tutorial.html)
+* [Deutsche](https://pyfpdf.github.io/fpdf2/Tutorial-de.html)
* [Spanish](https://pyfpdf.github.io/fpdf2/Tutorial-es.html)
* [हिंदी](https://pyfpdf.github.io/fpdf2/Tutorial-हिंदी.html)
diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py
index a2eb9f4dd..da5229ab0 100644
--- a/fpdf/fpdf.py
+++ b/fpdf/fpdf.py
@@ -1017,8 +1017,7 @@ def rect(self, x, y, w, h, style=None):
* `F`: fill
* `DF` or `FD`: draw and fill
"""
- style_to_operators = {"F": "f", "FD": "B", "DF": "B"}
- op = style_to_operators.get(style, "S")
+ op = _style_to_operator(style)
self._out(
f"{x * self.k:.2f} {(self.h - y) * self.k:.2f} {w * self.k:.2f} "
f"{-h * self.k:.2f} re {op}"
@@ -1040,8 +1039,7 @@ def ellipse(self, x, y, w, h, style=None):
* `F`: fill
* `DF` or `FD`: draw and fill
"""
- style_to_operators = {"F": "f", "FD": "B", "DF": "B"}
- op = style_to_operators.get(style, "S")
+ op = _style_to_operator(style)
cx = x + w / 2
cy = y + h / 2
@@ -1098,6 +1096,194 @@ def circle(self, x, y, r, style=None):
"""
self.ellipse(x, y, r, r, style)
+ @check_page
+ def arc(
+ self,
+ x,
+ y,
+ a,
+ start_angle,
+ end_angle,
+ b=None,
+ inclination=0,
+ clockwise=False,
+ start_from_center=False,
+ end_at_center=False,
+ style=None,
+ ):
+ """
+ Outputs an arc.
+ It can be drawn (border only), filled (with no border) or both.
+
+ Args:
+ x (int): Abscissa of upper-left bounging box.
+ y (int): Ordinate of upper-left bounging box.
+ a (int): Semi-major axis diameter.
+ b (int): Semi-minor axis diameter, if None, equals to a (default: None).
+ start_angle (int): Start angle of the arc (in degrees).
+ end_angle (int): End angle of the arc (in degrees).
+ inclination (int): Inclination of the arc in respect of the x-axis (default: 0).
+ clockwise (bool): Way of drawing the arc (True: clockwise, False: counterclockwise) (default: False).
+ start_from_center (bool): Start drawing from the center of the circle (default: False).
+ end_at_center (bool): End drawing at the center of the circle (default: False).
+ style (int): Style of rendering. Possible values are:
+ * `D` or None: draw border. This is the default value.
+ * `F`: fill
+ * `DF` or `FD`: draw and fill
+ """
+ op = _style_to_operator(style)
+
+ if b is None:
+ b = a
+
+ a /= 2
+ b /= 2
+
+ cx = x + a
+ cy = y + b
+
+ # Functions used only to construct other points of the bezier curve
+ def deg_to_rad(deg):
+ return deg * math.pi / 180
+
+ def angle_to_param(angle):
+ angle = deg_to_rad(angle % 360)
+ eta = math.atan2(math.sin(angle) / b, math.cos(angle) / a)
+
+ if eta < 0:
+ eta += 2 * math.pi
+ return eta
+
+ theta = deg_to_rad(inclination)
+ cos_theta = math.cos(theta)
+ sin_theta = math.sin(theta)
+
+ def evaluate(eta):
+ a_cos_eta = a * math.cos(eta)
+ b_sin_eta = b * math.sin(eta)
+
+ return [
+ cx + a_cos_eta * cos_theta - b_sin_eta * sin_theta,
+ cy + a_cos_eta * sin_theta + b_sin_eta * cos_theta,
+ ]
+
+ def derivative_evaluate(eta):
+ a_sin_eta = a * math.sin(eta)
+ b_cos_eta = b * math.cos(eta)
+
+ return [
+ -a_sin_eta * cos_theta - b_cos_eta * sin_theta,
+ -a_sin_eta * sin_theta + b_cos_eta * cos_theta,
+ ]
+
+ # Calculating start_eta and end_eta so that
+ # start_eta < end_eta <= start_eta + 2*PI if counterclockwise
+ # end_eta < start_eta <= end_eta + 2*PI if clockwise
+ start_eta = angle_to_param(start_angle)
+ end_eta = angle_to_param(end_angle)
+
+ if not clockwise and end_eta <= start_eta:
+ end_eta += 2 * math.pi
+ elif clockwise and end_eta >= start_eta:
+ start_eta += 2 * math.pi
+
+ start_point = evaluate(start_eta)
+
+ # Move to the start point
+ if start_from_center:
+ self._out(f"{cx * self.k:.2f} {(self.h - cy) * self.k:.2f} m")
+ self._out(
+ f"{start_point[0] * self.k:.2f} {(self.h - start_point[1]) * self.k:.2f} l"
+ )
+ else:
+ self._out(
+ f"{start_point[0] * self.k:.2f} {(self.h - start_point[1]) * self.k:.2f} m"
+ )
+
+ # Number of curves to use, maximal segment angle is 2*PI/max_curves
+ max_curves = 4
+ n = min(
+ max_curves, math.ceil(abs(end_eta - start_eta) / (2 * math.pi / max_curves))
+ )
+ d_eta = (end_eta - start_eta) / n
+
+ alpha = math.sin(d_eta) * (math.sqrt(4 + 3 * math.tan(d_eta / 2) ** 2) - 1) / 3
+
+ eta2 = start_eta
+ p2 = evaluate(eta2)
+ p2_prime = derivative_evaluate(eta2)
+
+ for i in range(n):
+ p1 = p2
+ p1_prime = p2_prime
+
+ eta2 += d_eta
+ p2 = evaluate(eta2)
+ p2_prime = derivative_evaluate(eta2)
+
+ control_point_1 = [p1[0] + alpha * p1_prime[0], p1[1] + alpha * p1_prime[1]]
+ control_point_2 = [p2[0] - alpha * p2_prime[0], p2[1] - alpha * p2_prime[1]]
+
+ end = ""
+ if i == n - 1 and not end_at_center:
+ end = f" {op}"
+
+ self._out(
+ (
+ f"{control_point_1[0] * self.k:.2f} {(self.h - control_point_1[1]) * self.k:.2f} "
+ f"{control_point_2[0] * self.k:.2f} {(self.h - control_point_2[1]) * self.k:.2f} "
+ f"{p2[0] * self.k:.2f} {(self.h - p2[1]) * self.k:.2f} c" + end
+ )
+ )
+
+ if end_at_center:
+ self._out(f"{cx * self.k:.2f} {(self.h - cy) * self.k:.2f} l {op}")
+
+ @check_page
+ def solid_arc(
+ self,
+ x,
+ y,
+ a,
+ start_angle,
+ end_angle,
+ b=None,
+ inclination=0,
+ clockwise=False,
+ style=None,
+ ):
+ """
+ Outputs a solid arc. A solid arc combines an arc and a triangle to form a pie slice
+ It can be drawn (border only), filled (with no border) or both.
+
+ Args:
+ x (int): Abscissa of upper-left bounging box.
+ y (int): Ordinate of upper-left bounging box.
+ a (int): Semi-major axis.
+ b (int): Semi-minor axis, if None, equals to a (default: None).
+ start_angle (int): Start angle of the arc (in degrees).
+ end_angle (int): End angle of the arc (in degrees).
+ inclination (int): Inclination of the arc in respect of the x-axis (default: 0).
+ clockwise (bool): Way of drawing the arc (True: clockwise, False: counterclockwise) (default: False).
+ style (int): Style of rendering. Possible values are:
+ * `D` or None: draw border. This is the default value.
+ * `F`: fill
+ * `DF` or `FD`: draw and fill
+ """
+ self.arc(
+ x,
+ y,
+ a,
+ start_angle,
+ end_angle,
+ b,
+ inclination,
+ clockwise,
+ True,
+ True,
+ style,
+ )
+
def add_font(self, family, style="", fname=None, uni=False):
"""
Imports a TrueType, OpenType or Type1 font and makes it available
@@ -3689,6 +3875,17 @@ def _apply_style(self, title_style):
self.underline = prev_underline
+def _style_to_operator(style):
+ style_to_operators = {"F": "f", "FD": "B", "DF": "B", "D": "S"}
+ if not style:
+ style = "D"
+ if style not in style_to_operators:
+ raise ValueError(
+ f"Invalid value for style: '{style}'. Allowed values: {'/'.join(style_to_operators.keys())}"
+ )
+ return style_to_operators[style]
+
+
def _char_width(font, char):
cw = font["cw"]
try:
diff --git a/test/shapes/class_arc_clockwise.pdf b/test/shapes/class_arc_clockwise.pdf
new file mode 100644
index 000000000..4ae08031b
Binary files /dev/null and b/test/shapes/class_arc_clockwise.pdf differ
diff --git a/test/shapes/class_arc_draw_color.pdf b/test/shapes/class_arc_draw_color.pdf
new file mode 100644
index 000000000..71b92f2d3
Binary files /dev/null and b/test/shapes/class_arc_draw_color.pdf differ
diff --git a/test/shapes/class_arc_end_at_center.pdf b/test/shapes/class_arc_end_at_center.pdf
new file mode 100644
index 000000000..5e202ecd7
Binary files /dev/null and b/test/shapes/class_arc_end_at_center.pdf differ
diff --git a/test/shapes/class_arc_fill_color.pdf b/test/shapes/class_arc_fill_color.pdf
new file mode 100644
index 000000000..0e0fbfa2c
Binary files /dev/null and b/test/shapes/class_arc_fill_color.pdf differ
diff --git a/test/shapes/class_arc_inclination.pdf b/test/shapes/class_arc_inclination.pdf
new file mode 100644
index 000000000..4490e0cc1
Binary files /dev/null and b/test/shapes/class_arc_inclination.pdf differ
diff --git a/test/shapes/class_arc_line_width.pdf b/test/shapes/class_arc_line_width.pdf
new file mode 100644
index 000000000..a1f121a3c
Binary files /dev/null and b/test/shapes/class_arc_line_width.pdf differ
diff --git a/test/shapes/class_arc_not_circle.pdf b/test/shapes/class_arc_not_circle.pdf
new file mode 100644
index 000000000..8a9bb04a9
Binary files /dev/null and b/test/shapes/class_arc_not_circle.pdf differ
diff --git a/test/shapes/class_arc_start_from_center.pdf b/test/shapes/class_arc_start_from_center.pdf
new file mode 100644
index 000000000..5e081e747
Binary files /dev/null and b/test/shapes/class_arc_start_from_center.pdf differ
diff --git a/test/shapes/class_arc_style.pdf b/test/shapes/class_arc_style.pdf
new file mode 100644
index 000000000..d9fc2d02e
Binary files /dev/null and b/test/shapes/class_arc_style.pdf differ
diff --git a/test/shapes/class_solid_arc_clockwise.pdf b/test/shapes/class_solid_arc_clockwise.pdf
new file mode 100644
index 000000000..979fa44bf
Binary files /dev/null and b/test/shapes/class_solid_arc_clockwise.pdf differ
diff --git a/test/shapes/class_solid_arc_draw_color.pdf b/test/shapes/class_solid_arc_draw_color.pdf
new file mode 100644
index 000000000..2721f5ee3
Binary files /dev/null and b/test/shapes/class_solid_arc_draw_color.pdf differ
diff --git a/test/shapes/class_solid_arc_fill_color.pdf b/test/shapes/class_solid_arc_fill_color.pdf
new file mode 100644
index 000000000..8fa0dac2c
Binary files /dev/null and b/test/shapes/class_solid_arc_fill_color.pdf differ
diff --git a/test/shapes/class_solid_arc_inclination.pdf b/test/shapes/class_solid_arc_inclination.pdf
new file mode 100644
index 000000000..0d910d537
Binary files /dev/null and b/test/shapes/class_solid_arc_inclination.pdf differ
diff --git a/test/shapes/class_solid_arc_line_width.pdf b/test/shapes/class_solid_arc_line_width.pdf
new file mode 100644
index 000000000..bf97107de
Binary files /dev/null and b/test/shapes/class_solid_arc_line_width.pdf differ
diff --git a/test/shapes/class_solid_arc_not_circle.pdf b/test/shapes/class_solid_arc_not_circle.pdf
new file mode 100644
index 000000000..a4eed9133
Binary files /dev/null and b/test/shapes/class_solid_arc_not_circle.pdf differ
diff --git a/test/shapes/class_solid_arc_style.pdf b/test/shapes/class_solid_arc_style.pdf
new file mode 100644
index 000000000..6426790d9
Binary files /dev/null and b/test/shapes/class_solid_arc_style.pdf differ
diff --git a/test/shapes/test_arc.py b/test/shapes/test_arc.py
new file mode 100644
index 000000000..304542510
--- /dev/null
+++ b/test/shapes/test_arc.py
@@ -0,0 +1,254 @@
+from pathlib import Path
+
+import fpdf
+from test.conftest import assert_pdf_equal
+
+
+HERE = Path(__file__).resolve().parent
+
+
+def next_row(pdf):
+ pdf.ln()
+ pdf.set_y(pdf.get_y() + size + margin)
+
+
+size = 50
+start_angle, end_angle = 30, 130
+margin = 10
+
+
+def test_arc_not_circle(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for counter, style in enumerate(["F", "FD", "DF", None]):
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size / 2,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=style,
+ )
+ pdf.set_x(pdf.get_x() + (size / 2) + margin)
+ if counter % 3 == 0:
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_not_circle.pdf", tmp_path)
+
+
+def test_arc_style(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for counter, style in enumerate(["F", "FD", "DF", None]):
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=style,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ if counter % 3 == 0:
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_style.pdf", tmp_path)
+
+
+def test_arc_line_width(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for line_width in [1, 2, 3]:
+ pdf.set_line_width(line_width)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ next_row(pdf)
+ for line_width in [4, 5, 6]:
+ pdf.set_line_width(line_width)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ pdf.set_line_width(0.2) # reset
+
+ assert_pdf_equal(pdf, HERE / "class_arc_line_width.pdf", tmp_path)
+
+
+def test_arc_draw_color(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ pdf.set_line_width(0.5)
+ for gray in [70, 140, 210]:
+ pdf.set_draw_color(gray)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_draw_color.pdf", tmp_path)
+
+
+def test_arc_fill_color(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ pdf.set_fill_color(240)
+ for color in [[230, 30, 180], [30, 180, 30], [30, 30, 70]]:
+ pdf.set_draw_color(*color)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style="FD",
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_fill_color.pdf", tmp_path)
+
+
+def test_arc_inclination(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for counter, inclination in enumerate([0, 30, 90, 120]):
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ if counter % 3 == 0:
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_inclination.pdf", tmp_path)
+
+
+def test_arc_clockwise(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for inclination in [0, 30, 90, 120]:
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ clockwise=True,
+ style=None,
+ )
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_clockwise.pdf", tmp_path)
+
+
+def test_arc_start_from_center(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for inclination in [0, 30, 90, 120]:
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ start_from_center=True,
+ style=None,
+ )
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_start_from_center.pdf", tmp_path)
+
+
+def test_arc_end_at_center(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for inclination in [0, 30, 90, 120]:
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ pdf.arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ end_at_center=True,
+ style=None,
+ )
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_arc_end_at_center.pdf", tmp_path)
diff --git a/test/shapes/test_solid_arc.py b/test/shapes/test_solid_arc.py
new file mode 100644
index 000000000..5e646c634
--- /dev/null
+++ b/test/shapes/test_solid_arc.py
@@ -0,0 +1,198 @@
+from pathlib import Path
+
+import fpdf
+from test.conftest import assert_pdf_equal
+
+
+HERE = Path(__file__).resolve().parent
+
+
+def next_row(pdf):
+ pdf.ln()
+ pdf.set_y(pdf.get_y() + size + margin)
+
+
+size = 50
+start_angle, end_angle = 30, 130
+margin = 10
+
+
+def test_solid_arc_not_circle(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for counter, style in enumerate(["F", "FD", "DF", None]):
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size / 2,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=style,
+ )
+ pdf.set_x(pdf.get_x() + (size / 2) + margin)
+ if counter % 3 == 0:
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_not_circle.pdf", tmp_path)
+
+
+def test_solid_arc_style(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for counter, style in enumerate(["F", "FD", "DF", None]):
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=style,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ if counter % 3 == 0:
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_style.pdf", tmp_path)
+
+
+def test_solid_arc_line_width(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ size_1 = size
+
+ for line_width in [1, 2, 3]:
+ pdf.set_line_width(line_width)
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ # A workaround to avoid warning of pylint triggering duplicate code
+ # with test_arc.py
+ a=size_1,
+ b=size_1,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ next_row(pdf)
+ for line_width in [4, 5, 6]:
+ pdf.set_line_width(line_width)
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ pdf.set_line_width(0.2) # reset
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_line_width.pdf", tmp_path)
+
+
+def test_solid_arc_draw_color(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ pdf.set_line_width(0.5)
+ for gray in [70, 140, 210]:
+ pdf.set_draw_color(gray)
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_draw_color.pdf", tmp_path)
+
+
+def test_solid_arc_fill_color(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ pdf.set_fill_color(240)
+ for color in [[230, 30, 180], [30, 180, 30], [30, 30, 70]]:
+ pdf.set_draw_color(*color)
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ style="FD",
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_fill_color.pdf", tmp_path)
+
+
+def test_solid_arc_inclination(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ size_1 = size
+
+ for counter, inclination in enumerate([0, 30, 90, 120]):
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ # A workaround to avoid warning of pylint triggering duplicate code
+ # with test_arc.py
+ a=size_1,
+ b=size_1,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ if counter % 3 == 0:
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_inclination.pdf", tmp_path)
+
+
+def test_arc_clockwise(tmp_path):
+ pdf = fpdf.FPDF(unit="mm")
+ pdf.add_page()
+
+ for inclination in [0, 30, 90, 120]:
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ style=None,
+ )
+ pdf.set_x(pdf.get_x() + size + margin)
+ pdf.solid_arc(
+ x=pdf.get_x(),
+ y=pdf.get_y(),
+ a=size,
+ b=size,
+ start_angle=start_angle,
+ end_angle=end_angle,
+ inclination=inclination,
+ clockwise=True,
+ style=None,
+ )
+ next_row(pdf)
+
+ assert_pdf_equal(pdf, HERE / "class_solid_arc_clockwise.pdf", tmp_path)