Dolibarr-Modul: Produktbilder in ODT/PDF-Vorlagen über Hook-System einbetten
Find a file
Eduard Wisch a026d3f16e
All checks were successful
Deploy ProductImageTags / deploy (push) Successful in 9s
AVIF-Produktfotos im Angebot (0.1.2) [deploy]
Eddy: „es gibt immer mehr Bilder im Netz, die AVIF verwenden“. Ein AVIF im
Produktordner fehlte bisher im PDF: „.avif“ zählte nicht als Bild, ein AVIF
unter „.jpg“ (Bild-CDNs) scheiterte am JPEG-Loader und ging roh ins ODT.

- lib/avif.lib.php: Erkennung am Inhalt (ftyp avif/avis), Alpha-Erkennung,
  Umwandlung in JPG (ImageMagick, sonst GD) bzw. PNG mit Transparenz nur
  über GD (ImageMagick 6 auf Prod verliert den Alphakanal)
- listSourceImages: AVIF zählt als Kandidat in der Galerie-Reihenfolge
- getScaledCopy: AVIF über eine Zwischendatei im Cache, dann wie jedes
  andere Foto skaliert und als PNG gecacht; Zwischendatei wird gelöscht,
  das rohe AVIF kommt nie ins Dokument (auch nicht bei Langseite 0)
- veraltete „alphabetisch“-Kommentare an die Galerie-Reihenfolge angepasst

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:45:38 +02:00
.forgejo/workflows Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
admin Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
class AVIF-Produktfotos im Angebot (0.1.2) [deploy] 2026-10-19 21:45:38 +02:00
core AVIF-Produktfotos im Angebot (0.1.2) [deploy] 2026-10-19 21:45:38 +02:00
doc Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
langs Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
lib AVIF-Produktfotos im Angebot (0.1.2) [deploy] 2026-10-19 21:45:38 +02:00
.gitignore Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
about.html Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
CHANGELOG.md AVIF-Produktfotos im Angebot (0.1.2) [deploy] 2026-10-19 21:45:38 +02:00
COPYING Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
modulebuilder.txt Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
productimagetagsindex.php Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00
README.md AVIF-Produktfotos im Angebot (0.1.2) [deploy] 2026-10-19 21:45:38 +02:00
tags.txt Initiales Commit — ProductImageTags v0.1.0 [deploy] 2026-04-26 17:41:36 +02:00

ProductImageTags

Dolibarr-Modul, das Produktbilder in Angebots- und Auftrags-ODTs einbindet — damit der Kunde mit den Augen kauft.

Funktionen

  • Zeilen-Platzhalter {line_product_image_path} und {line_product_has_image} innerhalb [!-- BEGIN lines --]
  • Eigenes Detailseiten-Segment [!-- BEGIN product_details --] mit einem großen und bis zu 4 kleinen Bildern je Produkt, Beschreibung, Preisen, Maßen
  • On-the-fly Skalierung der Bilder auf konfigurierbare Maximalgröße, gecacht (Bildtausch invalidiert den Cache automatisch)
  • AVIF-Fotos (auch unter „.jpg" aus Bild-CDNs) werden am Inhalt erkannt und vor dem Skalieren in JPG bzw. — mit Transparenz — PNG umgewandelt (lib/avif.lib.php; transparente nur über GD mit AVIF, ImageMagick 6 verliert den Alphakanal)
  • Konfigurierbar über Admin-UI (Bildgrößen, Anzahl, Cache-Dauer, Skip-Empty)
  • Greift für Angebot (propal) und Auftrag (commande); Rechnung/Lieferschein technisch vorbereitet, kann später freigeschaltet werden

Installation

  1. Repo nach htdocs/custom/productimagetags/ kopieren oder symlinken
  2. Home → Setup → Module → ProductImageTags aktivieren
  3. Einstellungen unter Setup anpassen (Bildgrößen, Cache)
  4. ODT-Template anpassen (siehe doc/TEMPLATE_ANLEITUNG.md)

Verfügbare Platzhalter

Innerhalb [!-- BEGIN lines --]

Platzhalter Bedeutung
{line_product_image} Echtes Bild (draw:frame), wird pro Zeile automatisch eingefügt. Im Template nicht als Dummy-Bild setzen — als Text-Platzhalter lassen. Das Bild erscheint an der Stelle des Platzhalters in der Größe des Originals × PRODUCTIMAGETAGS_LINE_RATIO.
{line_product_image_path} Absoluter Dateisystem-Pfad zum skalierten Hauptbild (als Text, falls du den Pfad irgendwo brauchst)
{line_product_has_image} 1 wenn ein Bild existiert, sonst 0 (für IF-Blöcke)

Das Zeilen-Bild nutzt einen Marker+Post-Processing-Workaround, weil Dolibarrs odfphp-Library Segment-Bilder beim mergeSegment nicht sauber zum Odf-Handler propagiert. Wir ersetzen den Marker im content.xml per Reflection nach dem Core-Merge durch ein echtes <draw:frame> und registrieren das Bild direkt am Odf-Handler — funktioniert ohne Core-Patch.

Innerhalb [!-- BEGIN product_details --] (eigener Loop)

Platzhalter Bedeutung
{pd_position} Laufende Nummer auf der Detailseite
{pd_ref} Produkt-Referenz
{pd_label} Produkt-Bezeichnung
{pd_description} Beschreibung (HTML-getrimmt)
{pd_price_ht} / {pd_price_ttc} Preise formatiert
{pd_qty} Menge aus der Angebots-/Auftragszeile
{pd_weight} Gewicht + Einheit
{pd_dimensions} L × B × H mit Einheit
{pd_image_count} Anzahl der tatsächlich vorhandenen Bilder
{pd_image_large} Großes Hauptbild (Dummy-Frame im Template)
{pd_image_1} … {pd_image_4} Bis zu 4 kleine Bilder
{pd_has_image_1} … {pd_has_image_4} 1/0 Flags für IF-Blöcke

Konfiguration

  • PRODUCTIMAGETAGS_LINE_MAXPX — Langseite Zeilen-Bild (Default 300)
  • PRODUCTIMAGETAGS_LINE_RATIO — setImage-Ratio Zeilen-Bild (Default 1.0)
  • PRODUCTIMAGETAGS_DETAIL_COUNT — Max. Anzahl kleiner Detailbilder (Default 4)
  • PRODUCTIMAGETAGS_DETAIL_SMALL_MAXPX — Langseite kleine Bilder (Default 600)
  • PRODUCTIMAGETAGS_DETAIL_LARGE_MAXPX — Langseite großes Bild (Default 1200)
  • PRODUCTIMAGETAGS_DETAIL_SKIP_EMPTY — Produkte ohne Bilder im Loop überspringen (Default 1)
  • PRODUCTIMAGETAGS_CACHE_DAYS — Cache-Lebensdauer Tage (Default 30)

Bild-Auswahl

Das „Hauptbild" eines Produkts (Zeilen-Bild und großes Detailbild) wird genau in der Reihenfolge gewählt, die Dolibarr im Produktkärtchen anzeigt — nicht alphabetisch. Sortiert wird wie in Product::show_photos():

  1. Cover (falls im ECM gesetzt — im Produkt-UI normalerweise nicht setzbar, daher meist ohne Wirkung)
  2. Position aus llx_ecm_files (die per Drag&Drop festgelegte Galerie-Reihenfolge)
  3. alphabetisch als Fallback (nicht indexierte Dateien landen am Ende)

So steuerst du, welches Bild im Angebot erscheint: Produkt öffnen → Reiter „Dokumente" → das gewünschte Bild per Hoch-/Runter-Pfeil bzw. Drag&Drop an Position 1 ziehen. Danach ggf. im Modul-Setup den Cache leeren, damit nicht eine ältere skalierte Kopie greift.

Quelle der Reihenfolge ist dol_dir_list_in_database() auf llx_ecm_files (position, cover) in class/productimage.class.php::listSourceImages. Vor v0.1.1 wurde rein alphabetisch nach Dateiname sortiert — dadurch landete ein willkürliches Bild im PDF.

Bekannte Limitationen

  • PDF-Skalierung: LibreOffice kann bei ODT→PDF-Konvertierung dünne Bildkanten wegglätten. Wir skalieren Originale, sodass das normalerweise kein Problem ist.
  • Anker des Zeilen-Bildes: aktuell fest as-char (wird als Zeichen in den Text eingebettet). Damit fließt das Bild mit der Zellhöhe mit. Für andere Anker-Typen wäre ein Template-eigener Dummy-Frame nötig — kommt bei Bedarf nach.

Lizenz

GPL v3+ (siehe COPYING)