/ 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
Comments
 Subscribe to comments
                    Subscribe to comments
                
                