Overview

Packages

  • Image
  • None

Classes

  • Horde_Image
  • Horde_Image_Base
  • Horde_Image_Effect
  • Horde_Image_Effect_Border
  • Horde_Image_Effect_Gd_DropShadow
  • Horde_Image_Effect_Gd_RoundCorners
  • Horde_Image_Effect_Gd_TextWatermark
  • Horde_Image_Effect_Gd_Unsharpmask
  • Horde_Image_Effect_Im_Border
  • Horde_Image_Effect_Im_CenterCrop
  • Horde_Image_Effect_Im_Composite
  • Horde_Image_Effect_Im_DropShadow
  • Horde_Image_Effect_Im_LiquidResize
  • Horde_Image_Effect_Im_PhotoStack
  • Horde_Image_Effect_Im_PolaroidImage
  • Horde_Image_Effect_Im_RoundCorners
  • Horde_Image_Effect_Im_TextWatermark
  • Horde_Image_Effect_Im_Unsharpmask
  • Horde_Image_Effect_Imagick_Border
  • Horde_Image_Effect_Imagick_CenterCrop
  • Horde_Image_Effect_Imagick_Composite
  • Horde_Image_Effect_Imagick_DropShadow
  • Horde_Image_Effect_Imagick_LiquidResize
  • Horde_Image_Effect_Imagick_PhotoStack
  • Horde_Image_Effect_Imagick_PolaroidImage
  • Horde_Image_Effect_Imagick_RoundCorners
  • Horde_Image_Effect_Imagick_SmartCrop
  • Horde_Image_Effect_Imagick_TextWatermark
  • Horde_Image_Effect_Imagick_Unsharpmask
  • Horde_Image_Exception
  • Horde_Image_Exif
  • Horde_Image_Exif_Base
  • Horde_Image_Exif_Bundled
  • Horde_Image_Exif_Exiftool
  • Horde_Image_Exif_Parser_Base
  • Horde_Image_Exif_Php
  • Horde_Image_Gd
  • Horde_Image_Im
  • Horde_Image_Imagick
  • Horde_Image_Png
  • Horde_Image_Svg
  • Horde_Image_Swf
  • Horde_Image_Translation
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Image effect for determining the best crop based on the center of edginess.
  4:  * Copyright 2010-2012 Horde LLC (http://www.horde.org/)
  5:  *
  6:  * Based on ideas and code by Jue Wang <jue@jueseph.com>
  7:  * http://jueseph.com/2010/06/opticrop-usage-and-implementation/
  8:  *
  9:  * See the enclosed file COPYING for license information (LGPL). If you
 10:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 11:  *
 12:  * @author  Michael J. Rubinsky <mrubinsk@horde.org>
 13:  * @package Image
 14:  */
 15: class Horde_Image_Effect_Imagick_SmartCrop extends Horde_Image_Effect
 16: {
 17:     /**
 18:      * Valid parameters:
 19:      *  <pre>
 20:      *    width    - Target width
 21:      *    height   - Target height
 22:      * </pre>
 23:      *
 24:      * @var array
 25:      */
 26:     protected $_params = array();
 27: 
 28:     public function apply()
 29:     {
 30:         $this->_params = new Horde_Support_Array($this->_params);
 31:        
 32:         // Existing geometry
 33:         $geometry = $this->_image->getDimensions();
 34:         $w0 = $geometry['width'];
 35:         $h0 = $geometry['height'];
 36: 
 37:         $w = $this->_params->width;
 38:         $h = $this->_params->height;
 39:         
 40:         // @TODO: Parameterize these
 41:         $r = 1;         // radius of edge filter
 42:         $nk = 9;        // scale count: number of crop sizes to try
 43:         $gamma = 0.2;   // edge normalization parameter -- see documentation
 44:         
 45:         // Target AR
 46:         $ar = $this->_params->width / $this->_params->height;
 47: 
 48:         // Existing AR
 49:         $ar0 = $w0 / $h0;
 50: 
 51:         $this->_logger->debug(sprintf("SmartCrop: %d x %d => %d x %d ", $w0, $h0, $w, $h));
 52:         $this->_logger->debug('OAR: ' . $ar0);
 53:         $this->_logger->debug('TAR: ' . $ar);
 54: 
 55: 
 56:         // Compute COE
 57:         $img = $this->_image->imagick->clone();
 58:         $img->edgeImage($r);
 59:         $img->modulateImage(100,0,100);
 60:         $img->blackThresholdImage("#0f0f0f");
 61: 
 62:         $xcenter = $ycenter = $sum = 0;
 63:         $n = 100000;
 64:         for ($k = 0; $k < $n; $k++) {
 65:             $i = mt_rand(0, $w0 - 1);
 66:             $j = mt_rand(0, $h0 - 1);
 67:             $pixel = $img->getImagePixelColor($i, $j);
 68:             $val = $pixel->getColor();
 69:             $val = $val['b'];
 70:             $sum += $val;
 71:             $xcenter = $xcenter + ($i + 1) * $val;
 72:             $ycenter = $ycenter + ($j + 1) * $val;
 73:         }
 74:         $xcenter /= $sum;
 75:         $ycenter /= $sum;
 76:         $this->_logger->debug('COE: ' . $xcenter . 'x' . $ycenter);
 77:         
 78:         // crop source img to target AR
 79:         if ($w0 / $h0 > $ar) {
 80:             // source AR wider than target
 81:             // crop width to target AR
 82:             $wcrop0 = round($ar * $h0);
 83:             $hcrop0 = $h0;
 84:         } else {
 85:             // crop height to target AR
 86:             $wcrop0 = $w0;
 87:             $hcrop0 = round($w0 / $ar);
 88:         }
 89: 
 90:         // crop parameters for all scales and translations
 91:         $params = array();
 92: 
 93:         // crop at different scales
 94:         $hgap = $hcrop0 - $h;
 95:         $hinc = ($nk == 1) ? 0 : $hgap / ($nk - 1);
 96:         $wgap = $wcrop0 - $w;
 97:         $winc = ($nk == 1) ? 0 : $wgap / ($nk - 1);
 98: 
 99:         // find window with highest normalized edginess
100:         $n = 10000;
101:         $maxbetanorm = 0;
102:         $maxfile = '';
103:         $maxparam = array('w' => 0,
104:                           'h' => 0,
105:                           'x' => 0,
106:                           'y' => 0);
107: 
108:         for ($k = 0; $k < $nk; $k++) {
109:             $hcrop = round($hcrop0 - $k * $hinc);
110:             $wcrop = round($wcrop0 - $k * $winc);
111:             $xcrop = $xcenter - $wcrop / 2;
112:             $ycrop = $ycenter - $hcrop / 2;
113:             if ($xcrop < 0) {
114:                 $xcrop = 0;
115:             }
116:             if ($xcrop + $wcrop > $w0) {
117:                 $xcrop = $w0 - $wcrop;
118:             }
119:             if ($ycrop < 0) {
120:                 $ycrop = 0;
121:             }
122:             if ($ycrop+$hcrop > $h0) {
123:                 $ycrop = $h0 - $hcrop;
124:             }
125:             $this->_logger->debug("crop: $wcrop, $hcrop, $xcrop, $ycrop");
126: 
127:             $beta = 0;
128:             for ($c = 0; $c < $n; $c++) {
129:                 $i = mt_rand(0, $wcrop - 1);
130:                 $j = mt_rand(0, $hcrop - 1);
131:                 $pixel = $img->getImagePixelColor($xcrop + $i, $ycrop + $j);
132:                 $val = $pixel->getColor();
133:                 $beta += $val['b'];// & 0xFF;
134:             }
135: 
136:             $area = $wcrop * $hcrop;
137:             $betanorm = $beta / ($n * pow($area, $gamma - 1));
138: 
139:             // best image found, save the params
140:             if ($betanorm > $maxbetanorm) {
141:                 $this->_logger->debug('Found best');
142:                 $maxbetanorm = $betanorm;
143:                 $maxparam['w'] = $wcrop;
144:                 $maxparam['h'] = $hcrop;
145:                 $maxparam['x'] = $xcrop;
146:                 $maxparam['y'] = $ycrop;
147:             }
148:         }
149: 
150:         $this->_logger->debug('Cropping');
151:         // Crop to best
152:         $this->_image->imagick->cropImage($maxparam['w'],
153:                                           $maxparam['h'],
154:                                           $maxparam['x'],
155:                                           $maxparam['y']);
156:         $this->_image->imagick->scaleImage($w, $h);
157:         $img->destroy();
158:     }
159: 
160: }
API documentation generated by ApiGen