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