/ Published in: PHP
I’ve been working on a CMS lately and having to create thumbnails for uploaded images is always a pain, lots of maths working out the correct sizes and such, so I’ve created a fairly small script to manipulate images in an object-oriented style.
Expand |
Embed | Plain Text
Copy this code and paste it in your HTML
<?php /** * Image * * Class for manipulating images as PHP objects * * @package default * @author Dom Hastings */ class Image { /** * options * * @var array Contains the options for the functions * @access private */ // array Load options // integer Force the input type of image 'forceType' => false ), // array Resizing specific options // boolean Whether or not to force the resize (true) or preserve the ratio 'force' => false ), // array Cutout specific options // mixed If null will default to taking the cutout from the absolute center of the image, otherwise uses the co-ordinates specified 'offsetX' => null, 'offsetY' => null, // mixed If null defaults to the smallest possible size, otherwise resizes (forced) to the specified size 'sourceX' => null, 'sourceY' => null ), // array Whitespace specific options // string HTML hex code for the 'white' space 'color' => '#ffffff', // integer Transparency value (see http://php.net/imagecolorallocatealpha) 'transparency' => 0, // string Filename for applying as a background image 'image' => '', // dimensions for scaling the image 'scaleX' => null, 'scaleY' => null, // offsets for placing the image 'offsetX' => 0, 'offsetY' => 0 ), // array Watermarking options // mixed If null will default to taking the placing the watermark in the absolute center of the image, otherwise uses the co-ordinates specified 'offsetX' => null, 'offsetY' => null, // boolean Repeats the image on the specified axis 'repeatX' => true, 'repeatY' => true ), // array Text options // string The font file to use (TTF) 'font' => '', // integer The font size in px (GD) or pt (GD2) 'size' => 10, // integer The angle 'angle' => 0, // string HTML colour code 'color' => '#000', // integer Transparency value (see http://php.net/imagecolorallocatealpha) 'transparency' => 0 ), // array Line options // array The style of the line (see http://php.net/imagesetstyle) // integer The line size in px 'size' => 1, // string HTML colour code 'color' => '#000', // integer Transparency value (see http://php.net/imagecolorallocatealpha) 'transparency' => 0 ), // array Line options // array The style of the line (see http://php.net/imagesetstyle) // integer The line size in px 'size' => 1, // string HTML colour code 'color' => '#000', // integer Transparency value (see http://php.net/imagecolorallocatealpha) 'transparency' => 0, // boolean If the box is filled or not 'filled' => true ), // array Outputting options // integer Force the output type of image 'forceType' => false, // array File options // boolean Whether to append the default extension 'extension' => false ), // array JPEG options // integer The quality parameter of imagejpeg() (http://php.net/imagejpeg) 'quality' => 85 ), // array PNG options // integer The quality parameter of imagepng() (http://php.net/imagepng) 'quality' => 1, // integer The filters parameter... 'filters' => PNG_ALL_FILTERS ) ) ); /** * filename * * @var string The filename of the source image * @access private */ private $filename = ''; /** * source * * @var resource The GD image resource * @access private */ private $source = null; /** * current * * @var resource The GD image resource * @access private */ private $current = null; /** * info * * @var array The data from getimagesize() (http://php.net/function.getimagesize) * @access private */ private $info = null; /** * __construct * * The constructor for the Image object * * @param string $f The filename of the source image * @param array $o The options for the object * @access public * @author Dom Hastings */ // store the filename $this->filename = $f; // load the image $this->load(); } else { throw new Exception('Imgae::__construct: Unable to load image \''.$f.'\'.'); } } /** * __get * * Magic method wrapper for specific properties * * @param string $p The property being retrieved * @return mixed The return value of the function called * @access public * @author Dom Hastings */ public function __get($p) { // only run this function if the image loaded successfully if (!$this->source) { throw new Exception('Image::__get: No image loaded.'); } // switch the property switch ($p) { // return the image width case 'x': case 'width': return $this->x(); break; // return the image height case 'y': case 'height': return $this->y(); break; // return the image width case 'currentX': case 'currentWidth': return $this->currentX(); break; // return the image height case 'currentY': case 'currentHeight': return $this->currentY(); break; // return the image size ratio case 'ratio': return $this->x() / $this->y(); break; // return the image size details case 'size': break; // return the image information case 'mimetype': return $this->info[3]; break; // return the image information case 'extension': ); break; // return the image information case 'imagetype': return $this->info[2]; break; // return the image information case 'info': return $this->info; break; // not caught default: throw new Exception('Image::__get: Undefined property'); break; } } /** * __set * * Magic method wrapper for setting values * * @param string $p The property being 'set' * @param mixed $v The value to 'set' property to * @return void * @access public * @author Dom Hastings */ public function __set($p, $v) { switch ($p) { case 'width': case 'x': $this->scale($v, 0); break; case 'height': case 'y': $this->scale(0, $v); break; case 'watermark': $this->watermark($v); break; case 'type': $this->options['output']['forceType'] = $v; break; default: break; } } /** * load * * Loads the image and saves the details * * @return void * @access private * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); // get the image details stored $this->info(); // if we're forcing a read type // use it $imageType = $options['forceType']; } else { // otherwise use the discovered type $imageType = $this->info[2]; } // if the image loading failed if (!$this->source) { throw new Exception('Imgae::load: Unable to load image \''.$this->filename.'\'.'); } } /** * loadFile * * Loads an image image from a file * * @param string f The filename * @param string imageType The type of image * @return resource The loaded image * @access private * @author Dom Hastings */ private function loadFile($f = null, $imageType = null) { // switch the type and load using the correct function switch ($imageType) { case IMAGETYPE_GIF: break; case IMAGETYPE_JPEG: case IMAGETYPE_JPEG2000: case IMAGETYPE_JPC: case IMAGETYPE_JP2: case IMAGETYPE_JPX: break; case IMAGETYPE_PNG: break; case IMAGETYPE_BMP: case IMAGETYPE_WBMP: break; case IMAGETYPE_XBM: break; case IMAGETYPE_TIFF_II: case IMAGETYPE_TIFF_MM: case IMAGETYPE_IFF: case IMAGETYPE_JB2: case IMAGETYPE_SWF: case IMAGETYPE_PSD: case IMAGETYPE_SWC: // case IMAGETYPE_ICO: default: $resource = null; break; } return $resource; } /** * output * * Output the image * * @param string $f (Optional) The filename to output to, if this is omitted the image is output to the browser * @return void * @access private * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); // if we're forcing an output type $imageType = $options['forceType']; } else { $imageType = $this->info[2]; } // use the correct output function switch ($imageType) { case IMAGETYPE_GIF: break; case IMAGETYPE_JPEG: case IMAGETYPE_JPEG2000: case IMAGETYPE_JPC: case IMAGETYPE_JP2: case IMAGETYPE_JPX: break; case IMAGETYPE_PNG: break; case IMAGETYPE_BMP: case IMAGETYPE_WBMP: break; case IMAGETYPE_XBM: break; case IMAGETYPE_TIFF_II: case IMAGETYPE_TIFF_MM: case IMAGETYPE_IFF: case IMAGETYPE_JB2: case IMAGETYPE_SWF: case IMAGETYPE_PSD: case IMAGETYPE_SWC: // case IMAGETYPE_ICO: default: break; } } /** * write * * Writes the output data to the specified filename * * @param string $f The filename * @return string The filename written to * @access public * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); if ($this->options['output']['forceType']) { $imageType = $this->options['output']['forceType']; } else { $imageType = $this->info[2]; } $f .= $this->extension; } $this->output($f); return $f; } /** * resource * * Returns the current image as a resource * * @return void * @access public * @author Dom Hastings */ public function resource() { } /** * info * * Gets information about the current image * * @return void * @access private * @author Dom Hastings */ private function info($f = null) { // if the filename is empty // stores the image information inside the object } else { // it's not the main image so return it directly } } /** * x * * Returns the width of the image * * @param string $a Reads the image directly, otherwise uses the cached information form load * @return integer The width of the image * @access public * @author Dom Hastings */ public function x($a = false) { if ($a) { } else { $this->info(); } return $this->info[0]; } } /** * currentX * * Returns the width of the thumb image * * @param string $a Reads the image directly, otherwise uses the cached information form load * @return integer The width of the image * @access public * @author Dom Hastings */ public function currentX() { } } /** * y * * Returns the height of the image * * @param boolean $a Reads the image directly, otherwise uses the cached information form load * @return integer The height of the image * @access public * @author Dom Hastings */ public function y($a = false) { if ($a) { } else { $this->info(); } return $this->info[1]; } } /** * currentY * * Returns the height of the current image * * @param boolean $a Reads the image directly, otherwise uses the cached information form load * @return integer The height of the image * @access public * @author Dom Hastings */ public function currentY($a = false) { } } /** * scale * * Scales the current image to the dimensions specified, using the options specified * * @param integer $x The desired width * @param integer $y The desired height * @param array $options See main options block at top of file * @return resource The new image * @access public * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); // if we're not forcing the size // check we're not trying to enlarge the image if ($x > $this->x) { $x = $this->x; } if ($y > $this->y) { $y = $this->y; } // if neither dimension is specified if ($x == 0 && $y == 0) { throw new Exception('Image::scale: At least one dimension must be spcified to scale an image.'); } elseif ($x > 0 && $y > 0) { // maths! $destX = $x; if ($destY > $y) { $destY = $y; } } elseif ($x == 0) { $destY = $y; } elseif ($y == 0) { $destX = $x; } } else { $destX = $x; $destY = $y; } // create the destination // resample the image as specified throw new Exception('Image::scale: Error scaling image'); } return $dest; } /** * cutout * * Returns a selected portion of the image after optionally resizing it * * @param integer $x The desired width * @param integer $y The desired height * @param array $options * @return resource The new image * @access public * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); // if the source image dimensions haven't been specified, work them out as best you can // more maths! if ($this->x >= $this->y) { // landscape $scaleY = $y; if ($scaleX < $x) { $scaleX = $x; } } else { // portrait $scaleX = $x; if ($scaleY < $y) { $scaleY = $y; } } } else { $scaleX = $options['scaleX']; $scaleY = $options['scaleY']; } // scale the image // if the offset hasn't been specified // calculate the center } else { $offsetX = $options['offsetX']; $offsetY = $options['offsetY']; } // create the destination // cut it out throw new Exception('Image::scale: Error cutting out image'); } return $dest; } /** * whitespace * * Returns a scaled version of the image with any white space on the base filled with an image or a colour, depending on options specified * * @param string $x * @param string $y * @param string $options * @return void * @access public * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); // if we're using an image background // load it $orig = new Image($options['image']); $dest = $orig->resource(); // else if it's just a colour // create the base image // extract the int values of the colour // allocate the colour // fill it // else, we aren't keeping any whitespace, so just scale it } else { return $this->scale($x, $y); } // if scaling options have been set // use them $scaleX = $options['scaleX']; $scaleY = $options['scaleY']; 'force' => true ); } else { // otherwise assume the passed options $scaleX = $x; $scaleY = $y; } // scale the image $source = $this->scale($scaleX, $scaleY, $options); // extract the new height and width $scaleX = $this->currentX; $scaleY = $this->currentY; // determine the offset } else { $offsetX = $options['offsetX']; $offsetY = $options['offsetY']; } // overlay it throw new Exception('Image::scale: Error whitespacing image'); } return $dest; } /** * watermark * * Watermarks the current image with the specified image * * @param string $i The image to use as a watermark * @param array $options The options * @return resource The watermarked image * @access public * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); throw new Exception('Image::watermark: Missing watermark image \''.$i.'\'.'); } // load the watermark $watermark = new Image($i); // determine the offset } else { $offsetX = $options['offsetX']; $offsetY = $options['offsetY']; } // overlay it $offsetX = $offsetY = 0; // rows for ($i = $offsetY; $i < $this->currentY; $i += $watermark->y) { // cols for ($j = $offsetX; $j < $this->currentX; $j += $watermark->x) { throw new Exception('Image::scale: Error watermarking image.'); } } } $offsetX = 0; for ($i = $offsetX; $i <= $this->currentX; $i += $watermark->x) { throw new Exception('Image::scale: Error watermarking image.'); } } $offsetY = 0; for ($i = $offsetY; $i <= $this->currentY; $i += $watermark->y) { throw new Exception('Image::scale: Error watermarking image.'); } } } else { if (!imagecopy($dest, $watermark->resource(), $offsetX, $offsetY, 0, 0, $watermark->x, $watermark->y)) { throw new Exception('Image::scale: Error watermarking image.'); } } return $dest; } /** * hexToRGB * * Returns the integer colour values from an HTML hex code * * @param string $h The HTML hex code * @return array The integer colour values * @access public * @author Dom Hastings */ private function hexToRGB($h) { // strip off the # if it's there ); ); } else { // default to white } } /** * addText * * Adds the specified text to the image at the specified location * * @param string $t The text to add to the image * @param integer $x The x co-ordinate of the text * @param integer $y The y co-ordinate of the text * @param array $options The options * @return array Results from imagettftext() * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); // check the font file exists throw new Exception('Imge::addText: Unable to find font file \''.$options['font'].'\''); } } else { throw new Exception('Imge::addText: Unable to find font file \''.$options['font'].'\''); } } return imagettftext($this->current, $options['size'], $options['angle'], $x, $y, $colour, $options['font'], $text); } /** * drawLine * * Draws a line from the co-ordinates in array start to the co-ordinates in array finish using the GD library function * * @param array $start The start point index 0 should be the x co-ordinate, 1 the y * @param array $finish The end point index 0 should be the x co-ordinate, 1 the y * @param array $options The options * @return mixed The result from imageline() * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); throw new Exception('Image::drawLine: Arguments 0 and 1 must be arrays.'); } } } /** * drawBox * * Draws a box from the co-ordinates in array start to the co-ordinates in array finish using the GD library function * * @param array $start The start point index 0 should be the x co-ordinate, 1 the y * @param array $finish The end point index 0 should be the x co-ordinate, 1 the y * @param array $options The options * @return mixed The result from imagerectangle() * @author Dom Hastings */ // merge in the options $options = array_merge_recursive_distinct( ); throw new Exception('Image::drawLine: Arguments 0 and 1 must be arrays.'); } } } else { } } } /** * array_merge_recursive_distinct * * Recursively process an array merge all child nodes together * * @return array * @author Dom Hastings */ function array_merge_recursive_distinct() { case 0: break; case 1: break; default: foreach ($a as $i => $b) { } foreach ($b as $k => $v) { $s[] = $v; } else { $s[$k] = array_merge_recursive_distinct($s[$k], $v); } else { $s[$k] = $v; } } else { $s[$k] = $v; } } } } break; } return $s; } }
URL: http://www.dom111.co.uk/blog/coding/php-object-oriented-image-manipulation/156