images.lib.php 25 KB

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