From ced34cb15e095836767971aa4d27b141fb1d7ec9 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Sat, 18 Oct 2014 08:47:54 -0400 Subject: [PATCH] Merge pull request #230 from bytesatwork-xx/master --- program/lib/Roundcube/rcube_image.php | 244 ++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 194 insertions(+), 50 deletions(-) diff --git a/program/lib/Roundcube/rcube_image.php b/program/lib/Roundcube/rcube_image.php index ad96842..d0d0c74 100644 --- a/program/lib/Roundcube/rcube_image.php +++ b/program/lib/Roundcube/rcube_image.php @@ -77,7 +77,8 @@ } /** - * Resize image to a given size + * Resize image to a given size. Use only to shrink an image. + * If an image is smaller than specified size it will be not resized. * * @param int $size Max width/height size * @param string $filename Output filename @@ -92,16 +93,19 @@ $convert = $rcube->config->get('im_convert_path', false); $props = $this->props(); + if (empty($props)) { + return false; + } + if (!$filename) { $filename = $this->image_file; } // use Imagemagick - if ($convert) { - $p['out'] = $filename; - $p['in'] = $this->image_file; - $p['size'] = $size.'x'.$size; - $type = $props['type']; + if ($convert || class_exists('Imagick', false)) { + $p['out'] = $filename; + $p['in'] = $this->image_file; + $type = $props['type']; if (!$type && ($data = $this->identify())) { $type = $data[0]; @@ -115,62 +119,146 @@ $type = 'jpg'; } - $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); - $p['-opts'] = array('-resize' => $p['size'].'>'); + // If only one dimension is greater than the limit convert doesn't + // work as expected, we need to calculate new dimensions + $scale = $size / max($props['width'], $props['height']); - if (in_array($type, explode(',', $p['types']))) { // Valid type? - $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {intype}:{in} {type}:{out}', $p); + // if file is smaller than the limit, we do nothing + // but copy original file to destination file + if ($scale >= 1 && $p['intype'] == $type) { + $result = ($this->image_file == $filename || copy($this->image_file, $filename)) ? '' : false; + } + else { + $valid_types = "bmp,eps,gif,jp2,jpg,png,svg,tif"; + + if (in_array($type, explode(',', $valid_types))) { // Valid type? + if ($scale >= 1) { + $width = $props['width']; + $height = $props['height']; + } + else { + $width = intval($props['width'] * $scale); + $height = intval($props['height'] * $scale); + } + + // use ImageMagick in command line + if ($convert) { + $p += array( + 'type' => $type, + 'quality' => 75, + 'size' => $width . 'x' . $height, + ); + + $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace sRGB -strip' + . ' -quality {quality} -resize {size} {intype}:{in} {type}:{out}', $p); + } + // use PHP's Imagick class + else { + try { + $image = new Imagick($this->image_file); + $image = $image->flattenImages(); + + $image->setImageColorspace(Imagick::COLORSPACE_SRGB); + $image->setImageCompressionQuality(75); + $image->setImageFormat($type); + $image->stripImage(); + $image->scaleImage($width, $height); + + if ($image->writeImage($filename)) { + $result = ''; + } + } + catch (Exception $e) { + rcube::raise_error($e, true, false); + } + } + } } if ($result === '') { + @chmod($filename, 0600); return $type; } } // 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) { + if ($props['gd_type']) { + if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) { $image = imagecreatefromjpeg($this->image_file); + $type = 'jpg'; } - elseif($props['gd_type'] == IMAGETYPE_GIF) { + else if($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) { $image = imagecreatefromgif($this->image_file); + $type = 'gif'; } - elseif($props['gd_type'] == IMAGETYPE_PNG) { + else if($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) { $image = imagecreatefrompng($this->image_file); + $type = 'png'; + } + else { + // @TODO: print error to the log? + return false; } - $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); + if ($image === false) { + return false; } - imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']); - $image = $new_image; + $scale = $size / max($props['width'], $props['height']); - if ($props['gd_type'] == IMAGETYPE_JPEG) { - $result = imagejpeg($image, $filename, 75); - $type = 'jpg'; + // Imagemagick resize is implemented in shrinking mode (see -resize argument above) + // we do the same here, if an image is smaller than specified size + // we do nothing but copy original file to destination file + if ($scale >= 1) { + $result = $this->image_file == $filename || copy($this->image_file, $filename); } - elseif($props['gd_type'] == IMAGETYPE_GIF) { - $result = imagegif($image, $filename); - $type = 'gid'; - } - elseif($props['gd_type'] == IMAGETYPE_PNG) { - $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); - $type = 'png'; + else { + $width = intval($props['width'] * $scale); + $height = intval($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; + + // fix rotation of image if EXIF data exists and specifies rotation (GD strips the EXIF data) + if ($this->image_file && function_exists('exif_read_data')) { + $exif = exif_read_data($this->image_file); + if ($exif && $exif['Orientation']) { + switch ($exif['Orientation']) { + case 3: + $image = imagerotate($image, 180, 0); + break; + case 6: + $image = imagerotate($image, -90, 0); + break; + case 8: + $image = imagerotate($image, 90, 0); + break; + } + } + } + + 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) { + @chmod($filename, 0600); return $type; } } @@ -202,32 +290,56 @@ } } - // use ImageMagick + // use ImageMagick in command line if ($convert) { $p['in'] = $this->image_file; $p['out'] = $filename; $p['type'] = self::$extensions[$type]; - $result = rcube::exec($convert . ' 2>&1 -colorspace RGB -quality 75 {in} {type}:{out}', $p); + $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -quality 75 {in} {type}:{out}', $p); if ($result === '') { + chmod($filename, 0600); return true; } } - // use GD extension (TIFF isn't supported) - $props = $this->props(); - $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); + // use PHP's Imagick class + if (class_exists('Imagick', false)) { + try { + $image = new Imagick($this->image_file); - if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) { - if ($props['gd_type'] == IMAGETYPE_JPEG) { + $image->setImageColorspace(Imagick::COLORSPACE_SRGB); + $image->setImageCompressionQuality(75); + $image->setImageFormat(self::$extensions[$type]); + $image->stripImage(); + + if ($image->writeImage($filename)) { + @chmod($filename, 0600); + return true; + } + } + catch (Exception $e) { + rcube::raise_error($e, true, false); + } + } + + // use GD extension (TIFF isn't supported) + $props = $this->props(); + + if ($props['gd_type']) { + if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) { $image = imagecreatefromjpeg($this->image_file); } - else if ($props['gd_type'] == IMAGETYPE_GIF) { + else if ($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) { $image = imagecreatefromgif($this->image_file); } - else if ($props['gd_type'] == IMAGETYPE_PNG) { + else if ($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) { $image = imagecreatefrompng($this->image_file); + } + else { + // @TODO: print error to the log? + return false; } if ($type == self::TYPE_JPG) { @@ -239,6 +351,11 @@ else if ($type == self::TYPE_PNG) { $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); } + + if ($result) { + @chmod($filename, 0600); + return true; + } } // @TODO: print error to the log? @@ -246,12 +363,26 @@ } /** - * Identify command handler. + * Checks if image format conversion is supported + * + * @return boolean True if specified format can be converted to another format + */ + public static function is_convertable($mimetype = null) + { + $rcube = rcube::get_instance(); + + // @TODO: check if specified mimetype is really supported + return class_exists('Imagick', false) || $rcube->config->get('im_convert_path'); + } + + /** + * ImageMagick based image properties read. */ private function identify() { $rcube = rcube::get_instance(); + // use ImageMagick in command line if ($cmd = $rcube->config->get('im_identify_path')) { $args = array('in' => $this->image_file, 'format' => "%m %[fx:w] %[fx:h]"); $id = rcube::exec($cmd. ' 2>/dev/null -format {format} {in}', $args); @@ -260,6 +391,19 @@ return explode(' ', strtolower($id)); } } - } + // use PHP's Imagick class + if (class_exists('Imagick', false)) { + try { + $image = new Imagick($this->image_file); + + return array( + strtolower($image->getImageFormat()), + $image->getImageWidth(), + $image->getImageHeight(), + ); + } + catch (Exception $e) {} + } + } } -- Gitblit v1.9.1