dolibarr 24.0.0-beta
images.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2007 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * or see https://www.gnu.org/
20 */
21
27// Define size of logo small and mini
28// TODO Remove this and call getDefaultImageSizes() instead
29$maxwidthsmall = 480;
30$maxheightsmall = 270; // Near 16/9eme
31$maxwidthmini = 128;
32$maxheightmini = 72; // 16/9eme
33$quality = 80;
34
35if (!defined('IMAGETYPE_WEBP')) {
36 define('IMAGETYPE_WEBP', 18);
37}
38
39
46{
47 $maxwidthsmall = 480;
48 $maxheightsmall = 270; // Near 16/9eme
49 $maxwidthmini = 128;
50 $maxheightmini = 72; // 16/9eme
51 $quality = 80;
52
53 return array(
54 'maxwidthsmall' => $maxwidthsmall,
55 'maxheightsmall' => $maxheightsmall,
56 'maxwidthmini' => $maxwidthmini,
57 'maxheightmini' => $maxheightmini,
58 'quality' => $quality
59 );
60}
61
68function getListOfPossibleImageExt($acceptsvg = 0)
69{
70 $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm|\.avif'; // See also into product.class.php
71 if ($acceptsvg || getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
72 $regeximgext .= '|\.svg'; // Not allowed by default. SVG can contains javascript
73 }
74
75 return $regeximgext;
76}
77
85function image_format_supported($file, $acceptsvg = 0)
86{
87 $regeximgext = getListOfPossibleImageExt();
88
89 // Case filename is not a format image
90 $reg = array();
91 if (!preg_match('/('.$regeximgext.')$/i', $file, $reg)) {
92 return -1;
93 }
94
95 // Case filename is a format image but not supported by this PHP
96 $imgfonction = '';
97 if (strtolower($reg[1]) == '.gif') {
98 $imgfonction = 'imagecreatefromgif';
99 }
100 if (strtolower($reg[1]) == '.jpg') {
101 $imgfonction = 'imagecreatefromjpeg';
102 }
103 if (strtolower($reg[1]) == '.jpeg') {
104 $imgfonction = 'imagecreatefromjpeg';
105 }
106 if (strtolower($reg[1]) == '.png') {
107 $imgfonction = 'imagecreatefrompng';
108 }
109 if (strtolower($reg[1]) == '.bmp') {
110 $imgfonction = 'imagecreatefromwbmp';
111 }
112 if (strtolower($reg[1]) == '.webp') {
113 $imgfonction = 'imagecreatefromwebp';
114 }
115 if (strtolower($reg[1]) == '.xpm') {
116 $imgfonction = 'imagecreatefromxpm';
117 }
118 if (strtolower($reg[1]) == '.xbm') {
119 $imgfonction = 'imagecreatefromxbm';
120 }
121 if (strtolower($reg[1]) == '.svg') {
122 $imgfonction = 'imagecreatefromsvg'; // Never available
123 }
124 if (strtolower($reg[1]) == '.avif') {
125 $imgfonction = 'imagecreatefromavif'; // PHP >= 8.1
126 }
127 if ($imgfonction) {
128 if (!function_exists($imgfonction)) {
129 // Functions of conversion not available in this PHP
130 return 0;
131 }
132
133 // Filename is a format image and supported for conversion by this PHP
134 return 1;
135 }
136
137 return 0;
138}
139
140
148function dol_getImageSize($file, $url = false)
149{
150 $ret = array();
151
152 if (image_format_supported($file) < 0) {
153 return $ret;
154 }
155
156 $filetoread = $file;
157 if (!$url) {
158 $filetoread = realpath(dol_osencode($file)); // Chemin canonique absolu de l'image
159 }
160
161 if ($filetoread) {
162 $infoImg = getimagesize($filetoread); // Recuperation des infos de l'image
163 if ($infoImg) {
164 $ret['width'] = $infoImg[0]; // Largeur de l'image
165 $ret['height'] = $infoImg[1]; // Hauteur de l'image
166 } else {
167 $ret['width'] = $ret['height'] = '';
168 }
169 }
170
171 return $ret;
172}
173
174
189function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x = 0, $src_y = 0, $filetowrite = '', $newquality = 0)
190{
191 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
192
193 global $langs;
194
195 dol_syslog("dol_imageResizeOrCrop file=".$file." mode=".$mode." newWidth=".$newWidth." newHeight=".$newHeight." src_x=".$src_x." src_y=".$src_y);
196
197 // Clean parameters
198 $file = trim($file);
199
200 // Check parameters
201 if (!$file) {
202 // Si le fichier n'a pas ete indique
203 return 'Bad parameter file';
204 } elseif (!file_exists($file)) {
205 // Si le fichier passe en parameter n'existe pas
206 return $langs->trans("ErrorFileNotFound", $file);
207 } elseif (image_format_supported($file) < 0) {
208 return 'This filename '.$file.' does not seem to be an image filename.';
209 } elseif (!is_numeric($newWidth) && !is_numeric($newHeight)) {
210 return 'Wrong value for parameter newWidth or newHeight';
211 } elseif ($mode == 0 && $newWidth <= 0 && $newHeight <= 0 && (empty($filetowrite) || $filetowrite == $file)) {
212 return 'At least newHeight or newWidth must be defined for resizing, or a target filename must be set to convert';
213 } elseif ($mode == 1 && ($newWidth <= 0 || $newHeight <= 0)) {
214 return 'Both newHeight or newWidth must be defined for croping';
215 }
216
217 $filetoread = realpath(dol_osencode($file)); // Chemin canonique absolu de l'image
218
219 // Get data about src image
220 // Index 0 and 1 contains respectively the width and the height of the image.
221 // Index 2 is one of the IMAGETYPE_* constants indicating the type of the image.
222 // Index 3 is a text string with the correct height="yyy" width="xxx" string that can be used directly in an IMG tag.
223 $infoImg = getimagesize($filetoread);
224 $imgWidth = $infoImg[0]; // Width of picture
225 $imgHeight = $infoImg[1]; // Height of picture
226
227 $imgTargetName = ($filetowrite ? $filetowrite : $file);
228 $newExt = strtolower(pathinfo($imgTargetName, PATHINFO_EXTENSION));
229
230 if ($mode == 0) { // If resize, we check parameters
231 if (!empty($filetowrite) && $filetowrite != $file && $newWidth <= 0 && $newHeight <= 0) {
232 $newWidth = $imgWidth;
233 $newHeight = $imgHeight;
234 }
235
236 if ($newWidth <= 0) {
237 $newWidth = intval(($newHeight / $imgHeight) * $imgWidth); // Keep ratio
238 }
239 if ($newHeight <= 0) {
240 $newHeight = intval(($newWidth / $imgWidth) * $imgHeight); // Keep ratio
241 }
242 }
243
244 // Test function to read source image exists
245 // The constants below are defined by this extension, and will only be available when the extension has either been compiled into PHP or dynamically loaded at runtime.
246 // They may not exists if gd extension isn't installed
247 // IMG_* and IMAGETYPE_* are different
248 // example IMG_WEBP = 32, IMAGETYPE_WEBP = 18
249 $imgfonction = '';
250 switch ($infoImg[2]) {
251 case 1: // IMAGETYPE_GIF
252 $imgfonction = 'imagecreatefromgif';
253 break;
254 case 2: // IMAGETYPE_JPG
255 $imgfonction = 'imagecreatefromjpeg';
256 break;
257 case 3: // IMAGETYPE_PNG
258 $imgfonction = 'imagecreatefrompng';
259 break;
260 case 15: // IMAGETYPE_WBMP
261 $imgfonction = 'imagecreatefromwbmp';
262 break;
263 case 18: // IMAGETYPE_WEBP
264 $imgfonction = 'imagecreatefromwebp';
265 break;
266 case 19: // IMAGETYPE_AVIF
267 $imgfonction = 'imagecreatefromavif';
268 break;
269 }
270 if ($imgfonction) {
271 if (!function_exists($imgfonction)) {
272 // Conversion functions not present in this PHP
273 return 'Read of image not possible. This PHP does not support GD functions '.$imgfonction;
274 }
275 }
276
277 // Test function to write target image exists
278 if ($filetowrite) {
279 $imgfonction = '';
280 switch ($newExt) {
281 case 'gif': // IMG_GIF
282 $imgfonction = 'imagecreatefromgif';
283 break;
284 case 'jpg': // IMG_JPG
285 case 'jpeg': // IMG_JPEG
286 $imgfonction = 'imagecreatefromjpeg';
287 break;
288 case 'png': // IMG_PNG
289 $imgfonction = 'imagecreatefrompng';
290 break;
291 case 'bmp': // IMG_WBMP
292 $imgfonction = 'imagecreatefromwbmp';
293 break;
294 case 'webp': // IMG_WEBP
295 $imgfonction = 'imagecreatefromwebp';
296 break;
297 case 'avif': // IMG_AVIF
298 $imgfonction = 'imagecreatefromavif';
299 break;
300 }
301 if ($imgfonction) {
302 if (!function_exists($imgfonction)) {
303 // Conversion functions not present in this PHP
304 return 'Write of image not possible. This PHP does not support GD functions '.$imgfonction;
305 }
306 }
307 }
308
309 // Read source image file
310 $img = null;
311 $extImg = null;
312 switch ($infoImg[2]) {
313 case 1: // Gif
314 $img = imagecreatefromgif($filetoread);
315 $extImg = '.gif'; // File name extension of image
316 break;
317 case 2: // Jpg
318 $img = imagecreatefromjpeg($filetoread);
319 $extImg = '.jpg';
320 break;
321 case 3: // Png
322 $img = imagecreatefrompng($filetoread);
323 $extImg = '.png';
324 break;
325 case 15: // Bmp
326 $img = imagecreatefromwbmp($filetoread);
327 $extImg = '.bmp';
328 break;
329 case 18: // Webp
330 $img = imagecreatefromwebp($filetoread);
331 $extImg = '.webp';
332 break;
333 }
334
335 if ($img === null) {
336 return "Error: Could not create Image from '$filetoread'";
337 }
338
339 // Create empty image for target
340 if ($newExt == 'gif') {
341 // Compatibility image GIF
342 $imgTarget = imagecreate($newWidth, $newHeight);
343 } else {
344 $imgTarget = imagecreatetruecolor($newWidth, $newHeight);
345 }
346
347 // Activate antialiasing for better quality
348 if (function_exists('imageantialias')) {
349 imageantialias($imgTarget, true);
350 }
351
352 // This is to keep transparent alpha channel if exists (PHP >= 4.2)
353 if (function_exists('imagesavealpha')) {
354 imagesavealpha($imgTarget, true);
355 }
356
357 // Set transparent color according to image extension
358 $trans_colour = -1; // By default, undefined
359 switch ($newExt) {
360 case 'gif': // Gif
361 $trans_colour = imagecolorallocate($imgTarget, 255, 255, 255); // The method is different for the GIF format
362 imagecolortransparent($imgTarget, $trans_colour);
363 break;
364 case 'jpg': // Jpg
365 case 'jpeg': // Jpeg
366 $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 0);
367 break;
368 case 'png': // Png
369 imagealphablending($imgTarget, false); // For compatibility with certain systems
370 $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 127); // Keep transparent channel
371 break;
372 case 'bmp': // Bmp
373 $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 0);
374 break;
375 case 'webp': // Webp
376 $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 127);
377 break;
378 }
379 if (function_exists("imagefill") && $trans_colour > 0) {
380 imagefill($imgTarget, 0, 0, $trans_colour);
381 }
382
383 dol_syslog("dol_imageResizeOrCrop: convert image from ($imgWidth x $imgHeight) at position ($src_x x $src_y) to ($newWidth x $newHeight) as a $extImg");
384 //imagecopyresized($imgTarget, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insere l'image de base redimensionnee
385 imagecopyresampled($imgTarget, $img, 0, 0, $src_x, $src_y, $newWidth, $newHeight, ($mode == 0 ? $imgWidth : $newWidth), ($mode == 0 ? $imgHeight : $newHeight)); // Insere l'image de base redimensionnee
386
387 // Check if permission are ok
388 //$fp = fopen($imgTargetName, "w");
389 //fclose($fp);
390
391 // Create image on disk (overwrite file if exists)
392 switch ($newExt) {
393 case 'gif': // Gif
394 $newquality = 'NU'; // Quality is not used for this format
395 imagegif($imgTarget, $imgTargetName);
396 break;
397 case 'jpg': // Jpg
398 case 'jpeg': // Jpeg
399 $newquality = ($newquality ? $newquality : '100'); // % quality maximum
400 imagejpeg($imgTarget, $imgTargetName, $newquality);
401 break;
402 case 'png': // Png
403 $newquality = 0; // No compression (0-9)
404 imagepng($imgTarget, $imgTargetName, $newquality);
405 break;
406 case 'bmp': // Bmp
407 $newquality = 'NU'; // Quality is not used for this format
408 imagewbmp($imgTarget, $imgTargetName);
409 break;
410 case 'webp': // Webp
411 $newquality = ($newquality ? $newquality : '100'); // % quality maximum
412 imagewebp($imgTarget, $imgTargetName, $newquality);
413 break;
414 default:
415 dol_syslog("images.lib.php::imageResizeOrCrop() Format ".$newExt." is not supported", LOG_WARNING);
416 }
417
418 // Set permissions on file
419 dolChmod($imgTargetName);
420
421 // Free memory. This does not delete image.
422 if ($img) {
423 imagedestroy($img);
424 }
425 if ($imgTarget) {
426 imagedestroy($imgTarget);
427 }
428
429 clearstatcache(); // File was replaced by a modified one, so we clear file caches.
430
431 return $imgTargetName;
432}
433
434
443function dolRotateImage($file_path)
444{
445 return correctExifImageOrientation($file_path, $file_path);
446}
447
448
457function correctExifImageOrientation($fileSource, $fileDest, $quality = 95)
458{
459 if (function_exists('exif_read_data')) {
460 $exif = @exif_read_data($fileSource);
461 if ($exif && isset($exif['Orientation'])) {
462 $infoImg = getimagesize($fileSource); // Get image infos
463
464 $orientation = $exif['Orientation'];
465 if ($orientation != 1) {
466 $img = imagecreatefromjpeg($fileSource);
467 $deg = 0;
468 switch ($orientation) {
469 case 3:
470 $deg = 180;
471 break;
472 case 6:
473 $deg = 270;
474 break;
475 case 8:
476 $deg = 90;
477 break;
478 }
479 if ($deg) {
480 if ($infoImg[2] === IMAGETYPE_PNG) { // In fact there is no exif on PNG but just in case
481 imagealphablending($img, false);
482 imagesavealpha($img, true);
483 $img = imagerotate($img, $deg, imagecolorallocatealpha($img, 0, 0, 0, 127));
484 imagealphablending($img, false);
485 imagesavealpha($img, true);
486 } else {
487 $img = imagerotate($img, $deg, 0);
488 }
489 }
490 // then rewrite the rotated image back to the disk as $fileDest
491 if ($fileDest === false) {
492 return $img;
493 } else {
494 // In fact there exif is only for JPG but just in case
495 // Create image on disk
496 $image = false;
497
498 switch ($infoImg[2]) {
499 case IMAGETYPE_GIF: // 1
500 $image = imagegif($img, $fileDest);
501 break;
502 case IMAGETYPE_JPEG: // 2
503 $image = imagejpeg($img, $fileDest, $quality);
504 break;
505 case IMAGETYPE_PNG: // 3
506 $image = imagepng($img, $fileDest, $quality);
507 break;
508 case IMAGETYPE_BMP: // 6
509 // Not supported by PHP GD
510 break;
511 case IMAGETYPE_WBMP: // 15
512 $image = imagewbmp($img, $fileDest);
513 break;
514 }
515
516 // Free up memory (imagedestroy does not delete files):
517 @imagedestroy($img);
518
519 return $image;
520 }
521 } // if there is some rotation necessary
522 } // if have the exif orientation info
523 } // if function exists
524
525 return false;
526}
527
542function vignette($file, $maxWidth = 160, $maxHeight = 120, $extName = '_small', $quality = 50, $outdir = 'thumbs', $targetformat = 0)
543{
544 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
545
546 global $langs;
547
548 dol_syslog("vignette file=".$file." extName=".$extName." maxWidth=".$maxWidth." maxHeight=".$maxHeight." quality=".$quality." outdir=".$outdir." targetformat=".$targetformat);
549
550 // Clean parameters
551 $file = dol_sanitizePathName(trim($file));
552
553 // Check parameters
554 if (!$file) {
555 // If the file has not been indicated
556 return 'ErrorBadParameters';
557 } elseif (image_format_supported($file) < 0) {
558 dol_syslog('This file '.$file.' does not seem to be a supported image file name (bad extension).', LOG_WARNING);
559 return 'ErrorBadImageFormat';
560 } elseif (!is_numeric($maxWidth) || empty($maxWidth) || $maxWidth < -1) {
561 // If max width is incorrect (not numeric, empty, or less than 0)
562 dol_syslog('Wrong value for parameter maxWidth', LOG_ERR);
563 return 'Error: Wrong value for parameter maxWidth';
564 } elseif (!is_numeric($maxHeight) || empty($maxHeight) || $maxHeight < -1) {
565 // If max height is incorrect (not numeric, empty, or less than 0)
566 dol_syslog('Wrong value for parameter maxHeight', LOG_ERR);
567 return 'Error: Wrong value for parameter maxHeight';
568 }
569
570 $filetoread = realpath(dol_osencode($file)); // Absolute canonical path of image
571
572 if (!file_exists($filetoread)) {
573 // If the file passed in parameter does not exist
574 dol_syslog($langs->trans("ErrorFileNotFound", $filetoread), LOG_ERR);
575 return $langs->trans("ErrorFileNotFound", $filetoread);
576 }
577
578 $infoImg = getimagesize($filetoread); // Get information like size and real format of image. Warning real format may be png when extension is .jpg
579 $imgWidth = $infoImg[0]; // Width of image
580 $imgHeight = $infoImg[1]; // Height of image
581
582 // TODO LDR
583 //if $infoImg[2] != extension of file $file, return a string 'Error: content of file has a format that differs of the format of its extension
584
585 $ort = false;
586 if (function_exists('exif_read_data')) {
587 $exif = @exif_read_data($filetoread);
588 if ($exif && !empty($exif['Orientation'])) {
589 $ort = $exif['Orientation'];
590 }
591 }
592
593 if ($maxWidth == -1) {
594 $maxWidth = $infoImg[0]; // If size is -1, we keep unchanged
595 }
596 if ($maxHeight == -1) {
597 $maxHeight = $infoImg[1]; // If size is -1, we keep unchanged
598 }
599
600 // If the image is smaller than the maximum width and height, no thumbnail is created.
601 if ($infoImg[0] < $maxWidth && $infoImg[1] < $maxHeight) {
602 // we always create thumbnails
603 dol_syslog("File size is smaller than thumb size", LOG_DEBUG);
604 // return 'Le fichier '.$file.' ne necessite pas de creation de vignette';
605 }
606
607 $imgfonction = '';
608 switch ($infoImg[2]) {
609 case IMAGETYPE_GIF: // 1
610 $imgfonction = 'imagecreatefromgif';
611 break;
612 case IMAGETYPE_JPEG: // 2
613 $imgfonction = 'imagecreatefromjpeg';
614 break;
615 case IMAGETYPE_PNG: // 3
616 $imgfonction = 'imagecreatefrompng';
617 break;
618 case IMAGETYPE_BMP: // 6
619 // Not supported by PHP GD
620 $imgfonction = '';
621 break;
622 case IMAGETYPE_WBMP: // 15
623 $imgfonction = 'imagecreatefromwbmp';
624 break;
625 case IMAGETYPE_WEBP: // 18
626 $imgfonction = 'imagecreatefromwebp';
627 break;
628 case 19: // 19 TYPEIMAGE_AVIF constant don't exists with php < 8.1
629 $imgfonction = 'imagecreatefromavif';
630 break;
631 default:
632 $imgfonction = '';
633 }
634 if ($imgfonction) {
635 if (!function_exists($imgfonction)) {
636 // Conversion functions not present in this PHP
637 return 'Error: Creation of thumbs not possible. This PHP does not support GD function '.$imgfonction;
638 }
639 }
640
641 // We create the directory containing the thumbnails
642 $dirthumb = dirname($file).($outdir ? '/'.$outdir : ''); // Path to thumbnail folder
643 dol_mkdir($dirthumb);
644
645 // Variable initialization according to image extension
646 $img = null;
647 $extImg = null;
648 switch ($infoImg[2]) {
649 case IMAGETYPE_GIF: // 1
650 $img = imagecreatefromgif($filetoread);
651 $extImg = '.gif';
652 break;
653 case IMAGETYPE_JPEG: // 2
654 $img = imagecreatefromjpeg($filetoread);
655 $extImg = (preg_match('/\.jpeg$/', $file) ? '.jpeg' : '.jpg');
656 break;
657 case IMAGETYPE_PNG: // 3
658 $img = imagecreatefrompng($filetoread);
659 $extImg = '.png';
660 break;
661 case IMAGETYPE_BMP: // 6
662 // Not supported by PHP GD
663 $extImg = '.bmp';
664 break;
665 case IMAGETYPE_WBMP: // 15
666 $img = imagecreatefromwbmp($filetoread);
667 $extImg = '.bmp';
668 break;
669 case IMAGETYPE_WEBP: // 18
670 $img = imagecreatefromwebp($filetoread);
671 $extImg = '.webp';
672 break;
673 case 19: // 19 TYPEIMAGE_AVIF constant don't exists with php < 8.1
674 $img = imagecreatefromavif($filetoread);
675 $extImg = '.avif';
676 break;
677 }
678
679 // Before PHP8, img was a resource, With PHP8, it is a GdImage
680 // if (!is_resource($img) && class_exists('GdImage') && !($img instanceof GdImage)) {
681 if (is_null($img) || $img === false) {
682 dol_syslog('Failed to detect type of image. We found infoImg[2]='.$infoImg[2], LOG_WARNING);
683 return 0;
684 }
685
686 $exifAngle = false;
687 if ($ort && getDolGlobalString('MAIN_USE_EXIF_ROTATION')) {
688 switch ($ort) {
689 case 3: // 180 rotate left
690 $exifAngle = 180;
691 break;
692 case 6: // 90 rotate right
693 $exifAngle = -90;
694 // changing sizes
695 $trueImgWidth = $infoImg[1];
696 $trueImgHeight = $infoImg[0];
697 break;
698 case 8: // 90 rotate left
699 $exifAngle = 90;
700 // changing sizes
701 $trueImgWidth = $infoImg[1]; // Largeur de l'image
702 $trueImgHeight = $infoImg[0]; // Hauteur de l'image
703 break;
704 }
705 }
706
707 if ($exifAngle) {
708 $rotated = false;
709
710 if ($infoImg[2] === IMAGETYPE_PNG) { // In fact there is no exif on PNG but just in case
711 imagealphablending($img, false);
712 imagesavealpha($img, true);
713 $rotated = imagerotate($img, $exifAngle, imagecolorallocatealpha($img, 0, 0, 0, 127));
714 imagealphablending($rotated, false);
715 imagesavealpha($rotated, true);
716 } else {
717 $rotated = imagerotate($img, $exifAngle, 0);
718 }
719
720 // replace image with good orientation
721 if (!empty($rotated) && isset($trueImgWidth) && isset($trueImgHeight)) {
722 $img = $rotated;
723 $imgWidth = $trueImgWidth;
724 $imgHeight = $trueImgHeight;
725 }
726 }
727
728 // Initialize thumbnail dimensions if larger than original
729 if ($maxWidth > $imgWidth) {
730 $maxWidth = $imgWidth;
731 }
732 if ($maxHeight > $imgHeight) {
733 $maxHeight = $imgHeight;
734 }
735
736 $whFact = $maxWidth / $maxHeight; // Width/height factor for maximum label dimensions
737 $imgWhFact = $imgWidth / $imgHeight; // Original width/height factor
738
739 // Set label dimensions
740 if ($whFact < $imgWhFact) {
741 // If determining width
742 $thumbWidth = $maxWidth;
743 $thumbHeight = $thumbWidth / $imgWhFact;
744 } else {
745 // If determining height
746 $thumbHeight = $maxHeight;
747 $thumbWidth = $thumbHeight * $imgWhFact;
748 }
749 $thumbHeight = (int) round($thumbHeight);
750 $thumbWidth = (int) round($thumbWidth);
751
752 // Define target format
753 if (empty($targetformat)) {
754 $targetformat = $infoImg[2];
755 }
756
757 // Create empty image
758 if ($targetformat == IMAGETYPE_GIF) {
759 // Compatibilite image GIF
760 $imgThumb = imagecreate($thumbWidth, $thumbHeight);
761 } else {
762 $imgThumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
763 }
764
765 // Activate antialiasing for better quality
766 if (function_exists('imageantialias')) {
767 imageantialias($imgThumb, true);
768 }
769
770 // This is to keep transparent alpha channel if exists (PHP >= 4.2)
771 if (function_exists('imagesavealpha')) {
772 imagesavealpha($imgThumb, true);
773 }
774
775 // Variable initialization according to image extension
776 // $targetformat is 0 by default, in such case, we keep original extension
777 $extImgTarget = ''; // Default = same extension as original
778 $trans_colour = false;
779 $newquality = null;
780 switch ($targetformat) {
781 case IMAGETYPE_GIF: // 1
782 $trans_colour = imagecolorallocate($imgThumb, 255, 255, 255); // The GIF format works differently
783 imagecolortransparent($imgThumb, $trans_colour);
784 $extImgTarget = '.gif';
785 $newquality = 'NU';
786 break;
787 case IMAGETYPE_JPEG: // 2
788 $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0);
789 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '.jpg');
790 $newquality = $quality;
791 break;
792 case IMAGETYPE_PNG: // 3
793 imagealphablending($imgThumb, false); // For compatibility on certain systems
794 $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 127); // Keep transparent channel
795 $extImgTarget = '.png';
796 $newquality = round(abs($quality - 100) * 9 / 100);
797 break;
798 case IMAGETYPE_BMP: // 6
799 // Not supported by PHP GD
800 $extImgTarget = '.bmp';
801 $newquality = 'NU';
802 break;
803 case IMAGETYPE_WBMP: // 15
804 $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0);
805 $extImgTarget = '.bmp';
806 $newquality = 'NU';
807 break;
808 case IMAGETYPE_WEBP: // 18
809 $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0);
810 $extImgTarget = '.webp';
811 $newquality = $quality;
812 break;
813 }
814 if (function_exists("imagefill") && $trans_colour !== false) {
815 imagefill($imgThumb, 0, 0, $trans_colour);
816 }
817
818 dol_syslog("vignette: convert image from ($imgWidth x $imgHeight) to ($thumbWidth x $thumbHeight) as $extImg, newquality=$newquality");
819 //imagecopyresized($imgThumb, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insert resized base image
820 imagecopyresampled($imgThumb, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insert resized base image
821
822 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.avif)$/i', '', $file); // We remove any extension box
823 $fileName = basename($fileName);
824 //$imgThumbName = $dirthumb.'/'.getImageFileNameForSize(basename($file), $extName, $extImgTarget); // Full path of thumb file
825 $imgThumbName = getImageFileNameForSize($file, $extName, $extImgTarget); // Full path of thumb file
826
827
828 // Check if permission are ok
829 //$fp = fopen($imgThumbName, "w");
830 //fclose($fp);
831
832 // Create image on disk
833 switch ($targetformat) {
834 case IMAGETYPE_GIF: // 1
835 imagegif($imgThumb, $imgThumbName);
836 break;
837 case IMAGETYPE_JPEG: // 2
838 imagejpeg($imgThumb, $imgThumbName, $newquality); // @phan-suppress-current-line PhanTypeMismatchArgumentNullableInternal,PhanPossiblyUndeclaredVariable
839 break;
840 case IMAGETYPE_PNG: // 3
841 imagepng($imgThumb, $imgThumbName, !is_numeric($newquality) ? -1 : (int) $newquality); // @phan-suppress-current-line PhanPossiblyUndeclaredVariable
842 break;
843 case IMAGETYPE_BMP: // 6
844 // Not supported by PHP GD
845 break;
846 case IMAGETYPE_WBMP: // 15
847 imagewbmp($imgThumb, $imgThumbName);
848 break;
849 case IMAGETYPE_WEBP: // 18
850 imagewebp($imgThumb, $imgThumbName, $newquality); // @phan-suppress-current-line PhanTypeMismatchArgumentNullableInternal,PhanPossiblyUndeclaredVariable
851 break;
852 case 19: // 19 TYPEIMAGE_AVIF constant don't exists with php < 8.1
853 imageavif($imgThumb, $imgThumbName, $newquality); // @phan-suppress-current-line PhanTypeMismatchArgumentNullableInternal,PhanPossiblyUndeclaredVariable
854 break;
855 }
856
857 // Set permissions on file
858 dolChmod($imgThumbName);
859
860 // Free memory. This does not delete image.
861 imagedestroy($img);
862 imagedestroy($imgThumb);
863
864 return $imgThumbName;
865}
866
867
876function imgAddEditDeleteButton($htmlid, $urledit, $urldelete)
877{
878 // TODO
879 return '';
880}
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_sanitizePathName($str, $newstr='_', $unaccent=0, $allowdash=0)
Clean a string to use it as a path name.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
getListOfPossibleImageExt($acceptsvg=0)
Return if a filename is file name of a supported image format.
if(!defined( 'IMAGETYPE_WEBP')) getDefaultImageSizes()
Return default values for image sizes.
correctExifImageOrientation($fileSource, $fileDest, $quality=95)
Add exif orientation correction for image.
dolRotateImage($file_path)
dolRotateImage if image is a jpg file.
dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x=0, $src_y=0, $filetowrite='', $newquality=0)
Resize or crop an image file (Supported extensions are gif, jpg, png, bmp and webp)
dol_getImageSize($file, $url=false)
Return size of image file on disk (Supported extensions are gif, jpg, png, bmp and webp)
imgAddEditDeleteButton($htmlid, $urledit, $urldelete)
Beautify an image by adding a link edit and delete on image.
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.