diff options
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | program/include/rcmail.php | 60 | ||||
-rw-r--r-- | program/include/rcube_image.php | 165 | ||||
-rw-r--r-- | program/steps/addressbook/upload_photo.inc | 18 |
4 files changed, 175 insertions, 69 deletions
@@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Image resize with GD extension (#1488383) - Fix lack of warning when switching task in compose window (#1488399) - Fix bug where it wasn't possible to enter ( or & characters in autocomplete fields - Request all needed fields from address book backends (#1488394) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 05cfefa06..6320e5e3f 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1537,66 +1537,6 @@ class rcmail /** - * Use imagemagick or GD lib to read image properties - * - * @param string Absolute file path - * @return mixed Hash array with image props like type, width, height or False on error - */ - public static function imageprops($filepath) - { - $rcmail = rcmail::get_instance(); - if ($cmd = $rcmail->config->get('im_identify_path', false)) { - list(, $type, $size) = explode(' ', strtolower(rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath)))); - if ($size) - list($width, $height) = explode('x', $size); - } - else if (function_exists('getimagesize')) { - $imsize = @getimagesize($filepath); - $width = $imsize[0]; - $height = $imsize[1]; - $type = preg_replace('!image/!', '', $imsize['mime']); - } - - return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false; - } - - - /** - * Convert an image to a given size and type using imagemagick (ensures input is an image) - * - * @param $p['in'] Input filename (mandatory) - * @param $p['out'] Output filename (mandatory) - * @param $p['size'] Width x height of resulting image, e.g. "160x60" - * @param $p['type'] Output file type, e.g. "jpg" - * @param $p['-opts'] Custom command line options to ImageMagick convert - * @return Success of convert as true/false - */ - public static function imageconvert($p) - { - $result = false; - $rcmail = rcmail::get_instance(); - $convert = $rcmail->config->get('im_convert_path', false); - $identify = $rcmail->config->get('im_identify_path', false); - - // imagemagick is required for this - if (!$convert) - return false; - - if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false)))) - list(, $type) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps - - $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps")); - $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); - $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts']; - - if (in_array($type, explode(',', $p['types']))) # Valid type? - $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === ""; - - return $result; - } - - - /** * Construct shell command, execute it and return output as string. * Keywords {keyword} are replaced with arguments * diff --git a/program/include/rcube_image.php b/program/include/rcube_image.php new file mode 100644 index 000000000..9fe15fe54 --- /dev/null +++ b/program/include/rcube_image.php @@ -0,0 +1,165 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/rcube_image.php | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2005-2012, The Roundcube Dev Team | + | Copyright (C) 2011-2012, Kolab Systems AG | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Image resizer | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +class rcube_image +{ + private $image_file; + + function __construct($filename) + { + $this->image_file = $filename; + } + + /** + * Get image properties. + * + * @return mixed Hash array with image props like type, width, height + */ + public function props() + { + $rcmail = rcmail::get_instance(); + + if (function_exists('getimagesize') && ($imsize = @getimagesize($this->image_file))) { + $width = $imsize[0]; + $height = $imsize[1]; + $gd_type = $imsize['2']; + $type = image_type_to_extension($imsize['2'], false); + } + + if (!$type && ($cmd = $rcmail->config->get('im_identify_path', false))) { + $id = rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $this->image_file)); + list(, $type, $size) = explode(' ', strtolower($id)); + if ($size) { + list($width, $height) = explode('x', $size); + } + } + + if ($type) { + return array( + 'type' => $type, + 'gd_type' => $gd_type, + 'width' => $width, + 'height' => $height, + ); + } + } + + + /** + * Resize image to a given size + * + * @param int $size Max width/height size + * @param string $filename Output filename + * + * @return Success of convert as true/false + */ + public function resize($size, $filename = null) + { + $result = false; + $rcmail = rcmail::get_instance(); + $convert = $rcmail->config->get('im_convert_path', false); + $identify = $rcmail->config->get('im_identify_path', false); + $props = $this->props(); + + if (!$filename) { + $filename = $this->image_file; + } + + // use Imagemagick + if ($convert) { + $p['out'] = $filename; + $p['in'] = $this->image_file; + $p['size'] = $size.'x'.$size; + $p['type'] = $type = $props['type']; + + if (!$type) { + list(, $p['type']) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); // for things like eps + } + + $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps")); + $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); + $p['-opts'] = array('-resize' => $size.'>'); + + if (in_array($type, explode(',', $p['types']))) { // Valid type? + $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === ''; + } + + if ($result) { + return true; + } + } + + // use GD extension + $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); + if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) { + if ($props['gd_type'] == IMAGETYPE_JPEG) { + $image = imagecreatefromjpeg($this->image_file); + } + elseif($props['gd_type'] == IMAGETYPE_GIF) { + $image = imagecreatefromgif($this->image_file); + } + elseif($props['gd_type'] == IMAGETYPE_PNG) { + $image = imagecreatefrompng($this->image_file); + } + + $scale = $size / max($props['width'], $props['height']); + $width = $props['width'] * $scale; + $height = $props['height'] * $scale; + + $new_image = imagecreatetruecolor($width, $height); + + // Fix transparency of gif/png image + if ($props['gd_type'] != IMAGETYPE_JPEG) { + imagealphablending($new_image, false); + imagesavealpha($new_image, true); + $transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127); + imagefilledrectangle($new_image, 0, 0, $width, $height, $transparent); + } + + imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']); + $image = $new_image; + + if ($props['gd_type'] == IMAGETYPE_JPEG) { + $result = imagejpeg($image, $filename, 75); + } + elseif($props['gd_type'] == IMAGETYPE_GIF) { + $result = imagegif($image, $filename); + } + elseif($props['gd_type'] == IMAGETYPE_PNG) { + $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); + } + + if ($result) { + return true; + } + } + + + // @TODO: print error to the log? + return false; + } + +} diff --git a/program/steps/addressbook/upload_photo.inc b/program/steps/addressbook/upload_photo.inc index 039a7b202..195bac563 100644 --- a/program/steps/addressbook/upload_photo.inc +++ b/program/steps/addressbook/upload_photo.inc @@ -31,20 +31,19 @@ $OUTPUT->reset(); if ($filepath = $_FILES['_photo']['tmp_name']) { // check file type and resize image - $imageprop = rcmail::imageprops($_FILES['_photo']['tmp_name']); + $image = new rcube_image($_FILES['_photo']['tmp_name']); + $imageprop = $image->props(); if (in_array(strtolower($imageprop['type']), $IMAGE_TYPES) - && $imageprop['width'] && $imageprop['height'] + && $imageprop['width'] && $imageprop['height'] ) { - $maxsize = intval($RCMAIL->config->get('contact_photo_size', 160)); - $tmpfname = tempnam($RCMAIL->config->get('temp_dir'), 'rcmImgConvert'); + $maxsize = intval($RCMAIL->config->get('contact_photo_size', 160)); + $tmpfname = tempnam($RCMAIL->config->get('temp_dir'), 'rcmImgConvert'); $save_hook = 'attachment_upload'; // scale image to a maximum size - if (($imageprop['width'] > $maxsize || $imageprop['height'] > $maxsize) && - (rcmail::imageconvert(array('in' => $filepath, 'out' => $tmpfname, - 'size' => $maxsize.'x'.$maxsize, 'type' => $imageprop['type'])) !== false)) { - $filepath = $tmpfname; + if (($imageprop['width'] > $maxsize || $imageprop['height'] > $maxsize) && $image->resize($maxsize, $tmpfname)) { + $filepath = $tmpfname; $save_hook = 'attachment_save'; } @@ -57,8 +56,9 @@ if ($filepath = $_FILES['_photo']['tmp_name']) { 'group' => 'contact', )); } - else + else { $attachment['error'] = rcube_label('invalidimageformat'); + } if ($attachment['status'] && !$attachment['abort']) { $file_id = $attachment['id']; |