AVIF-Produktfotos im Angebot (0.1.2) [deploy]
All checks were successful
Deploy ProductImageTags / deploy (push) Successful in 9s
All checks were successful
Deploy ProductImageTags / deploy (push) Successful in 9s
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>
This commit is contained in:
parent
6c1d922994
commit
a026d3f16e
5 changed files with 253 additions and 64 deletions
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -1,5 +1,24 @@
|
|||
# Changelog — ProductImageTags
|
||||
|
||||
## 0.1.2 (2026-10-19)
|
||||
|
||||
### Behoben
|
||||
- **AVIF-Produktfotos fehlten im Angebot.** Anlass (Eddy): „es gibt immer mehr Bilder im
|
||||
Netz, die AVIF verwenden". Dolibarr legt ein hochgeladenes AVIF unverändert in den
|
||||
Produktordner. Bisher zählte `.avif` in `listSourceImages` nicht als Bild (Dolibarrs
|
||||
`image_format_supported()` kennt die Endung nicht), und ein AVIF unter `.jpg` (so liefern
|
||||
es Bild-CDNs aus) scheiterte in `getScaledCopy` am JPEG-Loader und ging roh ins ODT.
|
||||
- Jetzt wird AVIF **am Inhalt** erkannt (`ftyp`-Marke `avif`/`avis`, neue `lib/avif.lib.php`),
|
||||
zählt als Kandidat in der Galerie-Reihenfolge und wird vor dem Skalieren in eine
|
||||
Zwischendatei im Cache umgewandelt: deckend → JPG (ImageMagick, sonst GD), mit Transparenz →
|
||||
PNG nur über GD (ImageMagick 6 auf Prod verliert den Alphakanal, der Hintergrund würde
|
||||
schwarz). Danach läuft es wie jedes andere Foto (skaliert, auf die Hintergrundfarbe
|
||||
geflattet, als PNG in den Cache), die Zwischendatei wird gelöscht. Ein AVIF geht auch bei
|
||||
Langseite 0 („Original") nie roh ins Dokument.
|
||||
- Transparente AVIF werden auf Prod per GD zu PNG (GD mit AVIF im Prod-Image seit
|
||||
`dolibarr-image` Commit 0cd9d18). Wo GD kein AVIF kann, bleibt ein transparentes AVIF
|
||||
weg (Eintrag im Dolibarr-Log) statt mit schwarzem Hintergrund im PDF zu landen.
|
||||
|
||||
## 0.1.1 (2026-06-18)
|
||||
|
||||
### Behoben
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Dolibarr-Modul, das **Produktbilder in Angebots- und Auftrags-ODTs** einbindet
|
|||
- **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
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
|||
require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||
require_once __DIR__.'/../lib/avif.lib.php';
|
||||
|
||||
/**
|
||||
* Bild-Helper für Produkte. Liefert skalierte, gecachte Kopien der
|
||||
* Produkt-Fotos (alphabetisch sortiert), damit ODT-Dokumente klein bleiben.
|
||||
* Produkt-Fotos (in Dolibarrs Galerie-Reihenfolge), damit ODT-Dokumente klein bleiben.
|
||||
* AVIF-Fotos werden dabei in JPG/PNG umgewandelt (lib/avif.lib.php).
|
||||
*/
|
||||
class ProductImage
|
||||
{
|
||||
|
|
@ -72,7 +74,7 @@ class ProductImage
|
|||
}
|
||||
|
||||
/**
|
||||
* Liefert das erste (alphabetisch) Produktbild skaliert.
|
||||
* Liefert das erste Produktbild (Galerie-Reihenfolge) skaliert.
|
||||
*
|
||||
* @param Product $product Produkt
|
||||
* @param int $targetPx Langseite des Zielbildes in Pixel
|
||||
|
|
@ -122,7 +124,7 @@ class ProductImage
|
|||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Listet alle Originalbilder eines Produkts, alphabetisch sortiert.
|
||||
* Listet alle Originalbilder eines Produkts (inkl. AVIF) in Dolibarrs Galerie-Reihenfolge.
|
||||
*
|
||||
* @param Product $product Produkt
|
||||
* @return string[] Absolute Pfade zu den Originalen
|
||||
|
|
@ -194,7 +196,9 @@ class ProductImage
|
|||
$indexed = array();
|
||||
foreach ($files as $file) {
|
||||
$fullPath = $file['fullname'];
|
||||
if (image_format_supported($fullPath) <= 0) {
|
||||
// AVIF zählt mit, obwohl Dolibarrs image_format_supported() die Endung „.avif" nicht kennt —
|
||||
// am Inhalt erkannt, damit auch AVIF unter fremder Endung greift. Umgewandelt wird in getScaledCopy().
|
||||
if (image_format_supported($fullPath) <= 0 && !productimagetags_bild_ist_avif($fullPath)) {
|
||||
continue;
|
||||
}
|
||||
$name = $file['name'];
|
||||
|
|
@ -238,13 +242,21 @@ class ProductImage
|
|||
if (!file_exists($srcPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// AVIF am INHALT erkennen, nicht an der Endung: Bild-CDNs liefern AVIF auch als „.jpg" aus, dann
|
||||
// scheiterte unten der JPEG-Loader und das Original ging roh ins ODT. AVIF läuft deshalb immer über
|
||||
// den Cache (auch ohne Skalierung), das Original kommt nie ins Dokument.
|
||||
$isAvif = productimagetags_bild_ist_avif($srcPath);
|
||||
// Wenn AVIF nicht umwandelbar: lieber kein Bild als das rohe AVIF
|
||||
$ohneCache = $isAvif ? null : $srcPath;
|
||||
|
||||
// Kein Resize wenn Ziel <= 0 (dann Original)
|
||||
if ($targetPx <= 0) {
|
||||
if ($targetPx <= 0 && !$isAvif) {
|
||||
return $srcPath;
|
||||
}
|
||||
|
||||
$srcExt = strtolower(pathinfo($srcPath, PATHINFO_EXTENSION));
|
||||
if (!in_array($srcExt, array('jpg', 'jpeg', 'png', 'gif', 'webp'))) {
|
||||
$srcExt = $isAvif ? 'avif' : strtolower(pathinfo($srcPath, PATHINFO_EXTENSION));
|
||||
if (!$isAvif && !in_array($srcExt, array('jpg', 'jpeg', 'png', 'gif', 'webp'))) {
|
||||
return $srcPath;
|
||||
}
|
||||
|
||||
|
|
@ -261,69 +273,91 @@ class ProductImage
|
|||
return $cacheFile;
|
||||
}
|
||||
|
||||
$size = @getimagesize($srcPath);
|
||||
if ($size === false) {
|
||||
return $srcPath;
|
||||
}
|
||||
list($w, $h) = $size;
|
||||
|
||||
// In GD laden (Quelle kann jpeg/png/gif/webp sein)
|
||||
$img = null;
|
||||
switch ($srcExt) {
|
||||
case 'jpg': case 'jpeg': $img = @imagecreatefromjpeg($srcPath); break;
|
||||
case 'png': $img = @imagecreatefrompng($srcPath); break;
|
||||
case 'gif': $img = @imagecreatefromgif($srcPath); break;
|
||||
case 'webp': $img = function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($srcPath) : null; break;
|
||||
}
|
||||
if (!$img) {
|
||||
// Fallback: 1:1-Kopie mit PNG-Endung — könnte ein WebP mit PNG-Header werden,
|
||||
// also lieber Quelle zurück
|
||||
return $srcPath;
|
||||
// AVIF zuerst in eine Zwischendatei im Cache wandeln (JPG, mit Transparenz PNG), danach wie jedes
|
||||
// andere Foto weiter. Die Zwischendatei wird nach dem Skalieren wieder gelöscht (finally unten) —
|
||||
// im Cache bleibt nur das fertige PNG, dessen Schlüssel wie bisher an Quelle+mtime+Größe hängt.
|
||||
$loadPath = $srcPath;
|
||||
$zwischen = '';
|
||||
if ($isAvif) {
|
||||
// PID im Namen: parallele PDF-Erzeugungen kommen sich nicht in die Quere
|
||||
$zwischen = productimagetags_avif_in_datei($srcPath, $this->cacheDir.'/prod'.((int) $product->id).'_'.$hash.'_avif'.getmypid());
|
||||
if ($zwischen === '') {
|
||||
dol_syslog('ProductImageTags: AVIF ließ sich nicht umwandeln (weder ImageMagick noch GD mit AVIF): '.$srcPath, LOG_WARNING);
|
||||
return null;
|
||||
}
|
||||
$loadPath = $zwischen;
|
||||
$srcExt = strtolower(pathinfo($zwischen, PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
// Zielgröße
|
||||
$longSide = max($w, $h);
|
||||
if ($longSide <= $targetPx) {
|
||||
$newW = $w; $newH = $h;
|
||||
} elseif ($w >= $h) {
|
||||
$newW = $targetPx;
|
||||
$newH = max(1, (int) round($h * ($targetPx / $w)));
|
||||
} else {
|
||||
$newH = $targetPx;
|
||||
$newW = max(1, (int) round($w * ($targetPx / $h)));
|
||||
}
|
||||
try {
|
||||
$size = @getimagesize($loadPath);
|
||||
if ($size === false) {
|
||||
return $ohneCache;
|
||||
}
|
||||
list($w, $h) = $size;
|
||||
|
||||
// Hintergrundfarbe (weiß default) — vereinheitlicht das Bild
|
||||
$bgHex = getDolGlobalString('PRODUCTIMAGETAGS_IMAGE_BG_COLOR', '#ffffff');
|
||||
list($bgR, $bgG, $bgB) = $this->hexToRgb($bgHex);
|
||||
// In GD laden (Quelle kann jpeg/png/gif/webp sein, AVIF ist hier schon jpg/png)
|
||||
$img = null;
|
||||
switch ($srcExt) {
|
||||
case 'jpg': case 'jpeg': $img = @imagecreatefromjpeg($loadPath); break;
|
||||
case 'png': $img = @imagecreatefrompng($loadPath); break;
|
||||
case 'gif': $img = @imagecreatefromgif($loadPath); break;
|
||||
case 'webp': $img = function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($loadPath) : null; break;
|
||||
}
|
||||
if (!$img) {
|
||||
// Fallback: 1:1-Kopie mit PNG-Endung — könnte ein WebP mit PNG-Header werden,
|
||||
// also lieber Quelle zurück
|
||||
return $ohneCache;
|
||||
}
|
||||
|
||||
$dst = imagecreatetruecolor($newW, $newH);
|
||||
// Hintergrund mit konfigurierter Farbe fluten (opak, keine Transparenz nötig)
|
||||
$bg = imagecolorallocate($dst, $bgR, $bgG, $bgB);
|
||||
imagefilledrectangle($dst, 0, 0, $newW - 1, $newH - 1, $bg);
|
||||
// Transparenz des Originals per alpha-blending auf den opaken Hintergrund legen
|
||||
imagealphablending($dst, true);
|
||||
imagecopyresampled($dst, $img, 0, 0, 0, 0, $newW, $newH, $w, $h);
|
||||
// Zielgröße (Ziel <= 0 kommt nur bei AVIF hier an: Originalgröße, nur umgewandelt)
|
||||
$longSide = max($w, $h);
|
||||
if ($targetPx <= 0 || $longSide <= $targetPx) {
|
||||
$newW = $w; $newH = $h;
|
||||
} elseif ($w >= $h) {
|
||||
$newW = $targetPx;
|
||||
$newH = max(1, (int) round($h * ($targetPx / $w)));
|
||||
} else {
|
||||
$newH = $targetPx;
|
||||
$newW = max(1, (int) round($w * ($targetPx / $h)));
|
||||
}
|
||||
|
||||
// Rahmen (falls konfiguriert)
|
||||
$borderW = (int) getDolGlobalString('PRODUCTIMAGETAGS_IMAGE_BORDER_WIDTH', 1);
|
||||
if ($borderW > 0) {
|
||||
$borderHex = getDolGlobalString('PRODUCTIMAGETAGS_IMAGE_BORDER_COLOR', '#cccccc');
|
||||
list($brR, $brG, $brB) = $this->hexToRgb($borderHex);
|
||||
$border = imagecolorallocate($dst, $brR, $brG, $brB);
|
||||
for ($i = 0; $i < $borderW; $i++) {
|
||||
imagerectangle($dst, $i, $i, $newW - 1 - $i, $newH - 1 - $i, $border);
|
||||
// Hintergrundfarbe (weiß default) — vereinheitlicht das Bild
|
||||
$bgHex = getDolGlobalString('PRODUCTIMAGETAGS_IMAGE_BG_COLOR', '#ffffff');
|
||||
list($bgR, $bgG, $bgB) = $this->hexToRgb($bgHex);
|
||||
|
||||
$dst = imagecreatetruecolor($newW, $newH);
|
||||
// Hintergrund mit konfigurierter Farbe fluten (opak, keine Transparenz nötig)
|
||||
$bg = imagecolorallocate($dst, $bgR, $bgG, $bgB);
|
||||
imagefilledrectangle($dst, 0, 0, $newW - 1, $newH - 1, $bg);
|
||||
// Transparenz des Originals per alpha-blending auf den opaken Hintergrund legen
|
||||
imagealphablending($dst, true);
|
||||
imagecopyresampled($dst, $img, 0, 0, 0, 0, $newW, $newH, $w, $h);
|
||||
|
||||
// Rahmen (falls konfiguriert)
|
||||
$borderW = (int) getDolGlobalString('PRODUCTIMAGETAGS_IMAGE_BORDER_WIDTH', 1);
|
||||
if ($borderW > 0) {
|
||||
$borderHex = getDolGlobalString('PRODUCTIMAGETAGS_IMAGE_BORDER_COLOR', '#cccccc');
|
||||
list($brR, $brG, $brB) = $this->hexToRgb($borderHex);
|
||||
$border = imagecolorallocate($dst, $brR, $brG, $brB);
|
||||
for ($i = 0; $i < $borderW; $i++) {
|
||||
imagerectangle($dst, $i, $i, $newW - 1 - $i, $newH - 1 - $i, $border);
|
||||
}
|
||||
}
|
||||
|
||||
$ok = @imagepng($dst, $cacheFile, 6);
|
||||
imagedestroy($dst);
|
||||
imagedestroy($img);
|
||||
|
||||
if (!$ok) {
|
||||
return $ohneCache;
|
||||
}
|
||||
return $cacheFile;
|
||||
} finally {
|
||||
if ($zwischen !== '') {
|
||||
@unlink($zwischen);
|
||||
}
|
||||
}
|
||||
|
||||
$ok = @imagepng($dst, $cacheFile, 6);
|
||||
imagedestroy($dst);
|
||||
imagedestroy($img);
|
||||
|
||||
if (!$ok) {
|
||||
return $srcPath;
|
||||
}
|
||||
return $cacheFile;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class modProductImageTags extends DolibarrModules
|
|||
$this->editor_url = 'https://git.data-it-solution.de/data-it/productimagetags';
|
||||
$this->editor_squarred_logo = '';
|
||||
|
||||
$this->version = '0.1.1';
|
||||
$this->version = '0.1.2';
|
||||
|
||||
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
|
||||
|
||||
|
|
|
|||
135
lib/avif.lib.php
Normal file
135
lib/avif.lib.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file lib/avif.lib.php
|
||||
* \ingroup productimagetags
|
||||
* \brief AVIF-Produktfotos erkennen und in JPG/PNG umwandeln.
|
||||
*
|
||||
* Immer mehr Bilder aus dem Netz sind AVIF — Bild-CDNs liefern sie auch unter „.jpg" aus. Dolibarr legt sie
|
||||
* beim Hochladen unverändert in den Produktordner. Ohne Umwandlung fehlte ein AVIF-Foto im Angebots-/Auftrags-
|
||||
* PDF: „.avif" zählt für Dolibarrs image_format_supported() nicht als Bild, und ein AVIF unter „.jpg" scheitert
|
||||
* am JPEG-Loader von GD. Das Modul lädt nichts hoch — hier steht deshalb nur der lesende Teil: Erkennen am
|
||||
* Inhalt, Alpha-Erkennung, Umwandlung in eine Zwischendatei, die productimage.class.php dann wie jedes andere
|
||||
* Foto skaliert und als PNG in den Cache legt.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ist die Datei ein AVIF? Am INHALT erkannt (ISO-BMFF `ftyp` mit Marke avif/avis), nicht an der Endung —
|
||||
* Bild-CDNs liefern AVIF auch unter „.jpg" aus.
|
||||
*
|
||||
* @param string $pfad Absoluter Pfad
|
||||
* @return bool
|
||||
*/
|
||||
function productimagetags_bild_ist_avif($pfad)
|
||||
{
|
||||
$kopf = @file_get_contents($pfad, false, null, 0, 64);
|
||||
if (!is_string($kopf) || strlen($kopf) < 16 || substr($kopf, 4, 4) !== 'ftyp') {
|
||||
return false;
|
||||
}
|
||||
$ende = min(strlen($kopf), max(16, unpack('N', substr($kopf, 0, 4))[1]));
|
||||
$marken = array(substr($kopf, 8, 4));
|
||||
for ($i = 16; $i + 4 <= $ende; $i += 4) {
|
||||
$marken[] = substr($kopf, $i, 4);
|
||||
}
|
||||
return count(array_intersect($marken, array('avif', 'avis'))) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trägt das AVIF einen Alphakanal? Steht als Hilfsbild „auxiliary:alpha" im `meta`-Kasten; nur der wird gelesen.
|
||||
*
|
||||
* @param string $pfad Absoluter Pfad
|
||||
* @return bool
|
||||
*/
|
||||
function productimagetags_avif_hat_alpha($pfad)
|
||||
{
|
||||
$fh = @fopen($pfad, 'rb');
|
||||
if (!$fh) {
|
||||
return false;
|
||||
}
|
||||
$alpha = false;
|
||||
while (true) {
|
||||
$kopf = fread($fh, 8);
|
||||
if (!is_string($kopf) || strlen($kopf) < 8) {
|
||||
break;
|
||||
}
|
||||
$groesse = unpack('N', substr($kopf, 0, 4))[1];
|
||||
$typ = substr($kopf, 4, 4);
|
||||
$kopfLaenge = 8;
|
||||
if ($groesse === 1) {
|
||||
$lang = fread($fh, 8);
|
||||
if (!is_string($lang) || strlen($lang) < 8) {
|
||||
break;
|
||||
}
|
||||
$teile = unpack('N2', $lang);
|
||||
$groesse = $teile[1] * 4294967296 + $teile[2];
|
||||
$kopfLaenge = 16;
|
||||
}
|
||||
if ($typ === 'meta') {
|
||||
$menge = ($groesse === 0) ? 1048576 : (int) min($groesse - $kopfLaenge, 1048576);
|
||||
$inhalt = $menge > 0 ? (string) fread($fh, $menge) : '';
|
||||
$alpha = strpos($inhalt, 'auxiliary:alpha') !== false || strpos($inhalt, 'urn:mpeg:hevc:2015:auxid:1') !== false;
|
||||
break;
|
||||
}
|
||||
if ($groesse === 0 || $groesse < $kopfLaenge || fseek($fh, $groesse - $kopfLaenge, SEEK_CUR) !== 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose($fh);
|
||||
return $alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* AVIF in JPEG (ohne Transparenz) bzw. PNG (mit Transparenz) umwandeln — Ziel frei wählbar.
|
||||
*
|
||||
* ⚠ ImageMagick 6 (Prod) liest AVIF ohne Alphakanal → transparent wird schwarz. Deshalb: ohne Alpha
|
||||
* ImageMagick zuerst (wendet Drehung aus irot/imir an), sonst GD; mit Alpha NUR GD.
|
||||
* Shell-Quoting byte-sicher (escapeshellarg() wirft unter LANG=C Umlaute aus Pfaden, KB #951).
|
||||
*
|
||||
* @param string $quelle AVIF-Datei
|
||||
* @param string $ziel Zieldatei ohne Endung — die Endung (.jpg/.png) hängt die Funktion an
|
||||
* @return string Pfad der erzeugten Datei oder '' (nicht umwandelbar)
|
||||
*/
|
||||
function productimagetags_avif_in_datei($quelle, $ziel)
|
||||
{
|
||||
$alpha = productimagetags_avif_hat_alpha($quelle);
|
||||
$ziel .= $alpha ? '.png' : '.jpg';
|
||||
$q = function ($w) {
|
||||
return "'".str_replace("'", "'\\''", str_replace("\0", '', (string) $w))."'";
|
||||
};
|
||||
if (!$alpha && function_exists('exec')) {
|
||||
$aus = array();
|
||||
$code = 1;
|
||||
@exec('command -v convert 2>/dev/null', $aus, $code);
|
||||
if ($code === 0 && !empty($aus)) {
|
||||
@exec('convert '.$q($quelle.'[0]').' -auto-orient -quality 90 '.$q($ziel).' 2>/dev/null');
|
||||
if (is_file($ziel) && filesize($ziel) > 0) {
|
||||
return $ziel;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (function_exists('imagecreatefromavif')) {
|
||||
$bild = @imagecreatefromavif($quelle);
|
||||
if ($bild) {
|
||||
if ($alpha) {
|
||||
imagealphablending($bild, false);
|
||||
imagesavealpha($bild, true);
|
||||
$ok = imagepng($bild, $ziel, 6);
|
||||
} else {
|
||||
$ok = imagejpeg($bild, $ziel, 90);
|
||||
}
|
||||
imagedestroy($bild);
|
||||
if ($ok && is_file($ziel) && filesize($ziel) > 0) {
|
||||
return $ziel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@unlink($ziel);
|
||||
return '';
|
||||
}
|
||||
Loading…
Reference in a new issue