--- /dev/null
+<?php
+/**
+ * Image effect for determining the best crop based on the center of edginess.
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * Based on ideas and code by Jue Wang <jue@jueseph.com>
+ * http://jueseph.com/2010/06/opticrop-usage-and-implementation/
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Horde_Image
+ */
+class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect
+{
+ /**
+ * Valid parameters:
+ * <pre>
+ * width - Target width
+ * height - Target height
+ * </pre>
+ *
+ * @var array
+ */
+ protected $_params = array();
+
+ public function apply()
+ {
+ $this->_params = new Horde_Support_Array($this->_params);
+
+ // Existing geometry
+ $geometry = $this->_image->getDimensions();
+ $w0 = $geometry['width'];
+ $h0 = $geometry['height'];
+
+ // @TODO: Parameterize these
+ $r = 1; // radius of edge filter
+ $nk = 9; // scale count: number of crop sizes to try
+ $gamma = 0.2; // edge normalization parameter -- see documentation
+
+ // Target AR
+ $ar = $this->_params->width / $this->_params->height;
+
+ // Existing AR
+ $ar0 = $w0/$h0;
+
+ // Compute COE
+ $img = $this->_image->imagick->clone();
+ $img->edgeImage($r);
+ $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();
+ }
+ }
+
+ $sum += $val;
+ $xcenter += ($i + 1) * $val;
+ $ycenter += ($j + 1) * $val;
+ }
+
+ $xcenter /= $sum;
+ $ycenter /= $sum;
+
+ // crop source img to target AR
+ if ($w0/$h0 > $ar) {
+ // source AR wider than target
+ // crop width to target AR
+ $wcrop0 = round($ar * $h0);
+ $hcrop0 = $h0;
+ } else {
+ // crop height to target AR
+ $wcrop0 = $w0;
+ $hcrop0 = round($w0 / $ar);
+ }
+
+ // crop parameters for all scales and translations
+ $params = array();
+
+ // crop at different scales
+ $hgap = $hcrop0 - $h;
+ $hinc = ($nk == 1) ? 0 : $hgap / ($nk - 1);
+ $wgap = $wcrop0 - $w;
+ $winc = ($nk == 1) ? 0 : $wgap / ($nk - 1);
+
+ // find window with highest normalized edginess
+ $n = 10000;
+ $maxbetanorm = 0;
+ $maxfile = '';
+ $maxparam = array('w' => 0,
+ 'h' => 0,
+ 'x' => 0,
+ 'y' => 0);
+
+ for ($k = 0; $k < $nk; $k++) {
+ $hcrop = round($hcrop0 - $k * $hinc);
+ $wcrop = round($wcrop0 - $k * $winc);
+ $xcrop = $xcenter - $wcrop / 2;
+ $ycrop = $ycenter - $hcrop / 2;
+ if ($xcrop < 0) {
+ $xcrop = 0;
+ }
+ if ($xcrop + $wcrop > $w0) {
+ $xcrop = $w0 - $wcrop;
+ }
+ if ($ycrop < 0) {
+ $ycrop = 0;
+ }
+ if ($ycrop+$hcrop > $h0) {
+ $ycrop = $h0 - $hcrop;
+ }
+
+ $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;
+ }
+
+ $area = $wcrop * $hcrop;
+ $betanorm = $beta / ($n * pow($area, $gamma - 1));
+
+ // best image found, save the params
+ if ($betanorm > $maxbetanorm) {
+ $maxbetanorm = $betanorm;
+ $maxparam['w'] = $wcrop;
+ $maxparam['h'] = $hcrop;
+ $maxparam['x'] = $xcrop;
+ $maxparam['y'] = $ycrop;
+ }
+ }
+
+ // Crop to best
+ $this->_image->imagick->cropImage($maxparam['w'],
+ $maxparam['h'],
+ $maxparam['x'],
+ $maxparam['y']);
+ $this->_image->imagick->scaleImage($w, $h);
+ $img->destroy();
+ }
+
+}
\ No newline at end of file
<file name="TextWatermark.php" role="php" />
<file name="Unsharpmask.php" role="php" />
<file name="LiquidResize.php" role="php" />
+ <file name="SmartCrop.php" role="php" />
</dir> <!-- /lib/Horde/Image/Effect/Imagick -->
<file name="Border.php" role="php" />
</dir> <!-- /lib/Horde/Image/Effect -->
<install as="Horde/Image/Effect/Imagick/TextWatermark.php" name="lib/Horde/Image/Effect/Imagick/TextWatermark.php" />
<install as="Horde/Image/Effect/Imagick/Unsharpmask.php" name="lib/Horde/Image/Effect/Imagick/Unsharpmask.php" />
<install as="Horde/Image/Effect/Imagick/LiquidResize.php" name="lib/Horde/Image/Effect/Imagick/LiquidResize.php" />
+ <isntall as="Horde/Image/Effect/Imagick/SmartCrop.php" name="lib/Horde/Image/Effect/Imagick/SmartCrop.php" />
<install as="Horde/Image/Exif/Base.php" name="lib/Horde/Image/Exif/Base.php" />
<install as="Horde/Image/Exif/Bundled.php" name="lib/Horde/Image/Exif/Bundled.php" />
<install as="Horde/Image/Exif/Exiftool.php" name="lib/Horde/Image/Exif/Exiftool.php" />