andy's php projects
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister   ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
Script and site usage:
All of the scripts on this site are provided free for non-commerical, personal or non-profit use. If you find these scripts useful to you, appreciate the free support, or are just an all round nice person, then why not donate a little dosh? If you wish to use any of these in a commercial system, please refer to the payment plan.


Improved thumbnailing class

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    php.amnuts.com Forum Index -> Crop Canvas
View previous topic :: View next topic  
Author Message
nation-x
Newbie


Joined: 28 Aug 2005
Posts: 6

PostPosted: Sun Aug 28, 2005 1:19 pm    Post subject: Improved thumbnailing class Reply with quote

These classes are a combination of the canvasCrop(), imgRedim(), UnsharpMask() and parts of phpThumb(). I put them together more for a friend that wanted to provide thumbnails for the images and more that people upload to his bulletin board. The site isn't working as yet so I can't give you a URL but I thought I should share this here.

I added the phpThumb() and UnsharpMask() filters in order to provide very nice looking thumbs. Adding the filters drastically increases processing time.

The class is declared as follows:

PHP:
<?php require_once(dirname(__FILE__) . '/includes/imagehandler.php');

/* CONFIG SECTION */
$improve_thumbnails true// Auto Contrast, Unsharp Mask, Desaturate,  White Balance
$temp_path dirname(__FILE__) . "/temp/"//required for improved gd_verion() function
$thumb_quality 90;
$width 90;
$height 120;
/* END CONFIG SECTION */

$rd = new imgRedim(false$improve_thumbnails$temp_path);

$image_filename "SOURCE_IMAGE"// define source image here
$output_filename "DESTINATION_IMAGE"// define destination image here

$rd->loadImage($image_filename);
$rd->redimToSize($width$heighttrue);

if (
$rd->saveImage($output_filename$thumb_quality)){
    echo 
"Thumbnail created.";
?>


Here is the source of imagehandler.php:
PHP:
<?php //////////////////////////////////////////////////////////////
///  phpThumb() by James Heinrich <info@silisoftware.com>   //
//        available at http://phpthumb.sourceforge.net     ///
//////////////////////////////////////////////////////////////
///  canvasCrop() by Andrew Collington <php@amnuts.com>     //
//        available at http://php.amnuts.com                //
//                                                         ///
//////////////////////////////////////////////////////////////

define("ccTOPLEFT"0);
define("ccTOP"1);
define("ccTOPRIGHT"2);
define("ccLEFT"3);
define("ccCENTRE"4);
define("ccCENTER"4);
define("ccRIGHT"5);
define("ccBOTTOMLEFT"6);
define("ccBOTTOM"7);
define("ccBOTTOMRIGHT"8);

class 
canvasCrop{
    var 
$_imgOrig;
    var 
$_imgFinal;
    var 
$_showDebug;
    var 
$_gdVersion;

    
/*
    * 
    * @return canvasCrop 
    * @param bool $debug 
    * @desc Class initializer
    */
    
function canvasCrop($debug false)
    {
        
$this->_showDebug = ($debug true false);
        
$this->_gdVersion $this->gd_version();
    }

    
/*
    * 
    * @return bool 
    * @param string $filename 
    * @desc Load an image from the file system - method based on file extension
    */
    
function loadImage($filename)
    {
        if (!@
file_exists($filename)){
            
$this->_debug('loadImage'"The supplied file name '$filename' does not point to a readable file.");
            return 
false;
        }

        
$ext strtolower($this->_getExtension($filename));
        
$func "imagecreatefrom$ext";

        if (!@
function_exists($func)){
            
$this->_debug('loadImage'"That file cannot be loaded with the function '$func'.");
            return 
false;
        }

        
$this->_imgOrig = @$func($filename);

        if (
$this->_imgOrig == null){
            
$this->_debug('loadImage''The image could not be loaded.');
            return 
false;
        }

        return 
true;
    }

    
/*
    * 
    * @return bool 
    * @param string $string 
    * @desc Load an image from a string (eg. from a database table)
    */
    
function loadImageFromString($string)
    {
        
$this->_imgOrig = @ImageCreateFromString($string);
        if (!
$this->_imgOrig){
            
$this->_debug('loadImageFromString''The image could not be loaded.');
            return 
false;
        }
        return 
true;
    }

    
/*
    * 
    * @return bool 
    * @param string $filename 
    * @param int $quality 
    * @desc Save the cropped image
    */
    
function saveImage($filename$quality 100)
    {
        if (
$this->_imgFinal == null){
            
$this->_debug('saveImage''There is no processed image to save.');
            return 
false;
        }

        
$ext strtolower($this->_getExtension($filename));
        
$func "image$ext";

        if (!@
function_exists($func)){
            
$this->_debug('saveImage'"That file cannot be saved with the function '$func'.");
            return 
false;
        }

        
$saved false;
        if (
$ext == 'png'$saved $func($this->_imgFinal$filename);
        if (
$ext == 'jpeg'$saved $func($this->_imgFinal$filename$quality);
        if (
$saved == false){
            
$this->_debug('saveImage'"Could not save the output file '$filename' as a $ext.");
            return 
false;
        }

        return 
true;
    }

    
/*
    * 
    * @return bool 
    * @param string $type 
    * @param int $quality 
    * @desc Shows the cropped image without any saving
    */
    
function showImage($type 'png'$quality 100)
    {
        if (
$this->_imgFinal == null){
            
$this->_debug('showImage''There is no processed image to show.');
            return 
false;
        }
        if (
$type == 'png'){
            echo @
ImagePNG($this->_imgFinal);
            return 
true;
        }else if (
$type == 'jpg' || $type == 'jpeg'){
            echo @
ImageJPEG($this->_imgFinal''$quality);
            return 
true;
        }else{
            
$this->_debug('showImage'"Could not show the output file as a $type.");
            return 
false;
        }
    }

    
/*
    * 
    * @return int 
    * @param int $x 
    * @param int $y 
    * @param int $position 
    * @desc Determines the dimensions to crop to if using the 'crop by size' method
    */
    
function cropBySize($x$y$position ccCENTRE)
    {
        if (
$x == 0){
            
$nx = @ImageSX($this->_imgOrig);
        }else{
            
$nx = @ImageSX($this->_imgOrig) - $x;
        }
        if (
$y == 0){
            
$ny = @ImageSY($this->_imgOrig);
        }else{
            
$ny = @ImageSY($this->_imgOrig) - $y;
        }
        return (
$this->_cropSize(-1, -1$nx$ny$position'cropBySize'));
    }

    
/*
    * 
    * @return int 
    * @param int $x 
    * @param int $y 
    * @param int $position 
    * @desc Determines the dimensions to crop to if using the 'crop to size' method
    */
    
function cropToSize($x$y$position ccCENTRE)
    {
        if (
$x == 0$x 1;
        if (
$y == 0$y 1;
        return (
$this->_cropSize(-1, -1$x$y$position'cropToSize'));
    }

    
/*
    * 
    * @return int 
    * @param int $sx 
    * @param int $sy 
    * @param int $ex 
    * @param int $ey 
    * @desc Determines the dimensions to crop to if using the 'crop to dimensions' method
    */
    
function cropToDimensions($sx$sy$ex$ey)
    {
        
$nx abs($ex $sx);
        
$ny abs($ey $sy);
        return (
$this->_cropSize($sx$sy$nx$ny$position'cropToDimensions'));
    }

    
/*
    * 
    * @return int 
    * @param int $percentx 
    * @param int $percenty 
    * @param int $position 
    * @desc Determines the dimensions to crop to if using the 'crop by percentage' method
    */
    
function cropByPercent($percentx$percenty$position ccCENTRE)
    {
        if (
$percentx == 0){
            
$nx = @ImageSX($this->_imgOrig);
        }else{
            
$nx = @ImageSX($this->_imgOrig) - (($percentx 100) * @ImageSX($this->_imgOrig));
        }
        if (
$percenty == 0){
            
$ny = @ImageSY($this->_imgOrig);
        }else{
            
$ny = @ImageSY($this->_imgOrig) - (($percenty 100) * @ImageSY($this->_imgOrig));
        }
        return (
$this->_cropSize(-1, -1$nx$ny$position'cropByPercent'));
    }

    
/*
    * 
    * @return int 
    * @param int $percentx 
    * @param int $percenty 
    * @param int $position 
    * @desc Determines the dimensions to crop to if using the 'crop to percentage' method
    */
    
function cropToPercent($percentx$percenty$position ccCENTRE)
    {
        if (
$percentx == 0){
            
$nx = @ImageSX($this->_imgOrig);
        }else{
            
$nx = ($percentx 100) * @ImageSX($this->_imgOrig);
        }
        if (
$percenty == 0){
            
$ny = @ImageSY($this->_imgOrig);
        }else{
            
$ny = ($percenty 100) * @ImageSY($this->_imgOrig);
        }
        return (
$this->_cropSize(-1, -1$nx$ny$position'cropByPercent'));
    }

    
/*
    * 
    * @return bool 
    * @param int $threshold 
    * @desc Determines the dimensions to crop to if using the 'automatic crop by threshold' method
    */
    
function cropByAuto($threshold 254)
    {
        if (
$threshold 0$threshold 0;
        if (
$threshold 255$threshold 255;

        
$sizex = @ImageSX($this->_imgOrig);
        
$sizey = @ImageSY($this->_imgOrig);

        
$sx $sy $ex $ey = -1;
        for (
$y 0$y $sizey$y++){
            for (
$x 0$x $sizex$x++){
                if (
$threshold >= $this->_getThresholdValue($this->_imgOrig$x$y)){
                    if (
$sy == -1$sy $y;
                    else 
$ey $y;

                    if (
$sx == -1$sx $x;
                    else{
                        if (
$x $sx$sx $x;
                        else if (
$x $ex$ex $x;
                    }
                }
            }
        }
        
$nx abs($ex $sx);
        
$ny abs($ey $sy);
        return (
$this->_cropSize($sx$sy$nx$nyccTOPLEFT'cropByAuto'));
    }

    
/*
    * 
    * @return void 
    * @desc Destroy the resources used by the images
    */
    
function flushImages()
    {
        @
ImageDestroy($this->_imgOrig);
        @
ImageDestroy($this->_imgFinal);
        
$this->_imgOrig $this->_imgFinal null;
    }

    
/*
    * 
    * @return bool 
    * @param int $ox Original image width
    * @param int $oy Original image height
    * @param int $nx New width
    * @param int $ny New height
    * @param int $position Where to place the crop
    * @param string $function Name of the calling function
    * @desc Creates the cropped image based on passed parameters
    */
    
function _cropSize($ox$oy$nx$ny$position$function)
    {
        if (
$this->_imgOrig == null){
            
$this->_debug($function'The original image has not been loaded.');
            return 
false;
        }
        if ((
$nx <= 0) || ($ny <= 0)){
            
$this->_debug($function'The image could not be cropped because the size given is not valid.');
            return 
false;
        }
        if ((
$nx > @ImageSX($this->_imgOrig)) || ($ny > @ImageSY($this->_imgOrig))){
            
$this->_debug($function'The image could not be cropped because the size given is larger than the original image.');
            return 
false;
        }
        if (
$ox == -|| $oy == -1){
            list(
$ox$oy) = $this->_getCopyPosition($nx$ny$position);
        }
        if (
$this->_gdVersion >= 2){
            
$this->_imgFinal = @ImageCreateTrueColor($nx$ny);
            
imagefill($this->_imgFinal,0,0,imagecolorallocate($this->_imgFinal255255255));
            @
imagecopyresampled($this->_imgFinal$this->_imgOrig00$ox$oy$nx$ny$nx$ny);
        }else{
            
$this->_imgFinal = @ImageCreate($nx$ny);
            @
ImageCopyResized($this->_imgFinal$this->_imgOrig00$ox$oy$nx$ny$nx$ny);
        }
        return 
true;
    }

    
/*
    * 
    * @return array 
    * @param int $nx 
    * @param int $ny 
    * @param int $position 
    * @desc Determines dimensions of the crop
    */
    
function _getCopyPosition($nx$ny$position)
    {
        
$ox = @ImageSX($this->_imgOrig);
        
$oy = @ImageSY($this->_imgOrig);

        switch (
$position){
            case 
ccTOPLEFT:
                return array(
00);
            case 
ccTOP:
                return array(
ceil(($ox $nx) / 2), 0);
            case 
ccTOPRIGHT:
                return array((
$ox $nx), 0);
            case 
ccLEFT:
                return array(
0ceil(($oy $ny) / 2));
            case 
ccCENTRE:
                return array(
ceil(($ox $nx) / 2), ceil(($oy $ny) / 2));
            case 
ccRIGHT:
                return array((
$ox $nx), ceil(($oy $ny) / 2));
            case 
ccBOTTOMLEFT:
                return array(
0, ($oy $ny));
            case 
ccBOTTOM:
                return array(
ceil(($ox $nx) / 2), ($oy $ny));
            case 
ccBOTTOMRIGHT:
                return array((
$ox $nx), ($oy $ny));
        }
    }

    
/*
    * 
    * @return float 
    * @param resource $im 
    * @param int $x 
    * @param int $y 
    * @desc Determines the intensity value of a pixel at the passed co-ordinates
    */
    
function _getThresholdValue($im$x$y)
    {
        
$rgb ImageColorAt($im$x$y);
        
$r = ($rgb >> 16) &0xFF;
        
$g = ($rgb >> 8) &0xFF;
        
$b $rgb &0xFF;
        
$intensity = ($r $g $b) / 3;
        return 
$intensity;
    }

    
/*
    * 
    * @return string 
    * @param string $filename 
    * @desc Get the extension of a file name
    */
    
function _getExtension($filename)
    {
        
$ext = @strtolower(@substr($filename, (@strrpos($filename".") ? @strrpos($filename".") + : @strlen($filename)), @strlen($filename)));
        return (
$ext == 'jpg') ? 'jpeg' $ext;
    }

    
/*
    * 
    * @return void 
    * @param string $function 
    * @param string $string 
    * @desc Shows debugging information
    */
    
function _debug($function$string)
    {
        if (
$this->_showDebug){
            echo 
"<p><strong style=\"color:#FF0000\">Error in function $function:</strong> $string</p>\n";
        }
    }

    function 
version_compare_replacement_sub($version1$version2$operator '')
    { 
        
// If you specify the third optional operator argument, you can test for a particular relationship.
        // The possible operators are: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne respectively.
        // Using this argument, the function will return 1 if the relationship is the one specified by the operator, 0 otherwise.
        // If a part contains special version strings these are handled in the following order: dev < (alpha = a) < (beta = b) < RC < pl
        
static $versiontype_lookup = array();
        if (empty(
$versiontype_lookup)){
            
$versiontype_lookup['dev'] = 10001;
            
$versiontype_lookup['a'] = 10002;
            
$versiontype_lookup['alpha'] = 10002;
            
$versiontype_lookup['b'] = 10003;
            
$versiontype_lookup['beta'] = 10003;
            
$versiontype_lookup['RC'] = 10004;
            
$versiontype_lookup['pl'] = 10005;
        }
        if (isset(
$versiontype_lookup[$version1])){
            
$version1 $versiontype_lookup[$version1];
        }
        if (isset(
$versiontype_lookup[$version2])){
            
$version2 $versiontype_lookup[$version2];
        }

        switch (
$operator){
            case 
'<':
            case 
'lt':
                return 
intval($version1 $version2);
                break;
            case 
'<=':
            case 
'le':
                return 
intval($version1 <= $version2);
                break;
            case 
'>':
            case 
'gt':
                return 
intval($version1 $version2);
                break;
            case 
'>=':
            case 
'ge':
                return 
intval($version1 >= $version2);
                break;
            case 
'==':
            case 
'=':
            case 
'eq':
                return 
intval($version1 == $version2);
                break;
            case 
'!=':
            case 
'<>':
            case 
'ne':
                return 
intval($version1 != $version2);
                break;
        }
        if (
$version1 == $version2){
            return 
0;
        }elseif (
$version1 $version2){
            return -
1;
        }
        return 
1;
    }

    function 
version_compare_replacement($version1$version2$operator '')
    {
        if (
function_exists('version_compare')){ 
            
// built into PHP v4.1.0+
            
return version_compare($version1$version2$operator);
        } 
        
// The function first replaces _, - and + with a dot . in the version strings
        
$version1 strtr($version1'_-+''...');
        
$version2 strtr($version2'_-+''...'); 
        
// and also inserts dots . before and after any non number so that for example '4.3.2RC1' becomes '4.3.2.RC.1'.
        // Then it splits the results like if you were using explode('.',$ver). Then it compares the parts starting from left to right.
        
$version1 eregi_replace('([0-9]+)([A-Z]+)([0-9]+)''\\1.\\2.\\3'$version1);
        
$version2 eregi_replace('([0-9]+)([A-Z]+)([0-9]+)''\\1.\\2.\\3'$version2);

        
$parts1 explode('.'$version1);
        
$parts2 explode('.'$version1);
        
$parts_count max(count($parts1), count($parts2));
        for (
$i 0$i $parts_count$i++){
            
$comparison $this->version_compare_replacement_sub($version1$version2$operator);
            if (
$comparison != 0){
                return 
$comparison;
            }
        }
        return 
0;
    }

    function 
gd_version($fullstring false)
    {
        static 
$cache_gd_version = array();
        if (empty(
$cache_gd_version)){
            
$gd_info $this->gd_info();
            if (
substr($gd_info['GD Version'], 0strlen('bundled (')) == 'bundled ('){
                
$cache_gd_version[1] = $gd_info['GD Version']; // e.g. "bundled (2.0.15 compatible)"
                
$cache_gd_version[0] = (float) substr($gd_info['GD Version'], strlen('bundled ('), 3); // e.g. "2.0" (not "bundled (2.0.15 compatible)")
            
}else{
                
$cache_gd_version[1] = $gd_info['GD Version']; // e.g. "1.6.2 or higher"
                
$cache_gd_version[0] = (float) substr($gd_info['GD Version'], 03); // e.g. "1.6" (not "1.6.2 or higher")
            
}
        }
        return 
$cache_gd_version[intval($fullstring)];
    }

    function 
gd_info()
    {
        if (
function_exists('gd_info')){ 
            
// built into PHP v4.3.0+ (with bundled GD2 library)
            
return gd_info();
        }

        static 
$gd_info = array();
        if (empty(
$gd_info)){ 
            
// based on code by johnschaefer at gmx dot de
            // from PHP help on gd_info()
            
$gd_info = array('GD Version' => '',
                
'FreeType Support' => false,
                
'FreeType Linkage' => '',
                
'T1Lib Support' => false,
                
'GIF Read Support' => false,
                
'GIF Create Support' => false,
                
'JPG Support' => false,
                
'PNG Support' => false,
                
'WBMP Support' => false,
                
'XBM Support' => false
                
);
            
$phpinfo_array $this->phpinfo_array();
            foreach (
$phpinfo_array as $line){
                
$line trim(strip_tags($line));
                foreach (
$gd_info as $key => $value){ 
                    
// if (strpos($line, $key) !== false) {
                    
if (strpos($line$key) === 0){
                        
$newvalue trim(str_replace($key''$line));
                        
$gd_info[$key] = $newvalue;
                    }
                }
            }
            if (empty(
$gd_info['GD Version'])){ 
                
// probable cause: "phpinfo() disabled for security reasons"
                
if (function_exists('ImageTypes')){
                    
$imagetypes ImageTypes();
                    if (
$imagetypes &IMG_PNG){
                        
$gd_info['PNG Support'] = true;
                    }
                    if (
$imagetypes &IMG_GIF){
                        
$gd_info['GIF Create Support'] = true;
                    }
                    if (
$imagetypes &IMG_JPG){
                        
$gd_info['JPG Support'] = true;
                    }
                    if (
$imagetypes &IMG_WBMP){
                        
$gd_info['WBMP Support'] = true;
                    }
                } 
                
// to determine capability of GIF creation, try to use ImageCreateFromGIF on a 1px GIF
                
if (function_exists('ImageCreateFromGIF')){
                    if (
$tempfilename $this->GetTempName()){
                        if (
$fp_tempfile = @fopen($tempfilename'wb')){
                            
fwrite($fp_tempfilebase64_decode('R0lGODlhAQABAIAAAH//AP///ywAAAAAAQABAAACAUQAOw==')); // very simple 1px GIF file base64-encoded as string
                            
fclose($fp_tempfile); 
                            
// if we can convert the GIF file to a GD image then GIF create support must be enabled, otherwise it's not
                            
$gd_info['GIF Read Support'] = (bool) @ImageCreateFromGIF($tempfilename);
                        }
                        
unlink($tempfilename);
                    }
                }
                if (
function_exists('ImageCreateTrueColor') && @ImageCreateTrueColor(11)){
                    
$gd_info['GD Version'] = '2.0.1 or higher (assumed)';
                }elseif (
function_exists('ImageCreate') && @ImageCreate(11)){
                    
$gd_info['GD Version'] = '1.6.0 or higher (assumed)';
                }
            }
        }
        return 
$gd_info;
    }

    function 
phpinfo_array()
    {
        static 
$phpinfo_array = array();
        if (empty(
$phpinfo_array)){
            
ob_start();
            
phpinfo();
            
$phpinfo ob_get_contents();
            
ob_end_clean();
            
$phpinfo_array explode("\n"$phpinfo);
        }
        return 
$phpinfo_array;
    }
}

class 
imgRedim extends canvasCrop{
    var 
$temp_directory;
    var 
$improve_thumbs;

    function 
imgRedim($debug false$filters false$temp_path)
    {
        
$this->canvasCrop($debug);
        if (empty(
$temp_path)){
            
$this->_debug($function'You must specify a temp directory.');
        }
        
$this->improve_thumbs $filters;
    }

    function 
redimToSize($x$y$crop false)
    {
        return (
$this->_reSize($x$y$crop'redimToSize'));
    }

    function 
_reSize($nx$ny$crop false$function)
    {
        if (
$this->_imgOrig == null){
            
$this->_debug($function'The original image has not been loaded.');
            return 
false;
        }
        if ((
$nx <= 0) || ($ny <= 0)){
            
$this->_debug($function'The image could not be resized because the size given is not valid.');
            return 
false;
        }

        
$ox = @ImageSX($this->_imgOrig);
        
$oy = @ImageSY($this->_imgOrig);
        
$nnx $nx;
        
$nny $ny;

        if ((
$nx $ox) || ($ny $oy)){
            
$this->_debug($function'The image could not be resized because the size given is larger than the original image.');
            return 
false;
        }

        if (
$ox $oy){
            
$nx $ox $ny $oy;
        }elseif (
$ox $oy){
            
$ny $oy $nx $ox;
        }

        if (
$this->_gdVersion >= 2){
            
$this->_imgFinal = @ImageCreateTrueColor($nx$ny);
            
imagefill($this->_imgFinal00imagecolorallocate($this->_imgFinal255255255));
            @
ImageCopyResampled($this->_imgFinal$this->_imgOrig0000$nx$ny$ox$oy);
        }else{
            
$this->_imgFinal = @ImageCreate($nx$ny);
            @
ImageCopyResized($this->_imgFinal$this->_imgOrig0000$nx$ny$ox$oy);
        }

        
$cropNecessary false;
        if ((
$nx != $nnx) || ($ny != $nny)) {
            
$cropNecessary true;
        }

        if (
$crop && $cropNecessary) {
            
$_imgOrigCopy $this->_imgOrig;
            
$this->_imgOrig $this->_imgFinal;
            
$result $this->cropToSize($nnx$nny);
            if (
$this->improve_thumbs){
                
$result $this->WhiteBalance($this->_imgFinal);
                
$result $this->AutoContrast($this->_imgFinal);
                
$result $this->UnSharpMask($this->_imgFinal"80|0.5|3");
                
$result $this->Desaturate($this->_imgFinal, -10);
            }
            
$this->_imgOrig $_imgOrigCopy;
            unset(
$_imgOrigCopy);
        
            return 
$result;
        }
        if (
$this->improve_thumbs){
            
$result $this->WhiteBalance($this->_imgFinal);
            
$result $this->AutoContrast($this->_imgFinal);
            
$result $this->UnSharpMask($this->_imgFinal"80|0.5|3");
            
$result $this->Desaturate($this->_imgFinal, -10);
        }

        return 
true;
    }

    function 
IsHexColor($HexColorString)
    {
        return 
eregi('^[0-9A-F]{6}$'$HexColorString);
    }

    function 
GetPixelColor(&$img$x$y)
    {
        return @
ImageColorsForIndex($img, @ImageColorAt($img$x$y));
    }

    function 
GrayscalePixel($OriginalPixel)
    {
        
$gray $this->GrayscaleValue($OriginalPixel['red'], $OriginalPixel['green'], $OriginalPixel['blue']);
        return array(
'red' => $gray'green' => $gray'blue' => $gray);
    }

    function 
GrayscaleValue($r$g$b)
    {
        return 
round(($r 0.30) + ($g 0.59) + ($b 0.11));
    }

    function 
ImageColorAllocateAlphaSafe(&$gdimg_hexcolorallocate$R$G$B$alpha false)
    {
        if (
$this->version_compare_replacement(phpversion(), '4.3.2''>=') && ($alpha !== false)){
            return 
ImageColorAllocateAlpha($gdimg_hexcolorallocate$R$G$Bintval($alpha));
        }else{
            return 
ImageColorAllocate($gdimg_hexcolorallocate$R$G$B);
        }
    }

    function 
Desaturate(&$gdimg$amount$color '')
    {
        return 
$this->Colorize($gdimg$amount, ($this->IsHexColor($color) ? $color 'gray'));
    }

    
//////////////////////////////////////////////////////////////
    ////                                                      ////
    ////              p h p U n s h a r p M a s k             ////
    ////                                                      ////
    ////    Unsharp mask algorithm by Torstein H?nsi 2003.    ////
    ////               thoensi_at_netcom_dot_no               ////
    ////               Please leave this notice.              ////
    ////                                                      ////
    //////////////////////////////////////////////////////////////
    /// From: http://vikjavev.no/hovudsida/umtestside.php       //
    //////////////////////////////////////////////////////////////
    
function UnSharpMask(&$img$parameter)
    {
        @list(
$amount$radius$threshold) = explode('|'$parameter);
        
$amount = ($amount $amount 80);
        
$radius = ($radius $radius 0.5);
        
$threshold = (strlen($threshold) ? $threshold 3);
        if (
$this->gd_version() >= 2.0){
            
$this->applyUnsharpMask($img$amount$radius$threshold);
        }else{
            
$this->_debug($function'Skipping unsharp mask because gd_version is "' $this->gd_version() . '"'__FILE____LINE__);
            return 
false;
        }
    }

    function 
applyUnsharpMask(&$img$amount$radius$threshold)
    { 
        
// $img is an image that is already created within php using
        // imgcreatetruecolor. No url! $img must be a truecolor image.
        // Attempt to calibrate the parameters to Photoshop:
        
$amount min($amount500);
        
$amount $amount 0.016;
        if (
$amount == 0){
            return 
true;
        }

        
$radius min($radius50);
        
$radius $radius 2;

        
$threshold min($threshold255);

        
$radius abs(round($radius)); // Only integers make sense.
        
if ($radius == 0){
            return 
true;
        }

        
$w ImageSX($img);
        
$h ImageSY($img);
        
$imgCanvas ImageCreateTrueColor($w$h);
        
$imgCanvas2 ImageCreateTrueColor($w$h);
        
$imgBlur ImageCreateTrueColor($w$h);
        
$imgBlur2 ImageCreateTrueColor($w$h);
        
ImageCopy($imgCanvas$img0000$w$h);
        
ImageCopy($imgCanvas2$img0000$w$h); 
        
// Gaussian blur matrix:
        // 1    2    1
        // 2    4    2
        // 1    2    1
        // ////////////////////////////////////////////////
        // Move copies of the image around one pixel at the time and merge them with weight
        // according to the matrix. The same matrix is simply repeated for higher radii.
        
for ($i 0$i $radius$i++){
            
ImageCopy ($imgBlur$imgCanvas0011$w 1$h 1); // up left
            
ImageCopyMerge($imgBlur$imgCanvas1100$w$h50); // down right
            
ImageCopyMerge($imgBlur$imgCanvas0110$w 1$h33.33333); // down left
            
ImageCopyMerge($imgBlur$imgCanvas1001$w$h 125); // up right
            
ImageCopyMerge($imgBlur$imgCanvas0010$w 1$h33.33333); // left
            
ImageCopyMerge($imgBlur$imgCanvas1000$w$h25); // right
            
ImageCopyMerge($imgBlur$imgCanvas0001$w$h 120); // up
            
ImageCopyMerge($imgBlur$imgCanvas0100$w$h16.666667); // down
            
ImageCopyMerge($imgBlur$imgCanvas0000$w$h50); // center
            
ImageCopy ($imgCanvas$imgBlur0000$w$h); 
            
// During the loop above the blurred copy darkens, possibly due to a roundoff
            // error. Therefore the sharp picture has to go through the same loop to
            // produce a similar image for comparison. This is not a good thing, as processing
            // time increases heavily.
            
ImageCopy ($imgBlur2$imgCanvas20000$w$h);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h50);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h33.33333);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h25);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h33.33333);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h25);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h20);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h16.666667);
            
ImageCopyMerge($imgBlur2$imgCanvas20000$w$h50);
            
ImageCopy ($imgCanvas2$imgBlur20000$w$h);
        } 
        
// Calculate the difference between the blurred pixels and the original
        // and set the pixels
        
for ($x 0$x $w$x++){ // each row
            
for ($y 0$y $h$y++){ // each pixel
                
$rgbOrig ImageColorAt($imgCanvas2$x$y);
                
$rOrig = (($rgbOrig >> 16) &0xFF);
                
$gOrig = (($rgbOrig >> 8) &0xFF);
                
$bOrig = ($rgbOrig &0xFF);

                
$rgbBlur ImageColorAt($imgCanvas$x$y);
                
$rBlur = (($rgbBlur >> 16) &0xFF);
                
$gBlur = (($rgbBlur >> 8) &0xFF);
                
$bBlur = ($rgbBlur &0xFF); 
                
// When the masked pixels differ less from the original
                // than the threshold specifies, they are set to their original value.
                
$rNew = (abs($rOrig $rBlur) >= $threshold) ? max(0min(255, ($amount * ($rOrig $rBlur)) + $rOrig)) : $rOrig;
                
$gNew = (abs($gOrig $gBlur) >= $threshold) ? max(0min(255, ($amount * ($gOrig $gBlur)) + $gOrig)) : $gOrig;
                
$bNew = (abs($bOrig $bBlur) >= $threshold) ? max(0min(255, ($amount * ($bOrig $bBlur)) + $bOrig)) : $bOrig;

                if ((
$rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)){
                    
$pixCol ImageColorAllocate($img$rNew$gNew$bNew);
                    
ImageSetPixel($img$x$y$pixCol);
                }
            }
        }
        
ImageDestroy($imgCanvas);
        
ImageDestroy($imgCanvas2);
        
ImageDestroy($imgBlur);
        
ImageDestroy($imgBlur2);

        return 
true;
    }

    function 
Colorize(&$gdimg$amount$targetColor)
    {
        
$amount = (is_numeric($amount) ? $amount 25);
        
$targetColor = ($this->IsHexColor($targetColor) ? $targetColor 'gray'); 
        
// overridden below for grayscale
        
if ($targetColor != 'gray'){
            
$TargetPixel['red'] = hexdec(substr($targetColor02));
            
$TargetPixel['green'] = hexdec(substr($targetColor22));
            
$TargetPixel['blue'] = hexdec(substr($targetColor42));
        }

        for (
$x 0$x ImageSX($gdimg); $x++){
            for (
$y 0$y ImageSY($gdimg); $y++){
                
$OriginalPixel $this->GetPixelColor($gdimg$x$y);
                if (
$targetColor == 'gray'){
                    
$TargetPixel $this->GrayscalePixel($OriginalPixel);
                }
                foreach (
$TargetPixel as $key => $value){
                    
$NewPixel[$key] = round(max(0min(255, ($OriginalPixel[$key] * ((100 $amount) / 100)) + ($TargetPixel[$key] * ($amount 100)))));
                } 
                
// $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']);
                
$newColor ImageColorAllocate($gdimg$NewPixel['red'], $NewPixel['green'], $NewPixel['blue']);
                
ImageSetPixel($gdimg$x$y$newColor);
            }
        }
        return 
true;
    }

    function 
HistogramAnalysis(&$gdimg$calculateGray false)
    {
        
$ImageSX ImageSX($gdimg);
        
$ImageSY ImageSY($gdimg);
        for (
$x 0$x $ImageSX$x++){
            for (
$y 0$y $ImageSY$y++){
                
$OriginalPixel $this->GetPixelColor($gdimg$x$y);
                @
$Analysis['red'][$OriginalPixel['red']]++;
                @
$Analysis['green'][$OriginalPixel['green']]++;
                @
$Analysis['blue'][$OriginalPixel['blue']]++;
                @
$Analysis['alpha'][$OriginalPixel['alpha']]++;
                if (
$calculateGray){
                    
$GrayPixel $this->GrayscalePixel($OriginalPixel);
                    @
$Analysis['gray'][$GrayPixel['red']]++;
                }
            }
        }
        
$keys = array('red''green''blue''alpha');
        if (
$calculateGray){
            
$keys[] = 'gray';
        }
        foreach (
$keys as $key){
            
ksort($Analysis[$key]);
        }
        return 
$Analysis;
    }

    function 
WhiteBalance(&$gdimg$targetColor '')
    {
        if (
$this->IsHexColor($targetColor)){
            
$targetPixel = array('red' => hexdec(substr($targetColor02)),
                
'green' => hexdec(substr($targetColor22)),
                
'blue' => hexdec(substr($targetColor42))
                );
        }else{
            
$Analysis $this->HistogramAnalysis($gdimgfalse);
            
$targetPixel = array('red' => max(array_keys($Analysis['red'])),
                
'green' => max(array_keys($Analysis['green'])),
                
'blue' => max(array_keys($Analysis['blue']))
                );
        }
        
$grayValue $this->GrayscaleValue($targetPixel['red'], $targetPixel['green'], $targetPixel['blue']);
        
$scaleR $grayValue $targetPixel['red'];
        
$scaleG $grayValue $targetPixel['green'];
        
$scaleB $grayValue $targetPixel['blue'];

        for (
$x 0$x ImageSX($gdimg); $x++){
            for (
$y 0$y ImageSY($gdimg); $y++){
                
$currentPixel $this->GetPixelColor($gdimg$x$y);
                
$newColor $this->ImageColorAllocateAlphaSafe($gdimg,
                    
max(0min(255round($currentPixel['red'] * $scaleR))),
                    
max(0min(255round($currentPixel['green'] * $scaleG))),
                    
max(0min(255round($currentPixel['blue'] * $scaleB))),
                    
$currentPixel['alpha']
                    );
                
ImageSetPixel($gdimg$x$y$newColor);
            }
        }
        return 
true;
    }

    function 
AutoContrast(&$gdimg$band '*'$min = -1$max = -1)
    { 
        
// equivalent of "Auto Contrast" in Adobe Photoshop
        
$Analysis $this->HistogramAnalysis($gdimgtrue);
        
$keys = array('r' => 'red''g' => 'green''b' => 'blue''a' => 'alpha''*' => 'gray');
        if (!isset(
$keys[$band])){
            return 
false;
        }
        
$key $keys[$band]; 
        
// If the absolute brightest and darkest pixels are used then one random
        // pixel in the image could throw off the whole system. Instead, count up/down
        // from the limit and allow 0.1% of brightest/darkest pixels to be clipped to min/max
        
$clip_threshold ImageSX($gdimg) * ImageSX($gdimg) * 0.001;
        if (
$min >= 0){
            
$range_min min($min255);
        }else{
            
$countsum 0;
            for (
$i 0$i <= 255$i++){
                
$countsum += @$Analysis[$key][$i];
                if (
$countsum >= $clip_threshold){
                    
$range_min $i 1;
                    break;
                }
            }
            
$range_min max($range_min0);
        }
        if (
$max >= 0){
            
$range_max max($max255);
        }else{
            
$countsum 0;
            
$threshold ImageSX($gdimg) * ImageSX($gdimg) * 0.001// 0.1% of brightest and darkest pixels can be clipped
            
for ($i 255$i >= 0$i--){
                
$countsum += @$Analysis[$key][$i];
                if (
$countsum >= $clip_threshold){
                    
$range_max $i 1;
                    break;
                }
            }
            
$range_max min($range_max255);
        }
        
$range_scale = (($range_max == $range_min) ? : (255 / ($range_max $range_min)));
        if ((
$range_min == 0) && ($range_max == 255)){ 
            
// no adjustment neccesary - don't waste CPU time!
            
return true;
        }

        
$ImageSX ImageSX($gdimg);
        
$ImageSY ImageSY($gdimg);
        for (
$x 0$x $ImageSX$x++){
            for (
$y 0$y $ImageSY$y++){
                
$OriginalPixel $this->GetPixelColor($gdimg$x$y);
                if (
$band == '*'){
                    
$new['red'] = min(255max(0, ($OriginalPixel['red'] - $range_min) * $range_scale));
                    
$new['green'] = min(255max(0, ($OriginalPixel['green'] - $range_min) * $range_scale));
                    
$new['blue'] = min(255max(0, ($OriginalPixel['blue'] - $range_min) * $range_scale));
                    
$new['alpha'] = min(255max(0, ($OriginalPixel['alpha'] - $range_min) * $range_scale));
                }else{
                    
$new $OriginalPixel;
                    
$new[$key] = min(255max(0, ($OriginalPixel[$key] - $range_min) * $range_scale));
                }
                
$newColor $this->ImageColorAllocateAlphaSafe($gdimg$new['red'], $new['green'], $new['blue'], $new['alpha']);
                
ImageSetPixel($gdimg$x$y$newColor);
            }
        }

        return 
true;
    }

    function 
GetTempName()
    {
        return 
tempnam($this->temp_directory'temp_thumb');
    }
?>
Back to top
View user's profile Send private message
amnuts
Site Admin


Joined: 01 Sep 2002
Posts: 662
Location: East Sussex, England

PostPosted: Tue Aug 30, 2005 3:40 am    Post subject: Reply with quote

phpThumb is excellent - it provides a lot of filters, doesn't it?

Other than crop canvas, a few of my other simpler classes might also interest you:

http://php.amnuts.com/index.php?do=view&id=9
http://php.amnuts.com/index.php?do=view&id=15
http://php.amnuts.com/index.php?do=view&id=16

Andy
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger MSN Messenger
nation-x
Newbie


Joined: 28 Aug 2005
Posts: 6

PostPosted: Tue Aug 30, 2005 8:33 am    Post subject: Reply with quote

amnuts wrote:
phpThumb is excellent - it provides a lot of filters, doesn't it?

Other than crop canvas, a few of my other simpler classes might also interest you:

http://php.amnuts.com/index.php?do=view&id=9
http://php.amnuts.com/index.php?do=view&id=15
http://php.amnuts.com/index.php?do=view&id=16

Andy


I like your classes, Andy. Smile phpThumb is nice but I found that the shear immensity of it causes speed issues. I also had alot of other issues with it hanging on certain methods. He does have some great filters but I borrowed the ones that I thought had the best practical uses... other than those I would recommend your class for image effects.
Back to top
View user's profile Send private message
amnuts
Site Admin


Joined: 01 Sep 2002
Posts: 662
Location: East Sussex, England

PostPosted: Tue Aug 30, 2005 9:32 am    Post subject: Reply with quote

That's very nice of you to sa. Cheers, mate! Smile
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger MSN Messenger
nation-x
Newbie


Joined: 28 Aug 2005
Posts: 6

PostPosted: Tue Jul 11, 2006 10:16 am    Post subject: Reply with quote

bump for other people
Back to top
View user's profile Send private message
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    php.amnuts.com Forum Index -> Crop Canvas All times are GMT - 5 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group