From: Michael J. Rubinsky Date: Tue, 28 Sep 2010 16:28:58 +0000 (-0400) Subject: Tweak and fix the smart crop effect. This now works under Imagick X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=56415f3847a003bceef2d29dc6ca080c655d8f8d;p=horde.git Tweak and fix the smart crop effect. This now works under Imagick --- diff --git a/framework/Image/lib/Horde/Image/Effect.php b/framework/Image/lib/Horde/Image/Effect.php index cea8ea0e5..e6fd37cf4 100644 --- a/framework/Image/lib/Horde/Image/Effect.php +++ b/framework/Image/lib/Horde/Image/Effect.php @@ -58,7 +58,7 @@ class Horde_Image_Effect $this->_logger = $logger; } - public function factory($type, $driver, $params) + static public function factory($type, $driver, $params) { if (is_array($type)) { list($app, $type) = $type; @@ -86,9 +86,11 @@ class Horde_Image_Effect @include_once $path; } } + if (class_exists($class)) { $effect = new $class($params); } else { + $params['logger']->err(sprintf("Horde_Image_Effect %s for %s driver not found.", $type, $driver)); throw new Horde_Image_Exception(sprintf("Horde_Image_Effect %s for %s driver not found.", $type, $driver)); } diff --git a/framework/Image/lib/Horde/Image/Effect/Imagick/SmartCrop.php b/framework/Image/lib/Horde/Image/Effect/Imagick/SmartCrop.php index 5eea96685..7e5ed4248 100644 --- a/framework/Image/lib/Horde/Image/Effect/Imagick/SmartCrop.php +++ b/framework/Image/lib/Horde/Image/Effect/Imagick/SmartCrop.php @@ -27,6 +27,7 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect public function apply() { + mt_srand(1); $this->_params = new Horde_Support_Array($this->_params); // Existing geometry @@ -34,6 +35,9 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect $w0 = $geometry['width']; $h0 = $geometry['height']; + $w = $this->_params->width; + $h = $this->_params->height; + // @TODO: Parameterize these $r = 1; // radius of edge filter $nk = 9; // scale count: number of crop sizes to try @@ -43,7 +47,12 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect $ar = $this->_params->width / $this->_params->height; // Existing AR - $ar0 = $w0/$h0; + $ar0 = $w0 / $h0; + + $this->_logger->debug(sprintf("SmartCrop: %d x %d => %d x %d ", $w0, $h0, $w, $h)); + $this->_logger->debug('OAR: ' . $ar0); + $this->_logger->debug('TAR: ' . $ar); + // Compute COE $img = $this->_image->imagick->clone(); @@ -51,31 +60,24 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect $img->modulateImage(100,0,100); $img->blackThresholdImage("#0f0f0f"); - // Get a 1x1 iterator (only way to get a single pixel's info without - // iterating the entire row. $xcenter = $ycenter = $sum = 0; $n = 100000; for ($k = 0; $k < $n; $k++) { $i = mt_rand(0, $w0 - 1); $j = mt_rand(0, $h0 - 1); - // A single pixel iterator! - $itr = $img->getPixelRegionIterator($i, $j, 1, 1); - foreach ($itr as $row => $pixels) { - foreach ($pixels as $col => $pixel) { - $val = $pixel->getColor(); - } - } - + $pixel = $img->getImagePixelColor($i, $j); + $val = $pixel->getColor(); + $val = $val['b']; $sum += $val; - $xcenter += ($i + 1) * $val; - $ycenter += ($j + 1) * $val; + $xcenter = $xcenter + ($i + 1) * $val; + $ycenter = $ycenter + ($j + 1) * $val; } - $xcenter /= $sum; $ycenter /= $sum; - + $this->_logger->debug('COE: ' . $xcenter . 'x' . $ycenter); + // crop source img to target AR - if ($w0/$h0 > $ar) { + if ($w0 / $h0 > $ar) { // source AR wider than target // crop width to target AR $wcrop0 = round($ar * $h0); @@ -121,18 +123,15 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect if ($ycrop+$hcrop > $h0) { $ycrop = $h0 - $hcrop; } + $this->_logger->debug("crop: $wcrop, $hcrop, $xcrop, $ycrop"); $beta = 0; for ($c = 0; $c < $n; $c++) { $i = mt_rand(0, $wcrop - 1); $j = mt_rand(0, $hcrop - 1); - $itr = $img->getPixelRegionIterator($xcrop + $i, $ycrop + $j, 1, 1); - foreach ($itr as $row => $pixels) { - foreach ($pixels as $col => $pixel) { - $val = $pixel->getColor(); - } - } - $beta += $val & 0xFF; + $pixel = $img->getImagePixelColor($xcrop + $i, $ycrop + $j); + $val = $pixel->getColor(); + $beta += $val['b'];// & 0xFF; } $area = $wcrop * $hcrop; @@ -140,6 +139,7 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect // best image found, save the params if ($betanorm > $maxbetanorm) { + $this->_logger->debug('Found best'); $maxbetanorm = $betanorm; $maxparam['w'] = $wcrop; $maxparam['h'] = $hcrop; @@ -148,6 +148,7 @@ class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect } } + $this->_logger->debug('Cropping'); // Crop to best $this->_image->imagick->cropImage($maxparam['w'], $maxparam['h'], diff --git a/framework/Image/package.xml b/framework/Image/package.xml index 99ca97d1c..1ac7f4e10 100644 --- a/framework/Image/package.xml +++ b/framework/Image/package.xml @@ -175,7 +175,7 @@ Initial Horde 4 package - + diff --git a/framework/Image/tests/im.php b/framework/Image/tests/im.php index 20a3dd3de..81e312ad8 100644 --- a/framework/Image/tests/im.php +++ b/framework/Image/tests/im.php @@ -15,18 +15,34 @@ Horde_Registry::appInit('horde', array('authentication' => 'none')); // profiling. $driver = Horde_Util::getFormData('driver', 'Im'); $test = Horde_Util::getFormData('test'); + +// Don't use horde config since we might be configured for Imagick only. $convert = trim(`which convert`); $identify = trim(`which identify`); + $handler = new Horde_Log_Handler_Stream(fopen('/tmp/imagetest.log','a+')); $logger = new Horde_Log_Logger($handler); switch ($test) { +case 'smart': + $time = xdebug_time_index(); + $image = getImageObject(array('filename' => 'img4.jpg')); + $image->addEffect('SmartCrop', array('width' => 100, 'height' => 100)); + $image->display(); + $time = xdebug_time_index() - $time; + $memory = xdebug_peak_memory_usage(); + logThis($test, $time, $memory); + exit; + case 'liquid': $time = xdebug_time_index(); $image = getImageObject(array('filename' => 'img4.jpg')); $image->addEffect('LiquidResize', array('ratio' => true, 'width' => 612, 'height' => 340, 'delta_x' => 3, 'rigidity' => 0)); $image->display(); - break; + $time = xdebug_time_index() - $time; + $memory = xdebug_peak_memory_usage(); + logThis($test, $time, $memory); + exit; case 'multipage': $time = xdebug_time_index(); @@ -40,7 +56,9 @@ case 'multipage': $first = false; } } - logThis($test, $time, xdebug_peak_memory_usage()); + $time = xdebug_time_index() - $time; + $memory = xdebug_peak_memory_usage(); + logThis($test, $time, $memory); case 'testInitialState': // Solid blue background color - basically tests initial state of the @@ -465,9 +483,10 @@ function getImageObject($params = array()) $context = array('tmpdir' => Horde::getTempDir(), 'convert' => $GLOBALS['convert'], - 'logger' => $GLOBALS['logger'], + 'logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger'), 'identify' => $GLOBALS['identify']); $params['context'] = $context; + return Horde_Image::factory($GLOBALS['driver'], $params); } diff --git a/framework/Image/tests/runtest.php b/framework/Image/tests/runtest.php index 169b8de08..9718e0cc6 100644 --- a/framework/Image/tests/runtest.php +++ b/framework/Image/tests/runtest.php @@ -35,6 +35,7 @@ $allTests = array( 'testResize' => 'Test resize method.', 'multipage' => 'Test Multipage tiffs', 'liquid' => 'Test Seam Carving', + 'smart' => 'Test Smart Crop (Center of Edginess)' ); ?>