From: Michael J. Rubinsky Date: Sun, 14 Feb 2010 21:49:13 +0000 (-0500) Subject: Complete implementation of Iterator support in Horde_Image. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=5dcae2cd2543b6c29aac1690c4f5e15af6b9fe26;p=horde.git Complete implementation of Iterator support in Horde_Image. This works in Imagemagick and Imagick only. GD will always return a clone of itself; (GD doesn't support TIFF or PDF, and has no native methods for obtaining individual pages from GIF) Multipage images (TIFF, GIF, PDF etc...) can now be either iterated as so: // $original Image contains a multipage image foreach($original as $page) { // $page is a Horde_Image object representing the single page } or individually select the page as so: $page = $original->getImageAtIndex($pageNumber); Horde_Image_Base#getImagePageCount returns the total number of pages. --- diff --git a/framework/Image/lib/Horde/Image/Base.php b/framework/Image/lib/Horde/Image/Base.php index 3313dc1ce..419a9fbde 100644 --- a/framework/Image/lib/Horde/Image/Base.php +++ b/framework/Image/lib/Horde/Image/Base.php @@ -16,7 +16,7 @@ * @TODO: - Can we depend on the Horde_Util:: class or some other solution needed? * - Exceptions */ -class Horde_Image_Base Implements Iterator +abstract class Horde_Image_Base Implements Iterator { /** * Background color. @@ -91,13 +91,22 @@ class Horde_Image_Base Implements Iterator protected $_type = 'png'; /** + * Cache the context + * + * @param array + */ + protected $_context; + + /** * Constructor. * * @param string $rgb The base color for generated pixels/images. */ protected function __construct($params, $context = array()) { - + $this->_params = $params; + $this->_context = $context; + if (empty($context['tmpdir'])) { throw new InvalidArgumentException('A path to a temporary directory is required.'); } @@ -309,7 +318,7 @@ class Horde_Image_Base Implements Iterator public function display() { $this->headers(); - echo $this->raw(); + echo $this->raw(true); } /** @@ -419,32 +428,19 @@ class Horde_Image_Base Implements Iterator } /** - * Iterator interface + * Request a specific image from the collection of images. + * + * @param integer $index The index to return + * + * @return Horde_Image_Base */ - public function rewind() - { - - } - - public function current() - - { - - } - - public function key() - { - - } - - public function next() - { - - } - - public function valid() - { - - } + abstract function getImageAtIndex($index); + /** + * Return the number of image pages available in the image object. + * + * @return integer + */ + abstract function getImagePageCount(); + } diff --git a/framework/Image/lib/Horde/Image/Gd.php b/framework/Image/lib/Horde/Image/Gd.php index 7d6e4417a..7e6bd801f 100644 --- a/framework/Image/lib/Horde/Image/Gd.php +++ b/framework/Image/lib/Horde/Image/Gd.php @@ -789,4 +789,68 @@ class Horde_Image_Gd extends Horde_Image_Base return $result; } + /** + * Return the current image from the internal iterator. + * + * @return Horde_Image_Gd + */ + public function current() + { + return clone($this); + } + + /** + * Get the index of the internal iterator. + * + * @return integer + */ + public function key() + { + return 0; + } + + /** + * Advance the iterator + * + * @return Horde_Image_Imagick + */ + public function next() + { + return null; + } + + /** + * Deterimines if the current iterator item is valid. + * + * @return boolean + */ + public function valid() + { + return false; + } + + /** + * Request a specific image from the collection of images. + * + * @param integer $index The index to return + * + * @return Horde_Image_Base + */ + public function getImageAtIndex($index) + { + if ($index > 0) { + throw new Horde_Image_Exception('Image index out of bounds.'); + } + } + + /** + * Return the number of image pages available in the image object. + * + * @return integer + */ + public function getImagePageCount() + { + return 1; + } + } diff --git a/framework/Image/lib/Horde/Image/Im.php b/framework/Image/lib/Horde/Image/Im.php index eae32625f..09367cebe 100644 --- a/framework/Image/lib/Horde/Image/Im.php +++ b/framework/Image/lib/Horde/Image/Im.php @@ -61,6 +61,27 @@ class Horde_Image_Im extends Horde_Image_Base protected $_convert = ''; /** + * Path to the identify binary + * + * @string + */ + protected $_identify; + + /** + * Cache the number of image pages + * + * @var integer + */ + private $_pages; + + /** + * Track current page for the iterator + * + * @var integer + */ + private $_currentPage = 0; + + /** * Constructor. */ public function __construct($params, $context = array()) @@ -71,6 +92,10 @@ class Horde_Image_Im extends Horde_Image_Base throw new InvalidArgumentException('A path to the convert binary is required.'); } $this->_convert = $context['convert']; + + if (!empty($context['identify'])) { + $this->_identify = $context['identify']; + } if (!empty($params['filename'])) { $this->loadFile($params['filename']); } elseif (!empty($params['data'])) { @@ -82,6 +107,17 @@ class Horde_Image_Im extends Horde_Image_Base } /** + * Publically visible raw method. Hides the extra parameters from client + * code. + * + * @see self::_raw + */ + public function raw($convert = false) + { + return $this->_raw($convert); + } + + /** * Returns the raw data for this image. * * @param boolean $convert If true, the image data will be returned in the @@ -92,7 +128,7 @@ class Horde_Image_Im extends Horde_Image_Base * * @return string The raw image data. */ - public function raw($convert = false) + private function _raw($convert = false, $index = 0, $preserve_data = false) { if (empty($this->_data) || // If there are no operations, and we already have data, don't @@ -109,7 +145,7 @@ class Horde_Image_Im extends Horde_Image_Base if (count($this->_operations) || count($this->_postSrcOperations) || $convert) { $tmpout = Horde_Util::getTempFile('img', false, $this->_tmpdir); $command = $this->_convert . ' ' . implode(' ', $this->_operations) - . ' "' . $tmpin . '"\'[0]\' ' + . ' "' . $tmpin . '"\'[' . $index . ']\' ' . implode(' ', $this->_postSrcOperations) . ' +profile "*" ' . $this->_type . ':"' . $tmpout . '" 2>&1'; $this->_logDebug(sprintf("convert command executed by Horde_Image_im::raw(): %s", $command)); @@ -123,12 +159,15 @@ class Horde_Image_Im extends Horde_Image_Base $this->_postSrcOperations = array(); /* Load the result */ - $this->_data = file_get_contents($tmpout); + $return = file_get_contents($tmpout); + if (!$preserve_data) { + $this->_data = $return; + } } @unlink($tmpin); @unlink($tmpout); - return $this->_data; + return $return; } /** @@ -536,4 +575,110 @@ class Horde_Image_Im extends Horde_Image_Base return $this->_convert; } + /** + * Reset the imagick iterator to the first image in the set. + * + * @return void + */ + public function rewind() + { + $this->_logDebug('Horde_Image_Im#rewind'); + $this->_currentPage = 0; + } + + /** + * Return the current image from the internal iterator. + * + * @return Horde_Image_Imagick + */ + public function current() + { + $this->_logDebug('Horde_Image_Im#current'); + return $this->getImageAtIndex($this->_currentPage); + } + + /** + * Get the index of the internal iterator. + * + * @return integer + */ + public function key() + { + $this->_logDebug('Horde_Image_Im#key'); + return $this->_currentPage; + } + + /** + * Advance the iterator + * + * @return Horde_Image_Im + */ + public function next() + { + $this->_logDebug('Horde_Image_Im#next'); + $this->_currentPage++; + if ($this->valid()) { + return $this->getImageAtIndex($this->_currentPage); + } + } + + /** + * Deterimines if the current iterator item is valid. + * + * @return boolean + */ + public function valid() + { + return $this->_currentPage < $this->getImagePageCount(); + } + + /** + * Request a specific image from the collection of images. + * + * @param integer $index The index to return + * + * @return Horde_Image_Base + */ + public function getImageAtIndex($index) + { + $this->_logDebug('Horde_Image_Im#getImageAtIndex: ' . $index); + if ($index >= $this->getImagePageCount()) { + throw new Horde_Image_Exception('Image index out of bounds.'); + } + $rawImage = $this->_raw(true, $index, true); + $image = new Horde_Image_Im(array('data' => $rawImage), $this->_context); + + return $image; + } + + /** + * Return the number of image pages available in the image object. + * + * @return integer + */ + public function getImagePageCount() + { + if (is_null($this->_pages)) { + $pages = $this->_getImagePages(); + $this->_pages = array_pop($pages); + } + $this->_logDebug('Horde_Image_Im#getImagePageCount: ' . $this->_pages); + + return $this->_pages; + + } + + private function _getImagePages() + { + $this->_logDebug('Horde_Image_Im#_getImagePages'); + $filename = $this->toFile(); + $cmd = $this->_identify . ' -format "%n" ' . $filename; + exec($cmd, $output, $retval); + if ($retval) { + $this->_logErr(sprintf("Error running command: %s", $cmd . "\n" . implode("\n", $output))); + } + unlink($filename); + + return $output; + } } diff --git a/framework/Image/lib/Horde/Image/Imagick.php b/framework/Image/lib/Horde/Image/Imagick.php index 082d8cb34..5524dbe42 100644 --- a/framework/Image/lib/Horde/Image/Imagick.php +++ b/framework/Image/lib/Horde/Image/Imagick.php @@ -114,7 +114,7 @@ class Horde_Image_Imagick extends Horde_Image_Base throw new Horde_Image_Exception($e); } $this->_imagick->setFormat($this->_type); - $this->_imagick->setIteratorIndex(0); + //$this->_imagick->setIteratorIndex(0); unset($this->_data); } @@ -555,10 +555,8 @@ class Horde_Image_Imagick extends Horde_Image_Base { $this->_logDebug('Horde_Image_Imagick#current'); $params = array('data' => $this->raw()); - $context = array('tmpdir' => $this->_tmpdir, - 'logger' => $this->_logger); - $image = new Horde_Image_Imagick($params, $context); - $this->_logDebug(print_r($image, true)); + $image = new Horde_Image_Imagick($params, $this->_context); + return $image; } @@ -589,9 +587,45 @@ class Horde_Image_Imagick extends Horde_Image_Base } } + /** + * Deterimines if the current iterator item is valid. + * + * @return boolean + */ public function valid() { $this->_logDebug('Horde_Image_Imagick#valid:' . print_r(!$this->moreImages, true)); return !$this->_noMoreImages; } + + /** + * Request a specific image from the collection of images. + * + * @param integer $index The index to return + * + * @return Horde_Image_Base + */ + public function getImageAtIndex($index) + { + if ($index >= $this->_imagick->getNumberImages()) { + throw Horde_Image_Exception('Image index out of bounds.'); + } + + $currentIndex = $this->_imagick->getIteratorIndex(); + $this->_imagick->setIteratorIndex($index); + $image = $this->current(); + $this->_imagick->setIteratorIndex($currentIndex); + + return $image; + } + + /** + * Return the number of image pages available in the image object. + * + * @return integer + */ + public function getImagePageCount() + { + return $this->_imagick->getNumberImages(); + } }