** Filename......: GD.php ** Last changed..: 30 Aug 2003 ** Notes.........: Orginal is from PEAR **/ // +----------------------------------------------------------------------+ // | PHP Version 4 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997-2002 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.02 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Peter Bowyer | // | Alan Knowles | // +----------------------------------------------------------------------+ // // Usage : // $img = new Image_Transform_GD(); // $angle = -78; // $img->load('magick.png'); // // if($img->rotate($angle,array('autoresize'=>true,'color_mask'=>array(255,0,0)))){ // $img->addText(array('text'=>"Rotation $angle",'x'=>0,'y'=>100,'font'=>'/usr/share/fonts/default/TrueType/cogb____.ttf')); // $img->display(); // } else { // echo "Error"; // } // // // $Id: GD.php,v 1.10 2009/03/27 08:20:44 gustafn Exp $ // // Image Transformation interface using the GD library // require_once "../ImageManager/Classes/Transform.php"; Class Image_Transform_Driver_GD extends Image_Transform { /** * Holds the image file for manipulation */ var $imageHandle = ''; /** * Holds the original image file */ var $old_image = ''; /** * Check settings * * @return mixed true or or a PEAR error object on error * * @see PEAR::isError() */ function Image_Transform_GD() { return; } // End function Image /** * Load image * * @param string filename * * @return mixed none or a PEAR error object on error * @see PEAR::isError() */ function load($image) { $this->uid = md5($_SERVER['REMOTE_ADDR']); $this->image = $image; $this->_get_image_details($image); $functionName = 'ImageCreateFrom' . $this->type; if(function_exists($functionName)) { $this->imageHandle = $functionName($this->image); if ( $this->type == 'png') { imageAlphaBlending($this->imageHandle, false); imageSaveAlpha($this->imageHandle, true); } } } // End load /** * addText * * @param array options Array contains options * array( * 'text' The string to draw * 'x' Horizontal position * 'y' Vertical Position * 'Color' Font color * 'font' Font to be used * 'size' Size of the fonts in pixel * 'resize_first' Tell if the image has to be resized * before drawing the text * ) * * @return none * @see PEAR::isError() */ function addText($params) { $default_params = array( 'text' => 'This is Text', 'x' => 10, 'y' => 20, 'color' => array(255,0,0), 'font' => 'Arial.ttf', 'size' => '12', 'angle' => 0, 'resize_first' => false // Carry out the scaling of the image before annotation? Not used for GD ); $params = array_merge($default_params, $params); extract($params); if( !is_array($color) ){ if ($color[0]=='#'){ $this->colorhex2colorarray( $color ); } else { include_once('Image/Transform/Driver/ColorsDefs.php'); $color = isset($colornames[$color])?$colornames[$color]:false; } } $c = imagecolorresolve ($this->imageHandle, $color[0], $color[1], $color[2]); if ('ttf' == substr($font, -3)) { ImageTTFText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text); } else { ImagePSText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text); } return true; } // End addText /** * Rotate image by the given angle * Uses a fast rotation algorythm for custom angles * or lines copy for multiple of 90 degrees * * @param int $angle Rotation angle * @param array $options array( 'autoresize'=>true|false, * 'color_mask'=>array(r,g,b), named color or #rrggbb * ) * @author Pierre-Alain Joye * @return mixed none or a PEAR error object on error * @see PEAR::isError() */ function rotate($angle, $options=null) { if(function_exists('imagerotate')) { $white = imagecolorallocatealpha ($this->imageHandle, 255, 255, 255, 127); $this->imageHandle = imagerotate($this->imageHandle, $angle, $white); return true; } if ( $options==null ){ $autoresize = true; $color_mask = array(105,255,255); } else { extract( $options ); } while ($angle <= -45) { $angle += 360; } while ($angle > 270) { $angle -= 360; } $t = deg2rad($angle); if( !is_array($color_mask) ){ if ($color[0]=='#'){ $this->colorhex2colorarray( $color_mask ); } else { include_once('Image/Transform/Driver/ColorDefs.php'); $color = isset($colornames[$color_mask])?$colornames[$color_mask]:false; } } // Do not round it, too much lost of quality $cosT = cos($t); $sinT = sin($t); $img =& $this->imageHandle; $width = $max_x = $this->img_x; $height = $max_y = $this->img_y; $min_y = 0; $min_x = 0; $x1 = round($max_x/2,0); $y1 = round($max_y/2,0); if ( $autoresize ){ $t = abs($t); $a = round($angle,0); switch((int)($angle)){ case 0: $width2 = $width; $height2 = $height; break; case 90: $width2 = $height; $height2 = $width; break; case 180: $width2 = $width; $height2 = $height; break; case 270: $width2 = $height; $height2 = $width; break; default: $width2 = (int)(abs(sin($t) * $height + cos($t) * $width)); $height2 = (int)(abs(cos($t) * $height+sin($t) * $width)); } $width2 -= $width2%2; $height2 -= $height2%2; $d_width = abs($width - $width2); $d_height = abs($height - $height2); $x_offset = $d_width/2; $y_offset = $d_height/2; $min_x2 = -abs($x_offset); $min_y2 = -abs($y_offset); $max_x2 = $width2; $max_y2 = $height2; } $img2 = @$this->newImgPreserveAlpha( imagecreateTrueColor($width2,$height2) ); if ( !is_resource($img2) ){ return false;/*PEAR::raiseError('Cannot create buffer for the rotataion.', null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);*/ } $this->img_x = $width2; $this->img_y = $height2; imagepalettecopy($img2,$img); $mask = imagecolorallocatealpha ($img2,$color_mask[0],$color_mask[1],$color_mask[2],127); // use simple lines copy for axes angles switch((int)($angle)){ case 0: imagefill ($img2, 0, 0,$mask); for ($y=0; $y < $max_y; $y++) { for ($x = $min_x; $x < $max_x; $x++){ $c = @imagecolorat ( $img, $x, $y); imagesetpixel($img2,$x+$x_offset,$y+$y_offset,$c); } } break; case 90: imagefill ($img2, 0, 0,$mask); for ($x = $min_x; $x < $max_x; $x++){ for ($y=$min_y; $y < $max_y; $y++) { $c = imagecolorat ( $img, $x, $y); imagesetpixel($img2,$max_y-$y-1,$x,$c); } } break; case 180: imagefill ($img2, 0, 0,$mask); for ($y=0; $y < $max_y; $y++) { for ($x = $min_x; $x < $max_x; $x++){ $c = @imagecolorat ( $img, $x, $y); imagesetpixel($img2, $max_x2-$x-1, $max_y2-$y-1, $c); } } break; case 270: imagefill ($img2, 0, 0,$mask); for ($y=0; $y < $max_y; $y++) { for ($x = $max_x; $x >= $min_x; $x--){ $c = @imagecolorat ( $img, $x, $y); imagesetpixel($img2,$y,$max_x-$x-1,$c); } } break; // simple reverse rotation algo default: $i=0; for ($y = $min_y2; $y < $max_y2; $y++){ // Algebra :) $x2 = round((($min_x2-$x1) * $cosT) + (($y-$y1) * $sinT + $x1),0); $y2 = round((($y-$y1) * $cosT - ($min_x2-$x1) * $sinT + $y1),0); for ($x = $min_x2; $x < $max_x2; $x++){ // Check if we are out of original bounces, if we are // use the default color mask if ( $x2>=0 && $x2<$max_x && $y2>=0 && $y2<$max_y ){ $c = imagecolorat ( $img, $x2, $y2); } else { $c = $mask; } imagesetpixel($img2,$x+$x_offset,$y+$y_offset,$c); // round verboten! $x2 += $cosT; $y2 -= $sinT; } } break; } $this->old_image = $this->imageHandle; $this->imageHandle = $img2; return true; } /** * Resize Action * * For GD 2.01+ the new copyresampled function is used * It uses a bicubic interpolation algorithm to get far * better result. * * @param int $new_x new width * @param int $new_y new height * * @return true on success or pear error * @see PEAR::isError() */ function _resize($new_x, $new_y) { if ($this->resized === true) { return false; /*PEAR::raiseError('You have already resized the image without saving it. Your previous resizing will be overwritten', null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);*/ } if(function_exists('ImageCreateTrueColor')){ $new_img = $this->newImgPreserveAlpha( ImageCreateTrueColor($new_x,$new_y) ); } else { $new_img =ImageCreate($new_x,$new_y); } if(function_exists('ImageCopyResampled')){ ImageCopyResampled($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y); } else { ImageCopyResized($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y); } $this->old_image = $this->imageHandle; $this->imageHandle = $new_img; $this->resized = true; $this->new_x = $new_x; $this->new_y = $new_y; return true; } /** * Crop the image * * @param int $crop_x left column of the image * @param int $crop_y top row of the image * @param int $crop_width new cropped image width * @param int $crop_height new cropped image height */ function crop($new_x, $new_y, $new_width, $new_height) { if(function_exists('ImageCreateTrueColor')){ $new_img = $this->newImgPreserveAlpha(ImageCreateTrueColor($new_width,$new_height)); } else { $new_img =ImageCreate($new_width,$new_height); } if(function_exists('ImageCopyResampled')){ ImageCopyResampled($new_img, $this->imageHandle, 0, 0, $new_x, $new_y,$new_width,$new_height,$new_width,$new_height); } else { ImageCopyResized($new_img, $this->imageHandle, 0, 0, $new_x, $new_y, $new_width,$new_height,$new_width,$new_height); } $this->old_image = $this->imageHandle; $this->imageHandle = $new_img; $this->resized = true; $this->new_x = $new_x; $this->new_y = $new_y; return true; } /** * Flip the image horizontally or vertically * * @param boolean $horizontal true if horizontal flip, vertical otherwise */ function flip($horizontal) { if(!$horizontal) { $this->rotate(180); } $width = imagesx($this->imageHandle); $height = imagesy($this->imageHandle); for ($j = 0; $j < $height; $j++) { $left = 0; $right = $width-1; while ($left < $right) { //echo " j:".$j." l:".$left." r:".$right."\n
"; $t = imagecolorat($this->imageHandle, $left, $j); imagesetpixel($this->imageHandle, $left, $j, imagecolorat($this->imageHandle, $right, $j)); imagesetpixel($this->imageHandle, $right, $j, $t); $left++; $right--; } } return true; } /** * Adjust the image gamma * * @param float $outputgamma * * @return none */ function gamma($outputgamma=1.0) { ImageGammaCorrect($this->imageHandle, 1.0, $outputgamma); } function paletteToTrueColorWithTransparency() { $oldImg = $this->imageHandle; $newImg = $this->newImgPreserveAlpha( imagecreatetruecolor($this->img_x,$this->img_y) ); imagecopy($newImg,$oldImg,0,0,0,0,$this->img_x,$this->img_y); $this->imageHandle = $newImg; } function newImgPreserveAlpha($newImg) { if ( $this->type == 'jpeg') return $newImg; // Turn off transparency blending (temporarily) imagealphablending($newImg, false); // Create a new transparent color for image if ( $transparent = imagecolortransparent($this->imageHandle) >= 0 ) { if (imageistruecolor($this->imageHandle)) { $red = ($transparent & 0xFF0000) >> 16; $green = ($transparent & 0x00FF00) >> 8; $blue = ($transparent & 0x0000FF); $color_values = array('red' => $red, 'green' => $green, 'blue' => $blue); } else { $color_values = imagecolorsforindex($this->imageHandle,$transparent); } $color_values = imagecolorsforindex($this->imageHandle,$transparent); $color = imagecolorallocatealpha($newImg, $color_values['red'],$color_values['green'],$color_values['blue'], 127); $colort = imagecolorallocate($newImg, $color_values['red'],$color_values['green'],$color_values['blue']); } else { $color = imagecolorallocatealpha($newImg, 252, 2, 252, 127); $colort = imagecolorallocate($newImg, 252, 2, 252); } imagecolortransparent($newImg,$colort); // Completely fill the background of the new image with allocated color. imagefill($newImg, 0, 0, $color); // Restore transparency blending imagesavealpha($newImg, true); return $newImg; } function preserveTransparencyForPalette() { $new_img = imagecreatetruecolor($this->img_x,$this->img_y); $truecolor = imageistruecolor($this->imageHandle); $transparent = imagecolorallocate($new_img, 252,2,252); // nasty pinkish purple that hopefully doesn't exist in the image imagecolortransparent($new_img, $transparent); for ($i=0;$i<$this->img_y;$i++) { for ($j=0;$j<$this->img_x;$j++) { $c = imagecolorat($this->imageHandle,$j, $i); if ($truecolor) { $a = ($c >> 24) & 0xFF; $r = ($c >> 16) & 0xFF; $g = ($c >> 8) & 0xFF; $b = $c & 0xFF; $color_values = array('red' => $r, 'green' => $g, 'blue' => $b, 'alpha' => $a); } else { $color_values = imagecolorsforindex($this->imageHandle,$c); } if ($color_values['alpha'] >= 126) { imagesetpixel($new_img, $j, $i, $transparent); } else { imagesetpixel($new_img, $j, $i, $c); } } } $this->imageHandle = $new_img; } /** * Save the image file * * @param string $filename the name of the file to write to * @param int $quality output DPI, default is 85 * @param string $types define the output format, default * is the current used format * * @return none */ function save($filename, $type = '', $quality = 85) { $type = $type==''? $this->type : $type; $functionName = 'image' . $type; if(function_exists($functionName)) { $this->old_image = $this->imageHandle; if($type=='jpeg') $functionName($this->imageHandle, $filename, $quality); else $functionName($this->imageHandle, $filename); $this->imageHandle = $this->old_image; $this->resized = false; } } // End save /** * Display image without saving and lose changes * * @param string type (JPG,PNG...); * @param int quality 75 * * @return none */ function display($type = '', $quality = 75) { if ($type != '') { $this->type = $type; } $functionName = 'Image' . $this->type; if(function_exists($functionName)) { header('Content-type: image/' . strtolower($this->type)); $functionName($this->imageHandle, '', $quality); $this->imageHandle = $this->old_image; $this->resized = false; ImageDestroy($this->old_image); $this->free(); } } /** * Destroy image handle * * @return none */ function free() { if ($this->imageHandle){ ImageDestroy($this->imageHandle); } } } // End class ImageGD ?>