Index: helpers/image_helper.php =================================================================== --- helpers/image_helper.php (revision 13557) +++ helpers/image_helper.php (working copy) @@ -46,9 +46,22 @@ } elseif (preg_match('/fill:(.*)/', $format_part, $regs)) { $res['fill'] = $regs[1]; - } elseif (preg_match('/default:(.*)/', $format_part, $regs)) { + } + elseif ($format_part == 'grayscale') { + $res['grayscale'] = true; + } + elseif (preg_match('/corner_radius:(\d*)/', $format_part, $regs)) { + $res['corner_radius'] = strtolower($regs[1]); + } + elseif (preg_match('/ellipse_radius:(.*)/', $format_part, $regs)) { + $res['ellipse_radius'] = strtolower($regs[1]); + } + elseif (preg_match('/default:(.*)/', $format_part, $regs)) { $res['default'] = FULL_PATH.THEMES_PATH.'/'.$regs[1]; } + else { + trigger_error('Unknown format part "' . $format_part . '".', E_USER_ERROR); + } } return $res; @@ -96,7 +109,7 @@ } $src_path = dirname($src_image); - $transform_keys = Array ('crop_x', 'crop_y', 'fill', 'wm_filename'); + $transform_keys = Array ('crop_x', 'crop_y', 'fill', 'wm_filename', 'grayscale', 'corner_radius', 'ellipse_radius'); if ($needs_resize || array_intersect(array_keys($params), $transform_keys)) { // resize required OR watermarking required -> change resulting image name ! @@ -191,7 +204,24 @@ $watermark_size = 'max'; } - // 3. apply watermark + // 3. make circled + if (array_key_exists('ellipse_radius', $params)) { + $fill_color = array_key_exists('fill', $params) ? $params['fill'] : '#FFFFFF'; + $this->_makeEllipse($dst_image_rs, $params['ellipse_radius'], $fill_color); + } + + // 4. make rounded corners + if (array_key_exists('corner_radius', $params)) { + $fill_color = array_key_exists('fill', $params) ? $params['fill'] : '#FFFFFF'; + $this->_makeRoundedCorners($dst_image_rs, $params['corner_radius'], $fill_color); + } + + // 5. apply grayscale + if (array_key_exists('grayscale', $params)) { + $this->_applyGrayscale($dst_image_rs); + } + + // 6. apply watermark $dst_image_rs =& $this->_applyWatermark($dst_image_rs, $params[$watermark_size . '_width'], $params[$watermark_size . '_height'], $params); if ($write_function == 'imagegif') { @@ -212,6 +242,163 @@ } /** + * Makes rounded corners + * + * @param resource $src_image_rs + * @param int $radius + * @param string $fill_color + */ + function _makeRoundedCorners(&$src_image_rs, $radius, $fill_color) + { + $fill_color = $this->_colorFromString($fill_color); + + if ($fill_color === false) { + return false; + } + + $source_width = imagesx($src_image_rs); + $source_height = imagesy($src_image_rs); + $mask_image_rs =& $this->getMaskImage($radius, $radius, $fill_color); + $transparent_color = imagecolorallocate($mask_image_rs, 255 - $fill_color[0], 255 - $fill_color[1], 255 - $fill_color[2]); + + // create mask ellipse image for top-left corner in memory + imagefilledellipse($mask_image_rs, $radius, $radius, $radius * 2, $radius * 2, $transparent_color); + + // render top-left corner by copying the mask + imagecopymerge($src_image_rs, $mask_image_rs, 0, 0, 0, 0, $radius, $radius, 100); + + // render bottom-left corner by rotating and copying the mask + $mask_image = imagerotate($mask_image_rs, 90, 0); + imagecopymerge($src_image_rs, $mask_image_rs, 0, $source_height - $radius, 0, 0, $radius, $radius, 100); + + // render bottom-right corner by rotating and copying the mask + $mask_image = imagerotate($mask_image_rs, 90, 0); + imagecopymerge($src_image_rs, $mask_image_rs, $source_width - $radius, $source_height - $radius, 0, 0, $radius, $radius, 100); + + // render top-right corner by rotating and copying the mask + $mask_image = imagerotate($mask_image_rs, 90, 0); + imagecopymerge($src_image_rs, $mask_image_rs, $source_width - $radius, 0, 0, 0, $radius, $radius, 100); + } + + /** + * Make circled or ellipsed image + * + * @param resource $src_image_rs + * @param string $radius + * @param string $fill_color + */ + function _makeEllipse(&$src_image_rs, $radius, $fill_color) + { + $fill_color = $this->_colorFromString($fill_color); + + if ($fill_color === false) { + return false; + } + + $source_width = imagesx($src_image_rs); + $source_height = imagesy($src_image_rs); + $mask_image_rs =& $this->getMaskImage($source_width, $source_height, $fill_color); + $transparent_color = imagecolorallocate($mask_image_rs, 255 - $fill_color[0], 255 - $fill_color[1], 255 - $fill_color[2]); + + // process case when different/same radius for X and Y axis used + if (strpos($radius, 'x') !== false) { + list ($x_radius, $y_radius) = explode('x', $radius, 2); + } + else { + $x_radius = $y_radius = $radius; + } + + // -1 pixel for better circle results + if (substr($x_radius, -1) == '%') { + $x_radius = min( (int)substr($x_radius, 0, -1), 100 ); + $x_radius = floor($source_width * ($x_radius / 100) - 1); + } + + if (substr($y_radius, -1) == '%') { + $y_radius = min( (int)substr($y_radius, 0, -1), 100 ); + $y_radius = floor($source_height * ($y_radius / 100) - 1); + } + + // create mask ellipse image + imagefilledellipse($mask_image_rs, floor($source_width / 2), floor($source_height / 2), $x_radius, $y_radius, $transparent_color); + + // copying the mask over the source image + imagecopymerge($src_image_rs, $mask_image_rs, 0, 0, 0, 0, $source_width, $source_height, 100); + } + + /** + * Returns RGB component of given color string + * + * @param string $string + * @return Array + */ + function _colorFromString($string) + { + if (preg_match('/^#(.*){2}(.*){2}(.*){2}$/', $string, $regs)) { + array_shift($regs); + return array_map('hexdec', $regs); + } + + return false; + } + + /** + * Returns mask image if given size and color + * + * @param int $width + * @param int $height + * @param Array $color + * @return resource + */ + function &getMaskImage($width, $height, $color) + { + // create mask image + $mask_image_rs = imagecreatetruecolor($width, $height); + imageantialias($mask_image_rs, true); + + // define fill and transparent colors + $fill_color = imagecolorallocate($mask_image_rs, $color[0], $color[1], $color[2]); + $transparent_color = imagecolorallocate($mask_image_rs, 255 - $color[0], 255 - $color[1], 255 - $color[2]); + + imagecolortransparent($mask_image_rs, $transparent_color); + imagefill($mask_image_rs, 0, 0, $fill_color); + + return $mask_image_rs; + } + + /** + * Converts image to grayscale + * + * @param resource $src_image_rs resized image resource + */ + function _applyGrayscale(&$src_image_rs) + { + $width = imagesx($src_image_rs); + $height = imagesy($src_image_rs); + + for ($i = 0; $i < $width; $i++) { + for ($j = 0; $j < $height; $j++) { + // get the rgb value for current pixel + $rgb = imagecolorat($src_image_rs, $i, $j); + + // extract each value for r, g, b + $rr = ($rgb >> 16) & 0xFF; + $gg = ($rgb >> 8) & 0xFF; + $bb = $rgb & 0xFF; + + // get the Value from the RGB value + $g = round(($rr + $gg + $bb) / 3); + + // grayscale values have r=g=b=g + $val = imagecolorallocate($src_image_rs, $g, $g, $g); + + // set the gray value + imagesetpixel($src_image_rs, $i, $j, $val); + } + } + } + + /** * Preserve transparency for GIF and PNG images * * @param resource $src_image_rs @@ -275,15 +462,15 @@ $fill = $params['fill']; - if (substr($fill, 0, 1) == '#') { - // hexdecimal color - $color = imagecolorallocate($fill_image_rs, hexdec( substr($fill, 1, 2) ), hexdec( substr($fill, 3, 2) ), hexdec( substr($fill, 5, 2) )); - } - else { + $color = $this->_colorFromString($fill); + + if ($color === false) { // for now we don't support color names, but we will in future return $src_image_rs; } + $color = imagecolorallocate($fill_image_rs, $color[0], $color[1], $color[2]); + imagefill($fill_image_rs, 0, 0, $color); imagecopy($fill_image_rs, $src_image_rs, $x_position, $y_position, 0, 0, $params['target_width'], $params['target_height']); Index: images/image_tag_processor.php =================================================================== --- images/image_tag_processor.php (revision 13557) +++ images/image_tag_processor.php (working copy) @@ -339,6 +339,24 @@ $max_height = null; } + $grayscale = $this->SelectParam($params, 'Grayscale,grayscale'); + if ($grayscale) { + $max_width = (is_null($max_height) ? $max_width : $resize_format) . ';grayscale'; + $max_height = null; + } + + $corner_radius = $this->SelectParam($params, 'CornerRadius,corner_radius'); + if ($corner_radius) { + $max_width = (is_null($max_height) ? $max_width : $resize_format) . ';corner_radius:' . $corner_radius; + $max_height = null; + } + + $ellipse_radius = $this->SelectParam($params, 'EllipseRadius,ellipse_radius'); + if ($ellipse_radius) { + $max_width = (is_null($max_height) ? $max_width : $resize_format) . ';ellipse_radius:' . $ellipse_radius; + $max_height = null; + } + return Array ($max_width, $max_height); }