images.lib.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  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. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. * or see https://www.gnu.org/
  18. */
  19. /**
  20. * \file htdocs/core/lib/images.lib.php
  21. * \brief Set of function for manipulating images
  22. */
  23. // Define size of logo small and mini
  24. // TODO Remove this and call getDefaultImageSizes() instead
  25. $maxwidthsmall = 480;
  26. $maxheightsmall = 270; // Near 16/9eme
  27. $maxwidthmini = 128;
  28. $maxheightmini = 72; // 16/9eme
  29. $quality = 80;
  30. if (!defined('IMAGETYPE_WEBP')) {
  31. define('IMAGETYPE_WEBP', 18);
  32. }
  33. /**
  34. * Return default values for image sizes
  35. *
  36. * @return array Array of default values
  37. */
  38. function getDefaultImageSizes()
  39. {
  40. $maxwidthsmall = 480;
  41. $maxheightsmall = 270; // Near 16/9eme
  42. $maxwidthmini = 128;
  43. $maxheightmini = 72; // 16/9eme
  44. $quality = 80;
  45. return array(
  46. 'maxwidthsmall' => $maxwidthsmall,
  47. 'maxheightsmall' => $maxheightsmall,
  48. 'maxwidthmini' => $maxwidthmini,
  49. 'maxheightmini' => $maxheightmini,
  50. 'quality' => $quality
  51. );
  52. }
  53. /**
  54. * Return if a filename is file name of a supported image format
  55. *
  56. * @param int $acceptsvg 0=Default (depends on setup), 1=Always accept SVG as image files
  57. * @return string Return list fo image format
  58. */
  59. function getListOfPossibleImageExt($acceptsvg = 0)
  60. {
  61. global $conf;
  62. $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm'; // See also into product.class.php
  63. if ($acceptsvg || getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
  64. $regeximgext .= '|\.svg'; // Not allowed by default. SVG can contains javascript
  65. }
  66. return $regeximgext;
  67. }
  68. /**
  69. * Return if a filename is file name of a supported image format
  70. *
  71. * @param string $file Filename
  72. * @param int $acceptsvg 0=Default (depends on setup), 1=Always accept SVG as image files
  73. * @return int -1=Not image filename, 0=Image filename but format not supported for conversion by PHP, 1=Image filename with format supported by this PHP
  74. */
  75. function image_format_supported($file, $acceptsvg = 0)
  76. {
  77. $regeximgext = getListOfPossibleImageExt();
  78. // Case filename is not a format image
  79. $reg = array();
  80. if (!preg_match('/('.$regeximgext.')$/i', $file, $reg)) {
  81. return -1;
  82. }
  83. // Case filename is a format image but not supported by this PHP
  84. $imgfonction = '';
  85. if (strtolower($reg[1]) == '.gif') {
  86. $imgfonction = 'imagecreatefromgif';
  87. }
  88. if (strtolower($reg[1]) == '.jpg') {
  89. $imgfonction = 'imagecreatefromjpeg';
  90. }
  91. if (strtolower($reg[1]) == '.jpeg') {
  92. $imgfonction = 'imagecreatefromjpeg';
  93. }
  94. if (strtolower($reg[1]) == '.png') {
  95. $imgfonction = 'imagecreatefrompng';
  96. }
  97. if (strtolower($reg[1]) == '.bmp') {
  98. $imgfonction = 'imagecreatefromwbmp';
  99. }
  100. if (strtolower($reg[1]) == '.webp') {
  101. $imgfonction = 'imagecreatefromwebp';
  102. }
  103. if (strtolower($reg[1]) == '.xpm') {
  104. $imgfonction = 'imagecreatefromxpm';
  105. }
  106. if (strtolower($reg[1]) == '.xbm') {
  107. $imgfonction = 'imagecreatefromxbm';
  108. }
  109. if (strtolower($reg[1]) == '.svg') {
  110. $imgfonction = 'imagecreatefromsvg'; // Never available
  111. }
  112. if ($imgfonction) {
  113. if (!function_exists($imgfonction)) {
  114. // Fonctions of conversion not available in this PHP
  115. return 0;
  116. }
  117. // Filename is a format image and supported for conversion by this PHP
  118. return 1;
  119. }
  120. return 0;
  121. }
  122. /**
  123. * Return size of image file on disk (Supported extensions are gif, jpg, png, bmp and webp)
  124. *
  125. * @param string $file Full path name of file
  126. * @param bool $url Image with url (true or false)
  127. * @return array array('width'=>width, 'height'=>height)
  128. */
  129. function dol_getImageSize($file, $url = false)
  130. {
  131. $ret = array();
  132. if (image_format_supported($file) < 0) {
  133. return $ret;
  134. }
  135. $filetoread = $file;
  136. if (!$url) {
  137. $filetoread = realpath(dol_osencode($file)); // Chemin canonique absolu de l'image
  138. }
  139. if ($filetoread) {
  140. $infoImg = getimagesize($filetoread); // Recuperation des infos de l'image
  141. if ($infoImg) {
  142. $ret['width'] = $infoImg[0]; // Largeur de l'image
  143. $ret['height'] = $infoImg[1]; // Hauteur de l'image
  144. } else {
  145. $ret['width'] = $ret['height'] = '';
  146. }
  147. }
  148. return $ret;
  149. }
  150. /**
  151. * Resize or crop an image file (Supported extensions are gif, jpg, png, bmp and webp)
  152. *
  153. * @param string $file Path of source file to resize/crop
  154. * @param int $mode 0=Resize, 1=Crop
  155. * @param int $newWidth Largeur maximum que dois faire l'image destination (0=keep ratio)
  156. * @param int $newHeight Hauteur maximum que dois faire l'image destination (0=keep ratio)
  157. * @param int $src_x Position of croping image in source image (not use if mode=0)
  158. * @param int $src_y Position of croping image in source image (not use if mode=0)
  159. * @param string $filetowrite Path of file to write (overwrite source file if not provided)
  160. * @param int $newquality Value for the new quality of image, for supported format (use 0 for maximum/unchanged).
  161. * @return string File name if OK, error message if KO
  162. * @see dol_convert_file()
  163. */
  164. function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x = 0, $src_y = 0, $filetowrite = '', $newquality = 0)
  165. {
  166. require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
  167. global $conf, $langs;
  168. dol_syslog("dol_imageResizeOrCrop file=".$file." mode=".$mode." newWidth=".$newWidth." newHeight=".$newHeight." src_x=".$src_x." src_y=".$src_y);
  169. // Clean parameters
  170. $file = trim($file);
  171. // Check parameters
  172. if (!$file) {
  173. // Si le fichier n'a pas ete indique
  174. return 'Bad parameter file';
  175. } elseif (!file_exists($file)) {
  176. // Si le fichier passe en parametre n'existe pas
  177. return $langs->trans("ErrorFileNotFound", $file);
  178. } elseif (image_format_supported($file) < 0) {
  179. return 'This filename '.$file.' does not seem to be an image filename.';
  180. } elseif (!is_numeric($newWidth) && !is_numeric($newHeight)) {
  181. return 'Wrong value for parameter newWidth or newHeight';
  182. } elseif ($mode == 0 && $newWidth <= 0 && $newHeight <= 0 && (empty($filetowrite) || $filetowrite == $file)) {
  183. return 'At least newHeight or newWidth must be defined for resizing, or a target filename must be set to convert';
  184. } elseif ($mode == 1 && ($newWidth <= 0 || $newHeight <= 0)) {
  185. return 'Both newHeight or newWidth must be defined for croping';
  186. }
  187. $filetoread = realpath(dol_osencode($file)); // Chemin canonique absolu de l'image
  188. $infoImg = getimagesize($filetoread); // Get data about src image
  189. $imgWidth = $infoImg[0]; // Largeur de l'image
  190. $imgHeight = $infoImg[1]; // Hauteur de l'image
  191. $imgTargetName = ($filetowrite ? $filetowrite : $file);
  192. $newExt = strtolower(pathinfo($imgTargetName, PATHINFO_EXTENSION));
  193. if ($mode == 0) { // If resize, we check parameters
  194. if (!empty($filetowrite) && $filetowrite != $file && $newWidth <= 0 && $newHeight <= 0) {
  195. $newWidth = $imgWidth;
  196. $newHeight = $imgHeight;
  197. }
  198. if ($newWidth <= 0) {
  199. $newWidth = intval(($newHeight / $imgHeight) * $imgWidth); // Keep ratio
  200. }
  201. if ($newHeight <= 0) {
  202. $newHeight = intval(($newWidth / $imgWidth) * $imgHeight); // Keep ratio
  203. }
  204. }
  205. // Test function to read source image exists
  206. $imgfonction = '';
  207. switch ($infoImg[2]) {
  208. case 1: // IMG_GIF
  209. $imgfonction = 'imagecreatefromgif';
  210. break;
  211. case 2: // IMG_JPG
  212. $imgfonction = 'imagecreatefromjpeg';
  213. break;
  214. case 3: // IMG_PNG
  215. $imgfonction = 'imagecreatefrompng';
  216. break;
  217. case 4: // IMG_WBMP
  218. $imgfonction = 'imagecreatefromwbmp';
  219. break;
  220. case 18: // IMG_WEBP
  221. $imgfonction = 'imagecreatefromwebp';
  222. break;
  223. }
  224. if ($imgfonction) {
  225. if (!function_exists($imgfonction)) {
  226. // Fonctions de conversion non presente dans ce PHP
  227. return 'Read of image not possible. This PHP does not support GD functions '.$imgfonction;
  228. }
  229. }
  230. // Test function to write target image exists
  231. if ($filetowrite) {
  232. $imgfonction = '';
  233. switch ($newExt) {
  234. case 'gif': // IMG_GIF
  235. $imgfonction = 'imagecreatefromgif';
  236. break;
  237. case 'jpg': // IMG_JPG
  238. case 'jpeg': // IMG_JPEG
  239. $imgfonction = 'imagecreatefromjpeg';
  240. break;
  241. case 'png': // IMG_PNG
  242. $imgfonction = 'imagecreatefrompng';
  243. break;
  244. case 'bmp': // IMG_WBMP
  245. $imgfonction = 'imagecreatefromwbmp';
  246. break;
  247. case 'webp': // IMG_WEBP
  248. $imgfonction = 'imagecreatefromwebp';
  249. break;
  250. }
  251. if ($imgfonction) {
  252. if (!function_exists($imgfonction)) {
  253. // Fonctions de conversion non presente dans ce PHP
  254. return 'Write of image not possible. This PHP does not support GD functions '.$imgfonction;
  255. }
  256. }
  257. }
  258. // Read source image file
  259. switch ($infoImg[2]) {
  260. case 1: // Gif
  261. $img = imagecreatefromgif($filetoread);
  262. $extImg = '.gif'; // File name extension of image
  263. break;
  264. case 2: // Jpg
  265. $img = imagecreatefromjpeg($filetoread);
  266. $extImg = '.jpg';
  267. break;
  268. case 3: // Png
  269. $img = imagecreatefrompng($filetoread);
  270. $extImg = '.png';
  271. break;
  272. case 4: // Bmp
  273. $img = imagecreatefromwbmp($filetoread);
  274. $extImg = '.bmp';
  275. break;
  276. case 18: // Webp
  277. $img = imagecreatefromwebp($filetoread);
  278. $extImg = '.webp';
  279. break;
  280. }
  281. // Create empty image for target
  282. if ($newExt == 'gif') {
  283. // Compatibility image GIF
  284. $imgTarget = imagecreate($newWidth, $newHeight);
  285. } else {
  286. $imgTarget = imagecreatetruecolor($newWidth, $newHeight);
  287. }
  288. // Activate antialiasing for better quality
  289. if (function_exists('imageantialias')) {
  290. imageantialias($imgTarget, true);
  291. }
  292. // This is to keep transparent alpha channel if exists (PHP >= 4.2)
  293. if (function_exists('imagesavealpha')) {
  294. imagesavealpha($imgTarget, true);
  295. }
  296. // Set transparent color according to image extension
  297. $trans_colour = -1; // By default, undefined
  298. switch ($newExt) {
  299. case 'gif': // Gif
  300. $trans_colour = imagecolorallocate($imgTarget, 255, 255, 255); // On procede autrement pour le format GIF
  301. imagecolortransparent($imgTarget, $trans_colour);
  302. break;
  303. case 'jpg': // Jpg
  304. case 'jpeg': // Jpeg
  305. $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 0);
  306. break;
  307. case 'png': // Png
  308. imagealphablending($imgTarget, false); // Pour compatibilite sur certain systeme
  309. $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 127); // Keep transparent channel
  310. break;
  311. case 'bmp': // Bmp
  312. $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 0);
  313. break;
  314. case 'webp': // Webp
  315. $trans_colour = imagecolorallocatealpha($imgTarget, 255, 255, 255, 127);
  316. break;
  317. }
  318. if (function_exists("imagefill") && $trans_colour > 0) {
  319. imagefill($imgTarget, 0, 0, $trans_colour);
  320. }
  321. dol_syslog("dol_imageResizeOrCrop: convert image from ($imgWidth x $imgHeight) at position ($src_x x $src_y) to ($newWidth x $newHeight) as a $extImg");
  322. //imagecopyresized($imgTarget, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insere l'image de base redimensionnee
  323. 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
  324. // Check if permission are ok
  325. //$fp = fopen($imgTargetName, "w");
  326. //fclose($fp);
  327. // Create image on disk (overwrite file if exists)
  328. switch ($newExt) {
  329. case 'gif': // Gif
  330. $newquality = 'NU'; // Quality is not used for this format
  331. imagegif($imgTarget, $imgTargetName);
  332. break;
  333. case 'jpg': // Jpg
  334. case 'jpeg': // Jpeg
  335. $newquality = ($newquality ? $newquality : '100'); // % quality maximum
  336. imagejpeg($imgTarget, $imgTargetName, $newquality);
  337. break;
  338. case 'png': // Png
  339. $newquality = 0; // No compression (0-9)
  340. imagepng($imgTarget, $imgTargetName, $newquality);
  341. break;
  342. case 'bmp': // Bmp
  343. $newquality = 'NU'; // Quality is not used for this format
  344. imagewbmp($imgTarget, $imgTargetName);
  345. break;
  346. case 'webp': // Webp
  347. $newquality = ($newquality ? $newquality : '100'); // % quality maximum
  348. imagewebp($imgTarget, $imgTargetName, $newquality);
  349. break;
  350. default:
  351. dol_syslog("images.lib.php::imageResizeOrCrop() Format ".$newExt." is not supported", LOG_WARNING);
  352. }
  353. // Set permissions on file
  354. dolChmod($imgTargetName);
  355. // Free memory. This does not delete image.
  356. imagedestroy($img);
  357. imagedestroy($imgTarget);
  358. clearstatcache(); // File was replaced by a modified one, so we clear file caches.
  359. return $imgTargetName;
  360. }
  361. /**
  362. * dolRotateImage if image is a jpg file.
  363. * Currently use an autodetection to know if we can rotate.
  364. * TODO Introduce a new parameter to force rotate.
  365. *
  366. * @param string $file_path Full path to image to rotate
  367. * @return boolean Success or not
  368. */
  369. function dolRotateImage($file_path)
  370. {
  371. return correctExifImageOrientation($file_path, $file_path);
  372. }
  373. /**
  374. * Add exif orientation correction for image
  375. *
  376. * @param string $fileSource Full path to source image to rotate
  377. * @param string|bool $fileDest string : Full path to image to rotate | false return gd img | null the raw image stream will be outputted directly
  378. * @param int $quality output image quality
  379. * @return bool : true on success or false on failure or gd img if $fileDest is false.
  380. */
  381. function correctExifImageOrientation($fileSource, $fileDest, $quality = 95)
  382. {
  383. if (function_exists('exif_read_data')) {
  384. $exif = @exif_read_data($fileSource);
  385. if ($exif && isset($exif['Orientation'])) {
  386. $infoImg = getimagesize($fileSource); // Get image infos
  387. $orientation = $exif['Orientation'];
  388. if ($orientation != 1) {
  389. $img = imagecreatefromjpeg($fileSource);
  390. $deg = 0;
  391. switch ($orientation) {
  392. case 3:
  393. $deg = 180;
  394. break;
  395. case 6:
  396. $deg = 270;
  397. break;
  398. case 8:
  399. $deg = 90;
  400. break;
  401. }
  402. if ($deg) {
  403. if ($infoImg[2] === IMAGETYPE_PNG) { // In fact there is no exif on PNG but just in case
  404. imagealphablending($img, false);
  405. imagesavealpha($img, true);
  406. $img = imagerotate($img, $deg, imageColorAllocateAlpha($img, 0, 0, 0, 127));
  407. imagealphablending($img, false);
  408. imagesavealpha($img, true);
  409. } else {
  410. $img = imagerotate($img, $deg, 0);
  411. }
  412. }
  413. // then rewrite the rotated image back to the disk as $fileDest
  414. if ($fileDest === false) {
  415. return $img;
  416. } else {
  417. // In fact there exif is only for JPG but just in case
  418. // Create image on disk
  419. $image = false;
  420. switch ($infoImg[2]) {
  421. case IMAGETYPE_GIF: // 1
  422. $image = imagegif($img, $fileDest);
  423. break;
  424. case IMAGETYPE_JPEG: // 2
  425. $image = imagejpeg($img, $fileDest, $quality);
  426. break;
  427. case IMAGETYPE_PNG: // 3
  428. $image = imagepng($img, $fileDest, $quality);
  429. break;
  430. case IMAGETYPE_BMP: // 6
  431. // Not supported by PHP GD
  432. break;
  433. case IMAGETYPE_WBMP: // 15
  434. $image = imagewbmp($img, $fileDest);
  435. break;
  436. }
  437. // Free up memory (imagedestroy does not delete files):
  438. @imagedestroy($img);
  439. return $image;
  440. }
  441. } // if there is some rotation necessary
  442. } // if have the exif orientation info
  443. } // if function exists
  444. return false;
  445. }
  446. /**
  447. * Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
  448. * If file is myfile.jpg, new file may be myfile_small.jpg
  449. *
  450. * @param string $file Path of source file to resize
  451. * @param int $maxWidth Maximum width of the thumbnail (-1=unchanged, 160 by default)
  452. * @param int $maxHeight Maximum height of the thumbnail (-1=unchanged, 120 by default)
  453. * @param string $extName Extension to differentiate thumb file name ('_small', '_mini')
  454. * @param int $quality Quality of compression (0=worst, 100=best)
  455. * @param string $outdir Directory where to store thumb
  456. * @param int $targetformat New format of target (IMAGETYPE_GIF, IMAGETYPE_JPG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_WBMP ... or 0 to keep old format)
  457. * @return string Full path of thumb or '' if it fails or 'Error...' if it fails
  458. */
  459. function vignette($file, $maxWidth = 160, $maxHeight = 120, $extName = '_small', $quality = 50, $outdir = 'thumbs', $targetformat = 0)
  460. {
  461. require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
  462. global $conf, $langs;
  463. dol_syslog("vignette file=".$file." extName=".$extName." maxWidth=".$maxWidth." maxHeight=".$maxHeight." quality=".$quality." outdir=".$outdir." targetformat=".$targetformat);
  464. // Clean parameters
  465. $file = trim($file);
  466. // Check parameters
  467. if (!$file) {
  468. // If the file has not been indicated
  469. return 'ErrorBadParameters';
  470. } elseif (!file_exists($file)) {
  471. // If the file passed in parameter does not exist
  472. dol_syslog($langs->trans("ErrorFileNotFound", $file), LOG_ERR);
  473. return $langs->trans("ErrorFileNotFound", $file);
  474. } elseif (image_format_supported($file) < 0) {
  475. dol_syslog('This file '.$file.' does not seem to be an image format file name.', LOG_WARNING);
  476. return 'ErrorBadImageFormat';
  477. } elseif (!is_numeric($maxWidth) || empty($maxWidth) || $maxWidth < -1) {
  478. // If max width is incorrect (not numeric, empty, or less than 0)
  479. dol_syslog('Wrong value for parameter maxWidth', LOG_ERR);
  480. return 'Error: Wrong value for parameter maxWidth';
  481. } elseif (!is_numeric($maxHeight) || empty($maxHeight) || $maxHeight < -1) {
  482. // If max height is incorrect (not numeric, empty, or less than 0)
  483. dol_syslog('Wrong value for parameter maxHeight', LOG_ERR);
  484. return 'Error: Wrong value for parameter maxHeight';
  485. }
  486. $filetoread = realpath(dol_osencode($file)); // Chemin canonique absolu de l'image
  487. $infoImg = getimagesize($filetoread); // Recuperation des infos de l'image
  488. $imgWidth = $infoImg[0]; // Largeur de l'image
  489. $imgHeight = $infoImg[1]; // Hauteur de l'image
  490. $ort = false;
  491. if (function_exists('exif_read_data')) {
  492. $exif = @exif_read_data($filetoread);
  493. if ($exif && !empty($exif['Orientation'])) {
  494. $ort = $exif['Orientation'];
  495. }
  496. }
  497. if ($maxWidth == -1) {
  498. $maxWidth = $infoImg[0]; // If size is -1, we keep unchanged
  499. }
  500. if ($maxHeight == -1) {
  501. $maxHeight = $infoImg[1]; // If size is -1, we keep unchanged
  502. }
  503. // If the image is smaller than the maximum width and height, no thumbnail is created.
  504. if ($infoImg[0] < $maxWidth && $infoImg[1] < $maxHeight) {
  505. // On cree toujours les vignettes
  506. dol_syslog("File size is smaller than thumb size", LOG_DEBUG);
  507. //return 'Le fichier '.$file.' ne necessite pas de creation de vignette';
  508. }
  509. $imgfonction = '';
  510. switch ($infoImg[2]) {
  511. case IMAGETYPE_GIF: // 1
  512. $imgfonction = 'imagecreatefromgif';
  513. break;
  514. case IMAGETYPE_JPEG: // 2
  515. $imgfonction = 'imagecreatefromjpeg';
  516. break;
  517. case IMAGETYPE_PNG: // 3
  518. $imgfonction = 'imagecreatefrompng';
  519. break;
  520. case IMAGETYPE_BMP: // 6
  521. // Not supported by PHP GD
  522. break;
  523. case IMAGETYPE_WBMP: // 15
  524. $imgfonction = 'imagecreatefromwbmp';
  525. break;
  526. case IMAGETYPE_WEBP: // 18
  527. $imgfonction = 'imagecreatefromwebp';
  528. break;
  529. }
  530. if ($imgfonction) {
  531. if (!function_exists($imgfonction)) {
  532. // Conversion functions not present in this PHP
  533. return 'Error: Creation of thumbs not possible. This PHP does not support GD function '.$imgfonction;
  534. }
  535. }
  536. // We create the directory containing the thumbnails
  537. $dirthumb = dirname($file).($outdir ? '/'.$outdir : ''); // Path to thumbnail folder
  538. dol_mkdir($dirthumb);
  539. // Variable initialization according to image extension
  540. $img = null;
  541. switch ($infoImg[2]) {
  542. case IMAGETYPE_GIF: // 1
  543. $img = imagecreatefromgif($filetoread);
  544. $extImg = '.gif';
  545. break;
  546. case IMAGETYPE_JPEG: // 2
  547. $img = imagecreatefromjpeg($filetoread);
  548. $extImg = (preg_match('/\.jpeg$/', $file) ? '.jpeg' : '.jpg');
  549. break;
  550. case IMAGETYPE_PNG: // 3
  551. $img = imagecreatefrompng($filetoread);
  552. $extImg = '.png';
  553. break;
  554. case IMAGETYPE_BMP: // 6
  555. // Not supported by PHP GD
  556. $extImg = '.bmp';
  557. break;
  558. case IMAGETYPE_WBMP: // 15
  559. $img = imagecreatefromwbmp($filetoread);
  560. $extImg = '.bmp';
  561. break;
  562. case IMAGETYPE_WEBP: // 18
  563. $img = imagecreatefromwebp($filetoread);
  564. $extImg = '.webp';
  565. break;
  566. }
  567. // Before PHP8, img was a resource, With PHP8, it is a GdImage
  568. if (!is_resource($img) && class_exists('GdImage') && !($img instanceof GdImage)) {
  569. dol_syslog('Failed to detect type of image. We found infoImg[2]='.$infoImg[2], LOG_WARNING);
  570. return 0;
  571. }
  572. $exifAngle = false;
  573. if ($ort && getDolGlobalString('MAIN_USE_EXIF_ROTATION')) {
  574. switch ($ort) {
  575. case 3: // 180 rotate left
  576. $exifAngle = 180;
  577. break;
  578. case 6: // 90 rotate right
  579. $exifAngle = -90;
  580. // changing sizes
  581. $trueImgWidth = $infoImg[1];
  582. $trueImgHeight = $infoImg[0];
  583. break;
  584. case 8: // 90 rotate left
  585. $exifAngle = 90;
  586. // changing sizes
  587. $trueImgWidth = $infoImg[1]; // Largeur de l'image
  588. $trueImgHeight = $infoImg[0]; // Hauteur de l'image
  589. break;
  590. }
  591. }
  592. if ($exifAngle) {
  593. $rotated = false;
  594. if ($infoImg[2] === 'IMAGETYPE_PNG') { // In fact there is no exif on PNG but just in case
  595. imagealphablending($img, false);
  596. imagesavealpha($img, true);
  597. $rotated = imagerotate($img, $exifAngle, imageColorAllocateAlpha($img, 0, 0, 0, 127));
  598. imagealphablending($rotated, false);
  599. imagesavealpha($rotated, true);
  600. } else {
  601. $rotated = imagerotate($img, $exifAngle, 0);
  602. }
  603. // replace image with good orientation
  604. if (!empty($rotated) && isset($trueImgWidth) && isset($trueImgHeight)) {
  605. $img = $rotated;
  606. $imgWidth = $trueImgWidth;
  607. $imgHeight = $trueImgHeight;
  608. }
  609. }
  610. // Initialize thumbnail dimensions if larger than original
  611. if ($maxWidth > $imgWidth) {
  612. $maxWidth = $imgWidth;
  613. }
  614. if ($maxHeight > $imgHeight) {
  615. $maxHeight = $imgHeight;
  616. }
  617. $whFact = $maxWidth / $maxHeight; // Width/height factor for maximum label dimensions
  618. $imgWhFact = $imgWidth / $imgHeight; // Original width/height factor
  619. // Set label dimensions
  620. if ($whFact < $imgWhFact) {
  621. // If determining width
  622. $thumbWidth = $maxWidth;
  623. $thumbHeight = $thumbWidth / $imgWhFact;
  624. } else {
  625. // If determining height
  626. $thumbHeight = $maxHeight;
  627. $thumbWidth = $thumbHeight * $imgWhFact;
  628. }
  629. $thumbHeight = round($thumbHeight);
  630. $thumbWidth = round($thumbWidth);
  631. // Define target format
  632. if (empty($targetformat)) {
  633. $targetformat = $infoImg[2];
  634. }
  635. // Create empty image
  636. if ($targetformat == IMAGETYPE_GIF) {
  637. // Compatibilite image GIF
  638. $imgThumb = imagecreate($thumbWidth, $thumbHeight);
  639. } else {
  640. $imgThumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
  641. }
  642. // Activate antialiasing for better quality
  643. if (function_exists('imageantialias')) {
  644. imageantialias($imgThumb, true);
  645. }
  646. // This is to keep transparent alpha channel if exists (PHP >= 4.2)
  647. if (function_exists('imagesavealpha')) {
  648. imagesavealpha($imgThumb, true);
  649. }
  650. // Variable initialization according to image extension
  651. // $targetformat is 0 by default, in such case, we keep original extension
  652. switch ($targetformat) {
  653. case IMAGETYPE_GIF: // 1
  654. $trans_colour = imagecolorallocate($imgThumb, 255, 255, 255); // The GIF format works differently
  655. imagecolortransparent($imgThumb, $trans_colour);
  656. $extImgTarget = '.gif';
  657. $newquality = 'NU';
  658. break;
  659. case IMAGETYPE_JPEG: // 2
  660. $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0);
  661. $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '.jpg');
  662. $newquality = $quality;
  663. break;
  664. case IMAGETYPE_PNG: // 3
  665. imagealphablending($imgThumb, false); // For compatibility on certain systems
  666. $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 127); // Keep transparent channel
  667. $extImgTarget = '.png';
  668. $newquality = $quality - 100;
  669. $newquality = round(abs($quality - 100) * 9 / 100);
  670. break;
  671. case IMAGETYPE_BMP: // 6
  672. // Not supported by PHP GD
  673. $extImgTarget = '.bmp';
  674. $newquality = 'NU';
  675. break;
  676. case IMAGETYPE_WBMP: // 15
  677. $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0);
  678. $extImgTarget = '.bmp';
  679. $newquality = 'NU';
  680. break;
  681. case IMAGETYPE_WEBP: // 18
  682. $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0);
  683. $extImgTarget = '.webp';
  684. $newquality = $quality;
  685. break;
  686. }
  687. if (function_exists("imagefill")) {
  688. imagefill($imgThumb, 0, 0, $trans_colour);
  689. }
  690. dol_syslog("vignette: convert image from ($imgWidth x $imgHeight) to ($thumbWidth x $thumbHeight) as $extImg, newquality=$newquality");
  691. //imagecopyresized($imgThumb, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insert resized base image
  692. imagecopyresampled($imgThumb, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insert resized base image
  693. $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp)$/i', '', $file); // We remove any extension box
  694. $fileName = basename($fileName);
  695. //$imgThumbName = $dirthumb.'/'.getImageFileNameForSize(basename($file), $extName, $extImgTarget); // Full path of thumb file
  696. $imgThumbName = getImageFileNameForSize($file, $extName, $extImgTarget); // Full path of thumb file
  697. // Check if permission are ok
  698. //$fp = fopen($imgThumbName, "w");
  699. //fclose($fp);
  700. // Create image on disk
  701. switch ($targetformat) {
  702. case IMAGETYPE_GIF: // 1
  703. imagegif($imgThumb, $imgThumbName);
  704. break;
  705. case IMAGETYPE_JPEG: // 2
  706. imagejpeg($imgThumb, $imgThumbName, $newquality);
  707. break;
  708. case IMAGETYPE_PNG: // 3
  709. imagepng($imgThumb, $imgThumbName, $newquality);
  710. break;
  711. case IMAGETYPE_BMP: // 6
  712. // Not supported by PHP GD
  713. break;
  714. case IMAGETYPE_WBMP: // 15
  715. imagewbmp($imgThumb, $imgThumbName);
  716. break;
  717. case IMAGETYPE_WEBP: // 18
  718. imagewebp($imgThumb, $imgThumbName, $newquality);
  719. break;
  720. }
  721. // Set permissions on file
  722. dolChmod($imgThumbName);
  723. // Free memory. This does not delete image.
  724. imagedestroy($img);
  725. imagedestroy($imgThumb);
  726. return $imgThumbName;
  727. }