"; } // end timer $timeparts = explode(' ',microtime()); $endtime = $timeparts[1].substr($timeparts[0],1); $elapsed = bcsub($endtime,$starttime,6); dprint("
Script execution time (s): ".$elapsed); // serve out results render($cache, (DEBUG==1)?true:false, FORMAT); // log results $lf = fopen(LOG_PATH, 'a'); $logstring = date(DATE_RFC822)."\n". $_SERVER["QUERY_STRING"]."\n$elapsed s\n\n"; fwrite($lf, $logstring); fclose($lf); } /* prints debug messages */ function dprint($str, $print_r=false) { if (DEBUG > 0) { if ($print_r) { print_r($str); echo "
\n"; } else { echo $str."
\n"; } } } /* * returns local system path for an image * doesn't work if image isn't on this domain * * $url - url of image on the same domain as this script * */ function get_image_path($url) { // url given, strip domain $image = preg_replace('/^(s?f|ht)tps?:\/\/[^\/]+/i', '', $url); // for security directories can't contain ':' // images can't contain '..' or '<', if (strpos(dirname($image), ':') || preg_match('/(\.\.|<|>)/', $image)) { header('HTTP/1.1 400 Bad Request'); echo 'Error: malformed image path. Image paths must begin with \'/\''; exit(); } // add docroot to absolute paths if ($image{0} == '/') { $docRoot = rtrim(DOCUMENT_ROOT,'/'); $image = $docRoot . $image; } else { // relative path $image = str_replace('\\', '/', getcwd()).'/'.$image; } // check if an image location is given if (!$image) { header('HTTP/1.1 400 Bad Request'); echo 'Error: no image was specified'; exit(); } // check if the file exists if (!file_exists($image)) { header('HTTP/1.1 400 Bad Request'); echo 'Error: image does not exist: ' . $image; exit(); } return $image; } /* * returns a path to the cache for an image * * $image - path to source image */ function get_cache_path($image) { $cache = ltrim($image, '/'); // path to cache directory $path = explode('/',$cache); $cache_dirs = CACHE_PATH.implode('/', array_slice($path, 2, -1)); // create cache directory if doesn't exist if (!is_dir($cache_dirs)) { mkdir($cache_dirs, 0777, true); } // path to cache file $cache_file = end($path); // append script parameters to cache path $cache = $cache_dirs.'/'.$cache_file.'-'.$_GET['w'].'x'.$_GET['h'].'-'.GAMMA.'-'.FORMAT; $cache = escapeshellcmd($cache); return $cache; } /* * parses imagemagick commands and runs the command line 'convert' utility on * the source image. calls outside functions for image processing if necessary. * * $image - path to source image * &$cache - path to save transformed image, passed by reference so it can be * changed depending on cache settings */ function dispatch($image, &$cache) { // bypass or disable cache? switch(CACHING) { case 'no': $cache = CACHE_PATH."temp.jpg"; dprint("no caching. using $cache for temporary storage"); case 'refresh': // or 'no': dprint("refreshing cache."); if (file_exists($cache)) { unlink($cache); dprint("cache $cache deleted."); } } // get cache if (file_exists($cache)) { dprint('cached data retrieved'); return 0; } // compute image $result = opticrop($image, WIDTH, HEIGHT, $cache, FORMAT); dprint($cache); // there should be a file named $cache now if (!file_exists($cache)) { die('ERROR: Image conversion failed.'); } return $result; } /* * displays an image over the webserver * * $cache - path of file to display * $as_html - serve the image as an img tag in an html page (use for debugging) */ function render($cache, $as_html=false, $format) { if ($format != 'img') { readfile($cache); return; } if ($as_html) { echo ""; return; } // get image data for use in http-headers $imginfo = getimagesize($cache); $content_length = filesize($cache); $last_modified = gmdate('D, d M Y H:i:s',filemtime($cache)).' GMT'; // array of getimagesize() mime types $getimagesize_mime = array(1=>'image/gif',2=>'image/jpeg', 3=>'image/png',4=>'application/x-shockwave-flash', 5=>'image/psd',6=>'image/bmp',7=>'image/tiff', 8=>'image/tiff',9=>'image/jpeg', 13=>'application/x-shockwave-flash',14=>'image/iff'); // did the browser send an if-modified-since request? if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { // parse header $if_modified_since = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']); if ($if_modified_since == $last_modified) { // the browser's cache is still up to date header("HTTP/1.0 304 Not Modified"); header("Cache-Control: max-age=86400, must-revalidate"); exit; } } // send other headers header('Cache-Control: max-age=86400, must-revalidate'); header('Content-Length: '.$content_length); header('Last-Modified: '.$last_modified); if (isset($getimagesize_mime[$imginfo[2]])) { header('Content-Type: '.$getimagesize_mime[$imginfo[2]]); } else { // send generic header header('Content-Type: application/octet-stream'); } // and finally, send the image readfile($cache); } /* * edge-maximizing crop * determines center-of-edginess, then tries different-sized crops around it. * picks the crop with the highest normalized edginess. * see documentation on how to tune the algorithm * * $w, $h - target dimensions of thumbnail * $image - system path to source image * $out - path/name of output image */ function opticrop($image, $w, $h, $out, $format) { // source dimensions $imginfo = getimagesize($image); $w0 = $imginfo[0]; $h0 = $imginfo[1]; if ($w > $w0 || $h > $h0) die("Target dimensions must be smaller or equal to source dimensions."); // parameters for the edge-maximizing crop algorithm $r = 1; // radius of edge filter $nk = 9; // scale count: number of crop sizes to try $gamma = GAMMA; // edge normalization parameter -- see documentation $ar = $w/$h; // target aspect ratio (AR) $ar0 = $w0/$h0; // target aspect ratio (AR) dprint("$image: $w0 x $h0 => $w x $h"); $img = new Imagick($image); $imgcp = clone $img; // compute center of edginess $img->edgeImage($r); $img->modulateImage(100,0,100); // grayscale $img->blackThresholdImage("#0f0f0f"); $img->writeImage($out); // use gd for random pixel access $im = ImageCreateFromJpeg($out); $xcenter = 0; $ycenter = 0; $sum = 0; $n = 100000; for ($k=0; $k<$n; $k++) { $i = mt_rand(0,$w0-1); $j = mt_rand(0,$h0-1); $val = imagecolorat($im, $i, $j) & 0xFF; $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; dprint("crop: $wcrop, $hcrop, $xcrop, $ycrop"); if ($xcrop < 0) $xcrop = 0; if ($xcrop+$wcrop > $w0) $xcrop = $w0-$wcrop; if ($ycrop < 0) $ycrop = 0; if ($ycrop+$hcrop > $h0) $ycrop = $h0-$hcrop; // debug $currfile = CACHE_PATH."image$k.jpg"; if (DEBUG > 0) { $currimg = clone $img; $c= new ImagickDraw(); $c->setFillColor("red"); $c->circle($xcenter, $ycenter, $xcenter, $ycenter+4); $currimg->drawImage($c); $currimg->cropImage($wcrop, $hcrop, $xcrop, $ycrop); $currimg->writeImage($currfile); $currimg->destroy(); } $beta = 0; for ($c=0; $c<$n; $c++) { $i = mt_rand(0,$wcrop-1); $j = mt_rand(0,$hcrop-1); $beta += imagecolorat($im, $xcrop+$i, $ycrop+$j) & 0xFF; } $area = $wcrop * $hcrop; $betanorm = $beta / ($n*pow($area, $gamma-1)); dprint("beta: $beta; betan: $betanorm"); dprint("image$k.jpg:
\n"); // best image found, save it if ($betanorm > $maxbetanorm) { $maxbetanorm = $betanorm; $maxparam['w'] = $wcrop; $maxparam['h'] = $hcrop; $maxparam['x'] = $xcrop; $maxparam['y'] = $ycrop; $maxfile = $currfile; } } dprint("best image: $maxfile"); if (FORMAT == 'json') { // return coordinates instead of image $data = json_encode($maxparam); file_put_contents($out, $data); } else { // return image $imgcp->cropImage($maxparam['w'],$maxparam['h'], $maxparam['x'],$maxparam['y']); $imgcp->scaleImage($w,$h); $imgcp->writeImage($out); } chmod($out, 0777); $img->destroy(); $imgcp->destroy(); return 0; } ?>