diff --git a/ChangeLog b/ChangeLog index 7d6c76c5e3c3b2cf55030a5927f0f5d9f8283466..0fcbf856d1d9d784510ecbbf62365f7a0af7f4c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,10 +3,11 @@ English Dolibarr ChangeLog ***** ChangeLog for 2.9 compared to 2.8 ***** For users: -New: Add "payment due before" field in invoice exports +- New: Add "payment due before" field in invoice exports +- New: Add feature to resize or crop image files (for products photos) For developers: - +- More comments in code ***** ChangeLog for 2.8 compared to 2.7 ***** diff --git a/htdocs/core/photos_resize.php b/htdocs/core/photos_resize.php index aacd0c548b7f1d491c96c603c4cfda1686d90044..0e6bad3b1146e4774e6671e18d6f9d51e2cd8ee0 100644 --- a/htdocs/core/photos_resize.php +++ b/htdocs/core/photos_resize.php @@ -1,8 +1,6 @@ <?php -/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org> - * Copyright (C) 2004-2009 Laurent Destailleur <eldy@users.sourceforge.net> - * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com> - * Copyright (C) 2005-2009 Regis Houssin <regis@dolibarr.fr> +/* Copyright (C) 2010 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2009 Meos * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,19 +24,17 @@ require_once(DOL_DOCUMENT_ROOT."/product.class.php"); $langs->load("products"); -// Security check +$modulepart=$_REQUEST['modulepart']?$_REQUEST['modulepart']:'produit|service'; if (isset($_GET["id"])) { $id = isset($_GET["id"])?$_GET["id"]:''; } -$result=restrictedArea($user,'produit|service',$id,'product','','',$fieldid); - - $original_file = isset($_REQUEST["file"])?urldecode($_REQUEST["file"]):''; -$langs->load("products"); - -if (!$user->rights->produit->lire) accessforbidden(); +// Security check +if ($modulepart=='produit|service') $result=restrictedArea($user,'produit|service',$id,'product','','',$fieldid); +else accessforbidden('Bad value for modulepart'); +if ($modulepart=='produit|service' && (! $user->rights->produit->lire && ! $user->rights->service->lire)) accessforbidden(); @@ -48,8 +44,8 @@ if (!$user->rights->produit->lire) accessforbidden(); if ($_POST["action"] == 'confirm_resize' && (isset($_POST["file"]) != "") && (isset($_POST["sizex"]) != "") && (isset($_POST["sizey"]) != "")) { - $fullpath=$conf->produit->dir_output."/".$_POST["file"]; - $result=dol_imageResize($fullpath,$_POST['sizex'],$_POST['sizey']); + $fullpath=$conf->produit->dir_output."/".$original_file; + $result=dol_imageResizeOrCrop($fullpath,0,$_POST['sizex'],$_POST['sizey']); if ($result == $fullpath) { @@ -65,16 +61,22 @@ if ($_POST["action"] == 'confirm_resize' && (isset($_POST["file"]) != "") && (is } // Crop d'une image -if ($_POST["action"] == 'confirm_crop' && $_POST["file"]) +if ($_POST["action"] == 'confirm_crop') { - // TODO Add function to crop image in images.lib.php -/* $thumb = new Imagick($conf->produit->dir_output."/".urldecode($_POST["file"])); - $thumb->cropImage($_POST['w'], $_POST['h'], $_POST['x'], $_POST['y']); - $thumb->writeImage($conf->produit->dir_output."/".urldecode($_POST["file"])); - $thumb->destroy(); -*/ - header("Location: ".DOL_URL_ROOT."/product/photos.php?id=".$_POST["product"].'&action=addthumb&file='.urldecode($_POST["file"])); - exit; + $fullpath=$conf->produit->dir_output."/".$original_file; + $result=dol_imageResizeOrCrop($fullpath,1,$_POST['w'],$_POST['h'],$_POST['x'],$_POST['y']); + + if ($result == $fullpath) + { + header("Location: ".DOL_URL_ROOT."/product/photos.php?id=".$_POST["product"].'&action=addthumb&file='.urldecode($_POST["file"])); + exit; + } + else + { + $mesg=$result; + $_GET['file']=$_POST["file"]; + $_GET['id']=$_POST["id"]; + } } @@ -92,17 +94,18 @@ if ($mesg) print '<div class="error">'.$mesg.'</div>'; $infoarray=dol_getImageSize($conf->produit->dir_output."/".urldecode($_GET["file"])); $height=$infoarray['height']; $width=$infoarray['width']; -print $langs->trans("Size").': </p> - <ul> +print $langs->trans("CurrentInformationOnImage").':'; +print '<ul> <li>'.$langs->trans("Width").': '.$width.' px</li> <li>'.$langs->trans("Height").': '.$height.' px</li> </ul>'; print '<br>'; -print_fiche_titre($langs->trans("Resize"),'',''); print '<form name="redim_file" action="'.$_SERVER["PHP_SELF"].'?id='.$_GET['id'].'" method="POST">'; +print '<fieldset id="redim_file">'; +print '<legend>'.$langs->trans("Resize").'</legend>'; print $langs->trans("ResizeDesc").'<br>'; print $langs->trans("NewLength").': <input class="flat" name="sizex" size="10" type="text" > px <br /> '; print $langs->trans("NewHeight").': <input class="flat" name="sizey" size="10" type="text" > px <br />'; @@ -111,16 +114,17 @@ print '<input type="hidden" name="action" value="confirm_resize" />'; print '<input type="hidden" name="product" value="'.$_GET['id'].'" />'; print '<input type="hidden" name="id" value="'.$_GET['id'].'" />'; print '<br><input class="button" name="sendit" value="'.dol_escape_htmltag($langs->trans("Resize")).'" type="submit" />'; +print '</fieldset>'; print '<br></form>'; -print '<br>'; /* * Recadrage d'une image */ print '<br>'; -print_fiche_titre($langs->trans("Recenter"),'',''); +print '<fieldset id="redim_file">'; +print '<legend>'.$langs->trans("Recenter").'</legend>'; print $langs->trans("DefineNewAreaToPick").'...<br>'; print '<br>'; print '<img style="border: 1px solid #888888;" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.$original_file.'" alt="Taille origine" id="cropbox" />'; @@ -145,6 +149,7 @@ print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$_GET['id'].'" method="post" <input type="hidden" name="id" value="'.$_GET['id'].'" /> <br><input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("Recenter")).'" /> </form>'; +print '</fieldset>'; llxFooter('$Date$ - $Revision$'); ?> \ No newline at end of file diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang index c697d2f783d313abfa5cb3841cc0bc191783b52b..27e5af34344e9baf8dd435477e82a8f474d3268a 100644 --- a/htdocs/langs/en_US/other.lang +++ b/htdocs/langs/en_US/other.lang @@ -120,6 +120,7 @@ NewLength=New width NewHeight=New height NewSizeAfterCropping=New size after cropping DefineNewAreaToPick=Define new area on image to pick (left click on image then drag until you reach the opposite corner) +CurrentInformationOnImage=Informations on current image ##### Bookmark ##### Bookmark=Bookmark diff --git a/htdocs/langs/fr_FR/other.lang b/htdocs/langs/fr_FR/other.lang index 72603482b5afd6f9d668ee4926bbee8030f7c64f..ff1cf51a3a26b99f6b2465388768c35db7135f1f 100644 --- a/htdocs/langs/fr_FR/other.lang +++ b/htdocs/langs/fr_FR/other.lang @@ -120,6 +120,7 @@ NewLength=Nouvelle largeur NewHeight=Nouvelle hauteur NewSizeAfterCropping=Nouvelles dimensions après recadrage DefineNewAreaToPick=Définissez la zone d'image à conserver (clic gauche sur l'image puis drag vers les coin opposé) +CurrentInformationOnImage=Informations courante sur l'image ##### Bookmark ##### Bookmark=Marque page diff --git a/htdocs/lib/images.lib.php b/htdocs/lib/images.lib.php index ba7276ba60bd10090731b2103c2b2b75e17d26d3..c8257ec193d545313e00eea5de9a51ae487d9b7a 100644 --- a/htdocs/lib/images.lib.php +++ b/htdocs/lib/images.lib.php @@ -26,7 +26,7 @@ /** - * \brief Return size of image file on disk + * \brief Return size of image file on disk (Supported extensions are gif, jpg, png and bmp) * \param $file Full path name of file * \return Array array('width'=>width, 'height'=>height) */ @@ -50,21 +50,23 @@ function dol_getImageSize($file) /** - * \brief Resize an image file - * \brief Supported extensions are jpg and png - * \param file Chemin du fichier image a redimensionner - * \param newWidth Largeur maximum que dois faire la miniature (-1=unchanged) - * \param newHeight Hauteur maximum que dois faire l'image (-1=unchanged) + * \brief Resize or crop an image file (Supported extensions are gif, jpg, png and bmp) + * \param file Path of file to resize/crop + * \param mode 0=Resize, 1=Crop + * \param newWidth Largeur maximum que dois faire l'image destination (0=keep ratio) + * \param newHeight Hauteur maximum que dois faire l'image destination (0=keep ratio) + * \param src_x Position of croping image in source image (not use if mode=0) + * \param src_y Position of croping image in source image (not use if mode=0) * \return int File name if OK, error message if KO * \remarks With file=myfile.jpg -> myfile_small.jpg */ -function dol_imageResize($file, $newWidth, $newHeight) +function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x=0, $src_y=0) { require_once(DOL_DOCUMENT_ROOT."/lib/functions2.lib.php"); global $conf,$langs; - dol_syslog("dol_imageResize file=".$file." newWidth=".$newWidth." newHeight=".$newHeight); + dol_syslog("dol_imageResizeOrCrop file=".$file." mode=".$mode." newWidth=".$newWidth." newHeight=".$newHeight." src_x=".$src_x." src_y=".$src_y); // Clean parameters $file=trim($file); @@ -82,14 +84,19 @@ function dol_imageResize($file, $newWidth, $newHeight) } elseif(image_format_supported($file) < 0) { - return 'This file '.$file.' does not seem to be an image format file name.'; + return 'This filename '.$file.' does not seem to be an image filename.'; } - elseif(!is_numeric($newWidth) && !is_numeric($newHeight)){ + elseif(!is_numeric($newWidth) && !is_numeric($newHeight)) + { return 'Wrong value for parameter newWidth or newHeight'; } - elseif ($newWidth <= 0 && $newHeight <= 0) + elseif ($mode == 0 && $newWidth <= 0 && $newHeight <= 0) + { + return 'At least newHeight or newWidth must be defined for resizing'; + } + elseif ($mode == 1 && ($newWidth <= 0 || $newHeight <= 0)) { - return 'At least newHeight or newWidth must be defined'; + return 'Both newHeight or newWidth must be defined for croping'; } $fichier = realpath($file); // Chemin canonique absolu de l'image @@ -99,13 +106,16 @@ function dol_imageResize($file, $newWidth, $newHeight) $imgWidth = $infoImg[0]; // Largeur de l'image $imgHeight = $infoImg[1]; // Hauteur de l'image - if ($newWidth <= 0) + if ($mode == 0) // If resize, we check parameters { - $newWidth=intval(($newHeight / $imgHeight) * $imgWidth); // Keep ratio - } - if ($newHeight <= 0) - { - $newHeight=intval(($newWidth / $imgWidth) * $imgHeight); // Keep ratio + if ($newWidth <= 0) + { + $newWidth=intval(($newHeight / $imgHeight) * $imgWidth); // Keep ratio + } + if ($newHeight <= 0) + { + $newHeight=intval(($newWidth / $imgWidth) * $imgHeight); // Keep ratio + } } $imgfonction=''; @@ -138,23 +148,23 @@ function dol_imageResize($file, $newWidth, $newHeight) { case 1: // Gif $img = imagecreatefromgif($fichier); - $extImg = '.gif'; // Extension de l'image - $newquality='NU'; + $extImg = '.gif'; // File name extension of image + $newquality='NU'; // Quality is not used for this format break; case 2: // Jpg $img = imagecreatefromjpeg($fichier); - $extImg = '.jpg'; // Extension de l'image - $newquality=100; + $extImg = '.jpg'; + $newquality=100; // % quality maximum break; case 3: // Png $img = imagecreatefrompng($fichier); $extImg = '.png'; - $newquality=10; + $newquality=0; // No compression (0-9) break; case 4: // Bmp $img = imagecreatefromwbmp($fichier); $extImg = '.bmp'; - $newquality='NU'; + $newquality='NU'; // Quality is not used for this format break; } @@ -201,9 +211,9 @@ function dol_imageResize($file, $newWidth, $newHeight) } if (function_exists("imagefill")) imagefill($imgThumb, 0, 0, $trans_colour); - dol_syslog("dol_imageResize: convert image from ($imgWidth x $imgHeight) to ($newWidth x $newHeight) as $extImg, newquality=$newquality"); + dol_syslog("dol_imageResizeOrCrop: convert image from ($imgWidth x $imgHeight) at position ($src_x x $src_y) to ($newWidth x $newHeight) as $extImg, newquality=$newquality"); //imagecopyresized($imgThumb, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imgWidth, $imgHeight); // Insere l'image de base redimensionnee - imagecopyresampled($imgThumb, $img, 0, 0, 0, 0, $newWidth, $newHeight, $imgWidth, $imgHeight); // Insere l'image de base redimensionnee + imagecopyresampled($imgThumb, $img, 0, 0, $src_x, $src_y, $newWidth, $newHeight, ($mode==0?$imgWidth:$newWidth), ($mode==0?$imgHeight:$newHeight)); // Insere l'image de base redimensionnee $imgThumbName = $file; @@ -234,13 +244,14 @@ function dol_imageResize($file, $newWidth, $newHeight) // Free memory imagedestroy($imgThumb); + clearstatcache(); // File was replaced by a modified on, so we clear file caches. + return $imgThumbName; } /** - * \brief Create a thumbnail from an image file (une small et un mini) - * \brief Les extensions prises en compte sont jpg et png + * \brief Create 2 thumbnails from an image file: one small and one mini (Supported extensions are gif, jpg, png and bmp) * \param file Chemin du fichier image a redimensionner * \param maxWidth Largeur maximum que dois faire la miniature (-1=unchanged, 160 par defaut) * \param maxHeight Hauteur maximum que dois faire l'image (-1=unchanged, 120 par defaut) diff --git a/htdocs/product.class.php b/htdocs/product.class.php index 03dea67de58796726e152826138992856b44d835..49fc19b2df4ab10949f8ac68275f9c25d70b8869 100644 --- a/htdocs/product.class.php +++ b/htdocs/product.class.php @@ -130,7 +130,7 @@ class Product extends CommonObject $this->stock_reel = 0; $this->seuil_stock_alerte = 0; $this->canvas = ''; - + if ($this->id > 0) $this->fetch($this->id); } @@ -2397,7 +2397,7 @@ class Product extends CommonObject /** * \brief Affiche toutes les photos du produit (nbmax maximum) - * \param sdir Repertoire a scanner + * \param sdir Directory to scan * \param size 0=taille origine, 1 taille vignette * \param nbmax Nombre maximum de photos (0=pas de max) * \param nbbyrow Nombre vignettes par ligne (si mode vignette) @@ -2408,6 +2408,7 @@ class Product extends CommonObject global $conf,$user,$langs; include_once(DOL_DOCUMENT_ROOT ."/lib/files.lib.php"); + include_once(DOL_DOCUMENT_ROOT ."/lib/images.lib.php"); $pdir = get_exdir($this->id,2) . $this->id ."/photos/"; $dir = $sdir . '/'. $pdir; @@ -2424,7 +2425,7 @@ class Product extends CommonObject { $photo=''; - if (! utf8_check($file)) $file=utf8_encode($file); // To be sure date is stored in UTF8 in memory + if (! utf8_check($file)) $file=utf8_encode($file); // To be sure file is stored in UTF8 in memory if (dol_is_file($dir.$file)) { @@ -2440,20 +2441,28 @@ class Product extends CommonObject if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette=''; } + // Get filesize of original file + $imgarray=dol_getImageSize($dir.$photo); if ($nbbyrow && $nbphoto == 1) print '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">'; if ($nbbyrow && ($nbphoto % $nbbyrow == 1)) print '<tr align=center valign=middle border=1>'; if ($nbbyrow) print '<td width="'.ceil(100/$nbbyrow).'%" class="photo">'; - print '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.urlencode($pdir.$photo).'" alt="Taille origine" target="_blank">'; + print "\n"; + print '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.urlencode($pdir.$photo).'" target="_blank">'; - // Si fichier vignette disponible, on l'utilise, sinon on utilise photo origine - if ($photo_vignette) { - print '<img class="photo" border="0" height="120" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.urlencode($pdirthumb.$photo_vignette).'">'; + // Show image (width height=120) + // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine + $alt=$langs->transnoentitiesnoconv('File').': '.$pdir.$photo; + $alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height']; + if ($photo_vignette && $imgarray['height'] > 120) { + print '<!-- Show thumb -->'; + print '<img class="photo" border="0" height="120" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.urlencode($pdirthumb.$photo_vignette).'" title="'.dol_escape_htmltag($alt).'">'; } else { - print '<img class="photo" border="0" height="120" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.urlencode($pdir.$photo).'">'; + print '<!-- Show original file -->'; + print '<img class="photo" border="0" height="120" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=product&file='.urlencode($pdir.$photo).'" title="'.dol_escape_htmltag($alt).'">'; } print '</a>'; @@ -2477,6 +2486,7 @@ class Product extends CommonObject print img_delete().'</a>'; } } + print "\n"; if ($nbbyrow) print '</td>'; if ($nbbyrow && ($nbphoto % $nbbyrow == 0)) print '</tr>'; @@ -2491,7 +2501,11 @@ class Product extends CommonObject { if ($user->rights->produit->creer || $user->rights->service->creer) { - print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$_GET["id"].'&action=delete&file='.urlencode($pdir.$viewfilename).'">'; + // Link to resize + print '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?id='.$_GET["id"].'&file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"),DOL_URL_ROOT.'/theme/common/transform-crop-and-resize','',1).'</a> '; + + // Link to delete + print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$_GET["id"].'&action=delete&file='.urlencode($pdir.$viewfilename).'">'; print img_delete().'</a>'; } }