*/
protected $_logger;
- // @TODO: width/height should be protected since they aren't reliable
- // (should use ::getDimensions()) but we need a way to set them
- // to zero from Effects... leaving public until a clearGeometry()
- // method is implemented.
/**
* The current width of the image data.
*
* @var integer
*/
- public $_width = 0;
+ protected $_width = 0;
/**
* The current height of the image data.
*
* @var integer
*/
- public $_height = 0;
+ protected $_height = 0;
/**
* A directory for temporary files.
*/
public function apply()
{
- if (!is_null($this->_image->_imagick)) {
- $this->_image->_imagick->borderImage(
- $this->_params['bordercolor'],
- $this->_params['borderwidth'],
- $this->_params['borderwidth']);
- } else {
- $this->_image->addPostSrcOperation(sprintf(
- " -bordercolor \"%s\" %s -border %s",
- $this->_params['bordercolor'],
- (!empty($this->_params['preserve']) ? '-compose Copy' : ''),
- $this->_params['borderwidth']));
- }
-
+ $this->_image->addPostSrcOperation(sprintf(
+ " -bordercolor \"%s\" %s -border %s",
+ $this->_params['bordercolor'],
+ (!empty($this->_params['preserve']) ? '-compose Copy' : ''),
+ $this->_params['borderwidth']));
return true;
}
*/
public function apply()
{
- $this->_image->_imagick = null;
- if (!is_null($this->_image->_imagick)) {
- foreach ($this->_params['images'] as $image) {
- $topimg = new Horde_Image_ImagickProxy();
- $topimg->clear();
- $topimg->readImageBlob($image->raw());
-
- /* Calculate center for composite (gravity center)*/
- $geometry = $this->_image->_imagick->getImageGeometry();
- $x = $geometry['width'] / 2;
- $y = $geometry['height'] / 2;
-
- if (isset($this->_params['x']) && isset($this->_params['y'])) {
- $x = $this->_params['x'];
- $y = $this->_params['y'];
- }
- $this->_image->_imagick->compositeImage($topimg, constant('Imagick::COMPOSITE_OVER'), $x, $y);
- }
- } else {
- $ops = $geometry = $gravity = '';
- if (isset($this->_params['gravity'])) {
- $gravity = ' -gravity ' . $this->_params['gravity'];
- }
+ $ops = $geometry = $gravity = '';
+ if (isset($this->_params['gravity'])) {
+ $gravity = ' -gravity ' . $this->_params['gravity'];
+ }
- if (isset($this->_params['x']) && isset($this->_params['y'])) {
- $geometry = ' -geometry +' . $this->_params['x'] . '+' . $this->_params['y'] . ' ';
- }
- if (isset($this->_params['compose'])) {
- // The -matte ensures that the destination (background) image
- // has an alpha channel - to avoid black holes in the image.
- $compose = ' -compose ' . $this->_params['compose'] . ' -matte';
- }
+ if (isset($this->_params['x']) && isset($this->_params['y'])) {
+ $geometry = ' -geometry +' . $this->_params['x'] . '+' . $this->_params['y'] . ' ';
+ }
+ if (isset($this->_params['compose'])) {
+ // The -matte ensures that the destination (background) image
+ // has an alpha channel - to avoid black holes in the image.
+ $compose = ' -compose ' . $this->_params['compose'] . ' -matte';
+ }
- foreach($this->_params['images'] as $image) {
- $temp = $image->toFile();
- $this->_image->addFileToClean($temp);
- $ops .= ' ' . $temp . $gravity . $compose . ' -composite';
- }
- $this->_image->addOperation($geometry);
- $this->_image->addPostSrcOperation($ops);
+ foreach($this->_params['images'] as $image) {
+ $temp = $image->toFile();
+ $this->_image->addFileToClean($temp);
+ $ops .= ' ' . $temp . $gravity . $compose . ' -composite';
}
+ $this->_image->addOperation($geometry);
+ $this->_image->addPostSrcOperation($ops);
+
return true;
}
*/
public function apply()
{
- if (!is_null($this->_image->_imagick)) {
- // $shadow is_a ImagickProxy object
- $shadow = $this->_image->_imagick->cloneIM();
- $shadow->setImageBackgroundColor('black');
- $shadow->shadowImage(80, $this->_params['fade'],
- $this->_params['distance'],
- $this->_params['distance']);
-
-
- // If we have an actual background color, we need to explicitly
- // create a new background image with that color to be sure there
- // *is* a background color.
- if ($this->_params['background'] != 'none') {
- $size = $shadow->getImageGeometry();
- $new = new Horde_Image_ImagickProxy($size['width'],
- $size['height'],
- $this->_params['background'],
- $this->_image->getType());
-
- $new->compositeImage($shadow,
- constant('Imagick::COMPOSITE_OVER'), 0, 0);
- $shadow->clear();
- $shadow->addImage($new);
- $new->destroy();
- }
-
- if ($this->_params['padding']) {
- $shadow->borderImage($this->_params['background'],
- $this->_params['padding'],
- $this->_params['padding']);
- }
- $shadow->compositeImage($this->_image->_imagick,
- constant('Imagick::COMPOSITE_OVER'),
- 0, 0);
- $this->_image->_imagick->clear();
- $this->_image->_imagick->addImage($shadow);
- $shadow->destroy();
- } else {
- $size = $this->_image->getDimensions();
-// $this->_image->addPostSrcOperation("-size {$size['width']}x{$size['height']} xc:{$this->_params['background']} "
-// . "-fill {$this->_params['background']} -draw \"matte 0,0 reset\"");
- $this->_image->addPostSrcOperation('\( +clone -background black -shadow 80x' . $this->_params['fade'] . '+' . $this->_params['distance'] . '+' . $this->_params['distance'] . ' \) +swap -background none -flatten +repage -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
- }
- $this->_image->_width = 0;
- $this->_image->_height = 0;
+ $size = $this->_image->getDimensions();
+ $this->_image->addPostSrcOperation('\( +clone -background black -shadow 80x' . $this->_params['fade'] . '+' . $this->_params['distance'] . '+' . $this->_params['distance'] . ' \) +swap -background none -flatten +repage -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
+ $this->_image->clearGeometry();
return true;
}
$i = 1;
$cnt = count($this->_params['images']);
if ($cnt <=0) {
- return PEAR::raiseError('No images provided');
+ throw new Horde_Image_Exception('No Images provided.');
}
- if (!is_null($this->_image->_imagick) &&
- $this->_image->_imagick->methodExists('polaroidImage') &&
- $this->_image->_imagick->methodExists('trimImage')) {
- $imgs = array();
- $length = 0;
+ // Start out fresh.
+ $this->_image->raw();
+
+ switch ($this->_params['type']) {
+ case 'plain':
+ case 'rounded':
+ // Get top image dimensions, then force each bottom image to the
+ // same dimensions.
+ $this->_params['images'][$cnt - 1]->resize($this->_params['resize_height'],
+ $this->_params['resize_height'],
+ true);
+ $size = $this->_params['images'][$cnt - 1]->getDimensions();
+ //$this->_image->resize(2 * $this->_params['resize_height'], 2 * $this->_params['resize_height']);
+ for ($i = 0; $i < $cnt; $i++) {
+ $this->_params['images'][$i]->resize($size['height'], $size['width'], false);
+ }
+ $xo = $yo = (count($this->_params['images']) + 1) * $this->_params['offset'];
+ $ops = '';
+ $haveBottom = false;
+ foreach ($this->_params['images'] as $image) {
+ $xo -= $this->_params['offset'];
+ $yo -= $this->_params['offset'];
- switch ($this->_params['type']) {
- case 'plain':
- case 'rounded':
- $haveBottom = false;
- // First, we need to resize the top image to get the dimensions
- // for the rest of the stack.
- $topimg = new Horde_Image_ImagickProxy();
- $topimg->clear();
- $topimg->readImageBlob($this->_params['images'][$cnt - 1]->raw());
- $topimg->thumbnailImage(
- $this->_params['resize_height'],
- $this->_params['resize_height'],
- true);
if ($this->_params['type'] == 'rounded') {
- $topimg = $this->_roundBorder($topimg);
+ $temp = $this->_roundBorder($image);
+ } else {
+ $temp = $image->toFile();
}
+ $this->_image->addFileToClean($temp);
+ $ops .= ' \( ' . $temp . ' -background none -thumbnail ' . $size['width'] . 'x' . $size['height'] . '! -repage +' . $xo . '+' . $yo . ($this->_params['type'] == 'plain' ? ' -bordercolor "#333" -border 1 ' : ' ' ) . ((!$haveBottom) ? '\( +clone -shadow 80x4+0+0 \) +swap -mosaic' : '') . ' \) ';
+ $haveBottom = true;
+ }
- $size = $topimg->getImageGeometry();
- foreach ($this->_params['images'] as $image) {
- $imgk= new Horde_Image_ImagickProxy();
- $imgk->clear();
- $imgk->readImageBlob($image->raw());
- if ($i++ <= $cnt) {
- $imgk->thumbnailImage($size['width'], $size['height'],
- false);
- } else {
- $imgk->destroy();
- $imgk = $topimg->cloneIM();
- }
+ // The first -background none option below is only honored in
+ // convert versions before 6.4 it seems. Without it specified as
+ // none here, all stacks come out with a white background.
+ $this->_image->addPostSrcOperation($ops . ' -background ' . $this->_params['background'] . ' -mosaic -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
- if ($this->_params['type'] == 'rounded') {
- $imgk = $this->_roundBorder($imgk);
- } else {
- $imgk->borderImage($this->_params['bordercolor'], 1, 1);
- }
- // Only shadow the bottom image for 'plain' stacks
- if (!$haveBottom) {
- $shad = $imgk->cloneIM();
- $shad->setImageBackgroundColor('black');
- $shad->shadowImage(80, 4, 0, 0);
- $shad->compositeImage($imgk,
- constant('Imagick::COMPOSITE_OVER'),
- 0, 0);
- $imgk->clear();
- $imgk->addImage($shad);
- $shad->destroy();
- $haveBottom = true;
- }
- // Get the geometry of the image and remember the largest.
- $geo = $imgk->getImageGeometry();
- $length = max(
- $length,
- sqrt(pow($geo['height'], 2) + pow($geo['width'], 2)));
+ break;
- $imgs[] = $imgk;
- }
- break;
- case 'polaroid':
+ case 'polaroid':
+ // Check for im version > 6.3.2
+ $ver = $this->_image->getIMVersion();
+ if (is_array($ver) && version_compare($ver[0], '6.3.2') >= 0) {
+ $ops = '';
foreach ($this->_params['images'] as $image) {
- $imgk= new Horde_Image_ImagickProxy();
- $imgk->clear();
- $imgk->readImageBlob($image->raw());
- $imgk->thumbnailImage($this->_params['resize_height'],
- $this->_params['resize_height'],
- true);
- $imgk->setImageBackgroundColor('black');
+ $temp = $image->toFile();
+ // Remember the temp files so we can nuke them later.
+ $this->_image->addFileToClean($temp);
+
+ // Don't rotate the top image.
if ($i++ == $cnt) {
$angle = 0;
} else {
$angle = $angle * -1;
}
}
- $result = $imgk->polaroidImage($angle);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- // Get the geometry of the image and remember the largest.
- $geo = $imgk->getImageGeometry();
- $length = max(
- $length,
- sqrt(pow($geo['height'], 2) + pow($geo['width'], 2)));
-
- $imgs[] = $imgk;
- }
- break;
- }
-
- // Make sure the background canvas is large enough to hold it all.
- $this->_image->_imagick->thumbnailImage($length * 1.5 + 20,
- $length * 1.5 + 20);
-
- // x and y offsets.
- $xo = $yo = (count($imgs) + 1) * $this->_params['offset'];
- foreach ($imgs as $image) {
- if ($this->_params['type'] == 'polaroid') {
- $xo = mt_rand(1, $this->_params['resize_height'] / 2);
- $yo = mt_rand(1, $this->_params['resize_height'] / 2);
- } elseif ($this->_params['type'] == 'plain' ||
- $this->_params['type'] == 'rounded') {
- $xo -= $this->_params['offset'];
- $yo -= $this->_params['offset'];
+ $ops .= ' \( ' . $temp . ' -geometry +' . mt_rand(1, $this->_params['resize_height']) . '+' . mt_rand(1, $this->_params['resize_height']) . ' -thumbnail \'' . $this->_params['resize_height'] . 'x' . $this->_params['resize_height'] . '>\' -bordercolor Snow -border 1 -polaroid ' . $angle . ' \) ';
}
-
- $this->_image->_imagick->compositeImage(
- $image, constant('Imagick::COMPOSITE_OVER'), $xo, $yo);
- $image->removeImage();
- $image->destroy();
- }
- // If we have a background other than 'none' we need to
- // compose two images together to make sure we *have* a background.
- if ($this->_params['background'] != 'none') {
- $size = $this->_image->getDimensions();
- $new = new Horde_Image_ImagickProxy($length * 1.5 + 20,
- $length * 1.5 + 20,
- $this->_params['background'],
- $this->_image->getType());
-
-
-
- $new->compositeImage($this->_image->_imagick,
- constant('Imagick::COMPOSITE_OVER'), 0, 0);
- $this->_image->_imagick->clear();
- $this->_image->_imagick->addImage($new);
- $new->destroy();
- }
- // Trim the canvas before resizing to keep the thumbnails as large
- // as possible.
- $this->_image->_imagick->trimImage(0);
- if ($this->_params['padding']) {
- $this->_image->_imagick->borderImage($this->_params['background'],
- $this->_params['padding'],
- $this->_params['padding']);
- }
-
- } else {
- // No Imagick installed - use im, but make sure we don't mix imagick
- // and convert.
- $this->_image->_imagick = null;
- $this->_image->raw();
-
- switch ($this->_params['type']) {
- case 'plain':
- case 'rounded':
- // Get top image dimensions, then force each bottom image to the
- // same dimensions.
- $this->_params['images'][$cnt - 1]->resize($this->_params['resize_height'],
- $this->_params['resize_height'],
- true);
- $size = $this->_params['images'][$cnt - 1]->getDimensions();
- //$this->_image->resize(2 * $this->_params['resize_height'], 2 * $this->_params['resize_height']);
- for ($i = 0; $i < $cnt; $i++) {
- $this->_params['images'][$i]->resize($size['height'], $size['width'], false);
- }
- $xo = $yo = (count($this->_params['images']) + 1) * $this->_params['offset'];
+ $this->_image->addPostSrcOperation('-background none' . $ops . '-mosaic -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
+ } else {
+ // An attempt at a -polaroid command free version of this
+ // effect based on various examples and ideas at
+ // http://imagemagick.org
$ops = '';
- $haveBottom = false;
foreach ($this->_params['images'] as $image) {
- $xo -= $this->_params['offset'];
- $yo -= $this->_params['offset'];
-
- if ($this->_params['type'] == 'rounded') {
- $temp = $this->_roundBorder($image);
- } else {
- $temp = $image->toFile();
- }
+ $temp = $image->toFile();
$this->_image->addFileToClean($temp);
- $ops .= ' \( ' . $temp . ' -background none -thumbnail ' . $size['width'] . 'x' . $size['height'] . '! -repage +' . $xo . '+' . $yo . ($this->_params['type'] == 'plain' ? ' -bordercolor "#333" -border 1 ' : ' ' ) . ((!$haveBottom) ? '\( +clone -shadow 80x4+0+0 \) +swap -mosaic' : '') . ' \) ';
- $haveBottom = true;
- }
-
- // The first -background none option below is only honored in
- // convert versions before 6.4 it seems. Without it specified as
- // none here, all stacks come out with a white background.
- $this->_image->addPostSrcOperation($ops . ' -background ' . $this->_params['background'] . ' -mosaic -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
-
- break;
-
- case 'polaroid':
- // Check for im version > 6.3.2
- $ver = $this->_image->getIMVersion();
- if (is_array($ver) && version_compare($ver[0], '6.3.2') >= 0) {
- $ops = '';
- foreach ($this->_params['images'] as $image) {
- $temp = $image->toFile();
- // Remember the temp files so we can nuke them later.
- $this->_image->addFileToClean($temp);
-
- // Don't rotate the top image.
- if ($i++ == $cnt) {
- $angle = 0;
- } else {
- $angle = mt_rand(1, 45);
- if (mt_rand(1, 2) % 2 === 0) {
- $angle = $angle * -1;
- }
- }
- $ops .= ' \( ' . $temp . ' -geometry +' . mt_rand(1, $this->_params['resize_height']) . '+' . mt_rand(1, $this->_params['resize_height']) . ' -thumbnail \'' . $this->_params['resize_height'] . 'x' . $this->_params['resize_height'] . '>\' -bordercolor Snow -border 1 -polaroid ' . $angle . ' \) ';
- }
- $this->_image->addPostSrcOperation('-background none' . $ops . '-mosaic -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
- } else {
- // An attempt at a -polaroid command free version of this
- // effect based on various examples and ideas at
- // http://imagemagick.org
- $ops = '';
- foreach ($this->_params['images'] as $image) {
- $temp = $image->toFile();
- $this->_image->addFileToClean($temp);
- if ($i++ == $cnt) {
- $angle = 0;
- } else {
- $angle = mt_rand(1, 45);
- if (mt_rand(1, 2) % 2 === 0) {
- $angle = $angle * -1;
- }
+ if ($i++ == $cnt) {
+ $angle = 0;
+ } else {
+ $angle = mt_rand(1, 45);
+ if (mt_rand(1, 2) % 2 === 0) {
+ $angle = $angle * -1;
}
- $ops .= '\( ' . $temp . ' -thumbnail \'' . $this->_params['resize_height'] . 'x' . $this->_params['resize_height']. '>\' -bordercolor "#eee" -border 4 -bordercolor grey90 -border 1 -bordercolor none -background none -rotate ' . $angle . ' -background none \( +clone -shadow 60x4+4+4 \) +swap -background none -flatten \) ';
}
- $this->_image->addPostSrcOperation('-background none ' . $ops . '-mosaic -trim +repage -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
+ $ops .= '\( ' . $temp . ' -thumbnail \'' . $this->_params['resize_height'] . 'x' . $this->_params['resize_height']. '>\' -bordercolor "#eee" -border 4 -bordercolor grey90 -border 1 -bordercolor none -background none -rotate ' . $angle . ' -background none \( +clone -shadow 60x4+4+4 \) +swap -background none -flatten \) ';
}
- break;
+ $this->_image->addPostSrcOperation('-background none ' . $ops . '-mosaic -trim +repage -bordercolor ' . $this->_params['background'] . ' -border ' . $this->_params['padding']);
}
+ break;
}
return true;
{
$context = array('tmpdir' => $this->_image->getTmpDir(),
'convert' => $this->_image->getConvertPath());
- if (!is_null($this->_image->_imagick)) {
- $size = $image->getImageGeometry();
- $new = Horde_Image::factory('im', array('context' => $context));
- $new->loadString('somestring', $image->getImageBlob());
- $image->destroy();
- $new->addEffect('RoundCorners', array('border' => 2, 'bordercolor' => '#111'));
- $new->applyEffects();
- $return = new Horde_Image_ImagickProxy($size['width'] + $this->_params['borderwidth'],
- $size['height'] + $this->_params['borderwidth'],
- $this->_params['bordercolor'],
- $this->_image->getType());
- $return->clear();
- $return->readImageBlob($new->raw());
- return $return;
- } else {
- $size = $image->getDimensions();
- $new = Horde_Image::factory('im', array('data' => $image->raw(), 'context' => $context));
- $new->addEffect('RoundCorners', array('border' => 2, 'bordercolor' => '#111', 'background' => 'none'));
- $new->applyEffects();
- return $new->toFile();
- }
+
+ $size = $image->getDimensions();
+ $new = Horde_Image::factory('im', array('data' => $image->raw(), 'context' => $context));
+ $new->addEffect('RoundCorners', array('border' => 2, 'bordercolor' => '#111', 'background' => 'none'));
+ $new->applyEffects();
+
+ return $new->toFile();
}
}
\ No newline at end of file
*/
public function apply()
{
- if (!is_null($this->_image->_imagick) &&
- $this->_image->_imagick->methodExists('polaroidImage') &&
- $this->_image->_imagick->methodExists('trimImage')) {
-
- // This determines the color of the underlying shadow.
- $this->_image->_imagick->setImageBackgroundColor($this->_params['shadowcolor']);
-
- $result = $this->_image->_imagick->polaroidImage($this->_params['angle']);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-
- // We need to create a new image to composite the polaroid over.
- // (yes, even if it's a transparent background evidently)
- $size = $this->_image->getDimensions();
- $imk = new Horde_Image_ImagickProxy($size['width'],
- $size['height'],
- $this->_params['background'],
- $this->_image->getType());
-
- $result = $imk->compositeImage($this->_image->_imagick,
- constant('Imagick::COMPOSITE_OVER'),
- 0, 0);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- $this->_image->_imagick->clear();
- $this->_image->_imagick->addImage($imk);
- $imk->destroy();
-
+ // Check for im version > 6.3.2
+ $this->_image->_imagick = null;
+ $ver = $this->_image->getIMVersion();
+ if (is_array($ver) && version_compare($ver[0], '6.3.2') >= 0) {
+ $this->_image->addPostSrcOperation(sprintf("-bordercolor \"#eee\" -background none -polaroid %s \( +clone -fill %s -draw 'color 0,0 reset' \) +swap +flatten",
+ $this->_params['angle'], $this->_params['background']));
} else {
-
- // Check for im version > 6.3.2
- $this->_image->_imagick = null;
- $ver = $this->_image->getIMVersion();
- if (is_array($ver) && version_compare($ver[0], '6.3.2') >= 0) {
- $this->_image->addPostSrcOperation(sprintf("-bordercolor \"#eee\" -background none -polaroid %s \( +clone -fill %s -draw 'color 0,0 reset' \) +swap +flatten",
- $this->_params['angle'], $this->_params['background']));
- } else {
- $size = $this->_image->getDimensions();
- $this->_image->addPostSrcOperation(sprintf("-bordercolor \"#eee\" -border 8 bordercolor grey90 -border 1 -bordercolor none -background none -rotate %s \( +clone -shadow 60x1.5+1+1 -rotate 90 -wave 1x%s -rotate 90 \) +swap -rotate 90 -wave 1x%s -rotate -90 -flatten \( +clone -fill %s -draw 'color 0,0 reset ' \) +swap -flatten",
- $this->_params['angle'], $size['height'] * 2, $size['height'] * 2, $this->_params['background']));
- }
-
- return true;
+ $size = $this->_image->getDimensions();
+ $this->_image->addPostSrcOperation(sprintf("-bordercolor \"#eee\" -border 8 bordercolor grey90 -border 1 -bordercolor none -background none -rotate %s \( +clone -shadow 60x1.5+1+1 -rotate 90 -wave 1x%s -rotate 90 \) +swap -rotate 90 -wave 1x%s -rotate -90 -flatten \( +clone -fill %s -draw 'color 0,0 reset ' \) +swap -flatten",
+ $this->_params['angle'], $size['height'] * 2, $size['height'] * 2, $this->_params['background']));
}
+
+ return true;
}
}
\ No newline at end of file
{
/* Use imagick extension if available */
$round = $this->_params['radius'];
- // Apparently roundCorners() requires imagick to be compiled against
- // IM > 6.2.8.
- if (!is_null($this->_image->_imagick) &&
- $this->_image->_imagick->methodExists('roundCorners')) {
- $result = $this->_image->_imagick->roundCorners($round, $round);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- // Using a border?
- if ($this->_params['bordercolor'] != 'none' &&
- $this->_params['border'] > 0) {
+ // Get image dimensions
+ $dimensions = $this->_image->getDimensions();
+ $height = $dimensions['height'];
+ $width = $dimensions['width'];
- $size = $this->_image->getDimensions();
+ $this->_image->addOperation("-size {$width}x{$height} xc:{$this->_params['background']} "
+ . "-fill {$this->_params['background']} -draw \"matte 0,0 reset\" -tile");
- $new = new Horde_Image_ImagickProxy($size['width'] + $this->_params['border'],
- $size['height'] + $this->_params['border'],
- $this->_params['bordercolor'],
- $this->_image->getType());
-
- $result = $new->roundCorners($round, $round);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- $new->compositeImage($this->_image->_imagick,
- constant('Imagick::COMPOSITE_OVER'), 1, 1);
- $this->_image->_imagick->clear();
- $this->_image->_imagick->addImage($new);
- $new->destroy();
- }
-
- // If we have a background other than 'none' we need to
- // compose two images together to make sure we *have* a background.
- if ($this->_params['background'] != 'none') {
- $size = $this->_image->getDimensions();
- $new = new Horde_Image_ImagickProxy($size['width'],
- $size['height'],
- $this->_params['background'],
- $this->_image->getType());
-
-
-
- $new->compositeImage($this->_image->_imagick,
- constant('Imagick::COMPOSITE_OVER'), 0, 0);
- $this->_image->_imagick->clear();
- $this->_image->_imagick->addImage($new);
- $new->destroy();
- }
- } else {
- // Get image dimensions
- $dimensions = $this->_image->getDimensions();
- $height = $dimensions['height'];
- $width = $dimensions['width'];
-
- // Make sure we don't attempt to use Imagick for any other effects
- // to make sure we do them in the proper order.
- $this->_image->_imagick = null;
-
- $this->_image->addOperation("-size {$width}x{$height} xc:{$this->_params['background']} "
- . "-fill {$this->_params['background']} -draw \"matte 0,0 reset\" -tile");
-
- $this->_image->roundedRectangle(round($round / 2),
- round($round / 2),
- $width - round($round / 2) - 2,
- $height - round($round / 2) - 2,
- $round + 2,
- 'none',
- 'white');
- }
+ $this->_image->roundedRectangle(round($round / 2),
+ round($round / 2),
+ $width - round($round / 2) - 2,
+ $height - round($round / 2) - 2,
+ $round + 2,
+ 'none',
+ 'white');
// Reset width/height since these might have changed
- $this->_image->_width = 0;
- $this->_image->_height = 0;
+ $this->_image->clearGeometry();
return true;
}
protected $_postSrcOperations = array();
/**
- * Reference to an Horde_Image_ImagickProxy object.
- *
- * @TODO: This needs to be public since some of the Effects need to
- * access this and possibly null it out. This will be resolved
- * when Imagick is pulled out into it's own driver.
- *
- * @var Imagick
- */
- public $_imagick = null;
-
- /**
* An array of temporary filenames that need to be unlinked at the end of
* processing. Use addFileToClean() from client code (Effects) to add files
* to this array.
throw new InvalidArgumentException('A path to the convert binary is required.');
}
$this->_convert = $context['convert'];
-
- // TODO: Will be breaking out Imagick into it's own driver.
-
- // Imagick library doesn't play nice with outputting data for 0x0
- // images, so use 1x1 for our default if needed.
- if (Util::loadExtension('imagick')) {
- ini_set('imagick.locale_fix', 1);
- $this->_width = max(array($this->_width, 1));
- $this->_height = max(array($this->_height, 1));
- // Use a proxy for the Imagick calls to keep exception catching
- // code out of PHP4 compliant code.
- $this->_imagick = new Horde_Image_ImagickProxy($this->_width,
- $this->_height,
- $this->_background,
- $this->_type);
- // Yea, it's wasteful to create the proxy (which creates a blank
- // image) then overwrite it if we're passing in an image, but this
- // will be fixed in Horde 4 when imagick is broken out into it's own
- // proper driver.
- if (!empty($params['filename'])) {
- $this->loadFile($params['filename']);
- } elseif(!empty($params['data'])) {
- $this->loadString(md5($params['data']), $params['data']);
- } else {
- $this->_data = $this->_imagick->getImageBlob();
- }
-
- $this->_imagick->setImageFormat($this->_type);
+ if (!empty($params['filename'])) {
+ $this->loadFile($params['filename']);
+ } elseif (!empty($params['data'])) {
+ $this->loadString(md5($params['data']), $params['data']);
} else {
- if (!empty($params['filename'])) {
- $this->loadFile($params['filename']);
- } elseif (!empty($params['data'])) {
- $this->loadString(md5($params['data']), $params['data']);
- } else {
- $cmd = "-size {$this->_width}x{$this->_height} xc:{$this->_background} +profile \"*\" {$this->_type}:__FILEOUT__";
- $this->executeConvertCmd($cmd);
- }
- }
- }
-
- /**
- * Load the image data from a string. Need to override this method
- * in order to load the imagick object if we need to.
- *
- * @TODO: This can be nuked when imagick is broken out.
- *
- * @param string $id An arbitrary id for the image.
- * @param string $image_data The data to use for the image.
- */
- public function loadString($id, $image_data)
- {
- parent::loadString($id, $image_data);
- if (!is_null($this->_imagick)) {
- $this->_imagick->clear();
- $this->_imagick->readImageBlob($image_data);
- $this->_imagick->setFormat($this->_type);
- $this->_imagick->setIteratorIndex(0);
- }
- }
-
- /**
- * Load the image data from a file. Need to override this method
- * in order to load the imagick object if we need to.
- *
- * @TODO: Nuke when imagick is broken out.
- *
- * @param string $filename The full path and filename to the file to load
- * the image data from. The filename will also be
- * used for the image id.
- *
- * @return mixed PEAR Error if file does not exist or could not be loaded
- * otherwise NULL if successful or already loaded.
- */
- public function loadFile($filename)
- {
- parent::loadFile($filename);
- if (!is_null($this->_imagick)) {
- $this->_imagick->clear();
- $this->_imagick->readImageBlob($this->_data);
- $this->_imagick->setIteratorIndex(0);
+ $cmd = "-size {$this->_width}x{$this->_height} xc:{$this->_background} +profile \"*\" {$this->_type}:__FILEOUT__";
+ $this->executeConvertCmd($cmd);
}
}
*/
public function raw($convert = false)
{
- // Make sure _data is sync'd with imagick object
- if (!is_null($this->_imagick)) {
- $this->_data = $this->_imagick->getImageBlob();
- }
-
if (!empty($this->_data)) {
// If there are no operations, and we already have data, don't
// bother writing out files, just return the current data.
/* Load the result */
$this->_data = file_get_contents($tmpout);
-
- // Keep imagick object in sync if we need to.
- // @TODO: Might be able to stop doing this once all operations
- // are doable through imagick api.
- if (!is_null($this->_imagick)) {
- $this->_imagick->clear();
- $this->_imagick->readImageBlob($this->_data);
- }
}
-
@unlink($tmpin);
@unlink($tmpout);
parent::reset();
$this->_operations = array();
$this->_postSrcOperations = array();
- if (is_object($this->_imagick)) {
- $this->_imagick->clear();
- }
- $this->_width = 0;
- $this->_height = 0;
+ $this->clearGeometry();
}
/**
*/
public function resize($width, $height, $ratio = true, $keepProfile = false)
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->thumbnailImage($width, $height, $ratio);
+ $resWidth = $width * 2;
+ $resHeight = $height * 2;
+ $this->_operations[] = "-size {$resWidth}x{$resHeight}";
+ if ($ratio) {
+ $this->_postSrcOperations[] = (($keepProfile) ? "-resize" : "-thumbnail") . " {$width}x{$height}";
} else {
- $resWidth = $width * 2;
- $resHeight = $height * 2;
- $this->_operations[] = "-size {$resWidth}x{$resHeight}";
- if ($ratio) {
- $this->_postSrcOperations[] = (($keepProfile) ? "-resize" : "-thumbnail") . " {$width}x{$height}";
- } else {
- $this->_postSrcOperations[] = (($keepProfile) ? "-resize" : "-thumbnail") . " {$width}x{$height}!";
- }
+ $this->_postSrcOperations[] = (($keepProfile) ? "-resize" : "-thumbnail") . " {$width}x{$height}!";
}
// Reset the width and height instance variables since after resize
// we don't know the *exact* dimensions yet (especially if we maintained
// aspect ratio.
// Refresh the data
$this->raw();
- $this->_width = 0;
- $this->_height = 0;
- }
-
- /**
- * More efficient way of getting size if using imagick library.
- * *ALWAYS* use getDimensions() to get image geometry...instance
- * variables only cache geometry until it changes, then they go
- * to zero.
- *
- */
- public function getDimensions()
- {
- if (!is_null($this->_imagick)) {
- if ($this->_height == 0 && $this->_width == 0) {
- $size = $this->_imagick->getImageGeometry();
- if (is_a($size, 'PEAR_Error')) {
- return $size;
- }
- $this->_height = $size['height'];
- $this->_width = $size['width'];
- }
- return array('width' => $this->_width,
- 'height' => $this->_height);
- } else {
- return parent::getDimensions();
- }
+ $this->clearGeometry();
}
/**
*/
public function crop($x1, $y1, $x2, $y2)
{
- if (!is_null($this->_imagick)) {
- $result = $this->_imagick->cropImage($x2 - $x1, $y2 - $y1, $x1, $y1);
- $this->_imagick->setImagePage(0, 0, 0, 0);
- } else {
- $line = ($x2 - $x1) . 'x' . ($y2 - $y1) . '+' . $x1 . '+' . $y1;
- $this->_operations[] = '-crop ' . $line . ' +repage';
- $result = true;
- }
+ $line = ($x2 - $x1) . 'x' . ($y2 - $y1) . '+' . $x1 . '+' . $y1;
+ $this->_operations[] = '-crop ' . $line . ' +repage';
+
// Reset width/height since these might change
$this->raw();
- $this->_width = 0;
- $this->_height = 0;
-
- return $result;
+ $this->clearGeometry();
}
/**
- * Rotate the current image.
+ * Rotate the current image. This is an atomic operation.
*
* @param integer $angle The angle to rotate the image by,
* in the clockwise direction.
*/
public function rotate($angle, $background = 'white')
{
- if (!is_null($this->_imagick)) {
- return $this->_imagick->rotateImage($background, $angle);
- } else {
- $this->raw();
- $this->_operations[] = "-background $background -rotate {$angle}";
- $this->raw();
- }
+ $this->raw();
+ $this->_operations[] = "-background $background -rotate {$angle}";
+ $this->raw();
+
// Reset width/height since these might have changed
- $this->_width = 0;
- $this->_height = 0;
+ $this->clearGeometry();
}
/**
*/
public function flip()
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->flipImage();
- } else {
- $this->_operations[] = '-flip';
- }
+ $this->_operations[] = '-flip';
}
/**
*/
public function mirror()
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->flopImage();
- } else {
- $this->_operations[] = '-flop';
- }
+ $this->_operations[] = '-flop';
}
/**
*/
public function grayscale()
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->setImageColorSpace(constant('Imagick::COLORSPACE_GRAY'));
- } else {
- $this->_postSrcOperations[] = '-colorspace GRAY';
- }
+ $this->_postSrcOperations[] = '-colorspace GRAY';
}
/**
*/
public function sepia($threshold = 85)
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->sepiaToneImage($threshold);
- } else {
- $this->_operations[] = '-sepia-tone ' . $threshold . '%';
- }
+ $this->_operations[] = '-sepia-tone ' . $threshold . '%';
}
- /**
+ /**
* Draws a text string on the image in a specified location, with
* the specified style information.
*
*/
public function text($string, $x, $y, $font = '', $color = 'black', $direction = 0, $fontsize = 'small')
{
- if (!is_null($this->_imagick)) {
- $fontsize = self::getFontSize($fontsize);
-
- return $this->_imagick->text($string, $x, $y, $font, $color, $direction, $fontsize);
- } else {
- $string = addslashes('"' . $string . '"');
- $fontsize = self::getFontSize($fontsize);
- $this->_postSrcOperations[] = "-fill $color " . (!empty($font) ? "-font $font" : '') . " -pointsize $fontsize -gravity northwest -draw \"text $x,$y $string\" -fill none";
- }
+ $string = addslashes('"' . $string . '"');
+ $fontsize = self::getFontSize($fontsize);
+ $this->_postSrcOperations[] = "-fill $color " . (!empty($font) ? "-font $font" : '') . " -pointsize $fontsize -gravity northwest -draw \"text $x,$y $string\" -fill none";
}
/**
*/
public function circle($x, $y, $r, $color, $fill = 'none')
{
- if (!is_null($this->_imagick)) {
- return $this->_imagick->circle($x, $y, $r, $color, $fill);
- } else {
- $xMax = $x + $r;
- $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"circle $x,$y $xMax,$y\" -stroke none -fill none";
- }
+ $xMax = $x + $r;
+ $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"circle $x,$y $xMax,$y\" -stroke none -fill none";
}
/**
*/
public function polygon($verts, $color, $fill = 'none')
{
- // TODO: For now, use only convert since ::polygon is called from other
- // methods that are convert-only for now.
- //if (!is_null($this->_imagick)) {
- //return $this->_imagick->polygon($verts, $color, $fill);
- //} else {
- $command = '';
- foreach ($verts as $vert) {
- $command .= sprintf(' %d,%d', $vert['x'], $vert['y']);
- }
- $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"polygon $command\" -stroke none -fill none";
- //}
+ $command = '';
+ foreach ($verts as $vert) {
+ $command .= sprintf(' %d,%d', $vert['x'], $vert['y']);
+ }
+ $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"polygon $command\" -stroke none -fill none";
}
/**
*/
public function rectangle($x, $y, $width, $height, $color, $fill = 'none')
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->rectangle($x, $y, $width, $height, $color, $fill);
- } else {
- $xMax = $x + $width;
- $yMax = $y + $height;
- $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"rectangle $x,$y $xMax,$yMax\" -stroke none -fill none";
- }
+ $xMax = $x + $width;
+ $yMax = $y + $height;
+ $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"rectangle $x,$y $xMax,$yMax\" -stroke none -fill none";
}
/**
*/
public function roundedRectangle($x, $y, $width, $height, $round, $color, $fill)
{
- if (!is_null($this->_imagick)) {
- $this->_imagick->roundedRectangle($x, $y, $width, $height, $round, $color, $fill);
- } else {
- $x1 = $x + $width;
- $y1 = $y + $height;
- $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"roundRectangle $x,$y $x1,$y1 $round,$round\" -stroke none -fill none";
-
- }
+ $x1 = $x + $width;
+ $y1 = $y + $height;
+ $this->_postSrcOperations[] = "-stroke $color -fill $fill -draw \"roundRectangle $x,$y $x1,$y1 $round,$round\" -stroke none -fill none";
}
/**
*/
public function line($x0, $y0, $x1, $y1, $color = 'black', $width = 1)
{
- if (!is_null($this->_imagick)) {
- return $this->_imagick->line($x0, $y0, $x1, $y1, $color, $width);
- } else {
- $this->_operations[] = "-stroke $color -strokewidth $width -draw \"line $x0,$y0 $x1,$y1\"";
- }
+ $this->_operations[] = "-stroke $color -strokewidth $width -draw \"line $x0,$y0 $x1,$y1\"";
}
/**
*/
public function dashedLine($x0, $y0, $x1, $y1, $color = 'black', $width = 1, $dash_length = 2, $dash_space = 2)
{
- if (!is_null($this->_imagick)) {
- return $this->_imagick->dashedLine($x0, $y0, $x1, $y1, $color,
- $width, $dash_length,
- $dash_space);
- } else {
- $this->_operations[] = "-stroke $color -strokewidth $width -draw \"line $x0,$y0 $x1,$y1\"";
- }
+ $this->_operations[] = "-stroke $color -strokewidth $width -draw \"line $x0,$y0 $x1,$y1\"";
}
/**
*/
public function polyline($verts, $color, $width = 1)
{
- if (!is_null($this->_imagick)) {
- return $this->_imagick->polyline($verts, $color, $width);
- } else {
- $command = '';
- foreach ($verts as $vert) {
- $command .= sprintf(' %d,%d', $vert['x'], $vert['y']);
- }
- $this->_operations[] = "-stroke $color -strokewidth $width -fill none -draw \"polyline $command\" -strokewidth 1 -stroke none -fill none";
+ $command = '';
+ foreach ($verts as $vert) {
+ $command .= sprintf(' %d,%d', $vert['x'], $vert['y']);
}
+ $this->_operations[] = "-stroke $color -strokewidth $width -fill none -draw \"polyline $command\" -strokewidth 1 -stroke none -fill none";
}
/**
{
static $version = null;
if (!is_array($version)) {
- if (!is_null($this->_imagick)) {
- $output = $this->_imagick->getVersion();
- $output[0] = $output['versionString'];
- } else {
- $commandline = $this->_convert . ' --version';
- exec($commandline, $output, $retval);
- }
+ $commandline = $this->_convert . ' --version';
+ exec($commandline, $output, $retval);
if (preg_match('/([0-9])\.([0-9])\.([0-9])/', $output[0], $matches)) {
$version = $matches;
return $matches;
return false;
}
}
+
return $version;
}