├── .gitignore ├── .travis.yml ├── README.md ├── composer.json ├── examples ├── README ├── crop_basic.php ├── crop_basic_fromstring.php ├── crop_fromcenter.php ├── reflection.php ├── remote_image_resize.php ├── resize_adaptive.php ├── resize_basic.php ├── resize_percentage.php ├── rotate_advanced.php ├── rotate_basic.php ├── save_differentformat.php └── test.jpg ├── phpunit.xml.dist ├── src └── PHPThumb │ ├── GD.php │ ├── PHPThumb.php │ ├── PluginInterface.php │ └── Plugins │ └── Reflection.php └── tests ├── PHPThumb ├── GDTest.php └── LoadTest.php └── resources ├── test.gif ├── test.jpg └── test.png /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | phpunit.xml 3 | composer.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.3 4 | - 5.4 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://secure.travis-ci.org/masterexploder/PHPThumb.png?branch=master)](http://travis-ci.org/masterexploder/PHPThumb) 2 | 3 | # PHP Thumb 4 | 5 | ## NOTICE - 6 | This project was recently updated to 2.0 and is PSR-0 compliant and supports Composer integration. Some parts of the documentation 7 | are incorrect as they haven't been updated for the new version. Your 1.0 code is not compatible with 2.0! Please review the updated 8 | examples for how to use the new version. 9 | 10 | PHP Thumb is a light-weight image manipulation library 11 | aimed at thumbnail generation. It features the ability to 12 | resize by width, height, and percentage, create custom crops, 13 | or square crops from the center, and rotate the image. You can 14 | also easily add custom functionality to the library through plugins. 15 | It also features the ability to perform multiple manipulations per 16 | instance (also known as chaining), without the need to save and 17 | re-initialize the class with every manipulation. 18 | 19 | More information and documentation is available at the project's wiki: [https://github.com/masterexploder/PHPThumb/wiki](https://github.com/masterexploder/PHPThumb/wiki) 20 | 21 | ## Documentation / Help 22 | 23 | I've tried to thoroughly document things as best I can, but here's a list of places to 24 | find documentation / help: 25 | 26 | - [Documentation](http://wiki.github.com/iselby/PHPThumb/) - Your best friend, the library docs 27 | - [Forums](http://phpthumb.gxdlabs.com/forums) - Got questions, comments, or feedback? This is the place to visit 28 | - [Developer Docs](http://phpthumb.gxdlabs.com/apidocs) - Auto-generated docs for developers… these cover the code itself 29 | 30 | ## License 31 | 32 | PHP Thumb is released under MIT license. 33 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "masterexploder/phpthumb", 3 | "type": "library", 4 | "license": "MIT", 5 | "description": "A library for manipulating images in PHP.", 6 | "keywords": ["image", "resize", "rotate"], 7 | "require": { 8 | "php": ">=5.3.0" 9 | }, 10 | "homepage": "https://github.com/masterexploder/PHPThumb", 11 | "authors": [ 12 | { 13 | "name": "Ian Selby", 14 | "email": "ian@gxdlabs.com" 15 | }, 16 | { 17 | "name": "Jarrod Nettles", 18 | "email": "jarrod.nettles@icloud.com" 19 | } 20 | ], 21 | 22 | "autoload": { 23 | "psr-0": { 24 | "PHPThumb": "src", 25 | "PHPThumb\\Tests": "tests" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | README 2 | 3 | These files contain various examples for using the PHP 4 | Thumb library. Feel free to do with them what you'd like. 5 | 6 | NOTE: The test images contained within are not my work. 7 | DO NOT REDISTRIBUTE OR USE THESE IMAGES OUTSIDE THE SAMPLES. 8 | If you are the owner of the images contained within, let me 9 | know so I can properly credit you or remove the images at 10 | your request. -------------------------------------------------------------------------------- /examples/crop_basic.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->crop(100, 100, 300, 200); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/crop_basic_fromstring.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | 27 | $fileData = file_get_contents('test.jpg'); 28 | 29 | $thumb = new PHPThumb\GD($fileData); 30 | $thumb->crop(100, 100, 300, 200); 31 | 32 | // $imageAsString will contain the image data suitable for saving in a database. 33 | $imageAsString = $thumb->getImageAsString(); 34 | 35 | ?> 36 |

Here's the Image Data:

37 | Note: This should be a bunch of gibberish
38 |
39 | 40 |

Here's that data as an image:

41 | 42 | -------------------------------------------------------------------------------- /examples/crop_fromcenter.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->cropFromCenter(200, 100); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/reflection.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg', array(), array( 29 | new PHPThumb\Plugins\Reflection(40, 40, 80, true, '#a4a4a4') 30 | )); 31 | 32 | $thumb->adaptiveResize(250, 250); 33 | $thumb->show(); 34 | -------------------------------------------------------------------------------- /examples/remote_image_resize.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD('http://phpthumb.gxdlabs.com/wp-content/themes/phpthumb/images/header_bg.png'); 29 | $thumb->resize(200, 200); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/resize_adaptive.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->adaptiveResize(175, 175); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/resize_basic.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->resize(100, 100); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/resize_percentage.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->resizePercent(50); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/rotate_advanced.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->rotateImageNDegrees(180); 30 | $thumb->show(); 31 | -------------------------------------------------------------------------------- /examples/rotate_basic.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->rotateImage('CW'); 30 | $thumb->show(); 31 | 32 | // or: 33 | // $thumb->rotate('CCW'); 34 | -------------------------------------------------------------------------------- /examples/save_differentformat.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @subpackage Examples 23 | * @filesource 24 | */ 25 | 26 | require_once '../vendor/autoload.php'; 27 | 28 | $thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); 29 | $thumb->adaptiveResize(300, 300); 30 | $thumb->save('test.png', 'png'); 31 | -------------------------------------------------------------------------------- /examples/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterexploder/PHPThumb/54b18cd00ab0a00dc90aa9871de0638efa93986a/examples/test.jpg -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | ./tests/PHPThumb/ 17 | 18 | 19 | 20 | 21 | 22 | ./src/ 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/PHPThumb/GD.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright (c) 2009, Ian Selby/Gen X Design 8 | * 9 | * Author(s): Ian Selby 10 | * 11 | * Licensed under the MIT License 12 | * Redistributions of files must retain the above copyright notice. 13 | * 14 | * @author Ian Selby 15 | * @copyright Copyright (c) 2009 Gen X Design 16 | * @link http://phpthumb.gxdlabs.com 17 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 18 | */ 19 | 20 | class GD extends PHPThumb 21 | { 22 | /** 23 | * The prior image (before manipulation) 24 | * 25 | * @var resource 26 | */ 27 | protected $oldImage; 28 | 29 | /** 30 | * The working image (used during manipulation) 31 | * 32 | * @var resource 33 | */ 34 | protected $workingImage; 35 | 36 | /** 37 | * The current dimensions of the image 38 | * 39 | * @var array 40 | */ 41 | protected $currentDimensions; 42 | 43 | /** 44 | * The new, calculated dimensions of the image 45 | * 46 | * @var array 47 | */ 48 | protected $newDimensions; 49 | 50 | /** 51 | * The options for this class 52 | * 53 | * This array contains various options that determine the behavior in 54 | * various functions throughout the class. Functions note which specific 55 | * option key / values are used in their documentation 56 | * 57 | * @var array 58 | */ 59 | protected $options = []; 60 | 61 | /** 62 | * The maximum width an image can be after resizing (in pixels) 63 | * 64 | * @var int 65 | */ 66 | protected $maxWidth; 67 | 68 | /** 69 | * The maximum height an image can be after resizing (in pixels) 70 | * 71 | * @var int 72 | */ 73 | protected $maxHeight; 74 | 75 | /** 76 | * The percentage to resize the image by 77 | * 78 | * @var int 79 | */ 80 | protected $percent; 81 | 82 | /** 83 | * @param string $fileName 84 | * @param array $options 85 | * @param array $plugins 86 | */ 87 | public function __construct($fileName, $options = array(), array $plugins = array()) 88 | { 89 | parent::__construct($fileName, $options, $plugins); 90 | 91 | $this->determineFormat(); 92 | $this->verifyFormatCompatiblity(); 93 | 94 | switch ($this->format) { 95 | case 'GIF': 96 | $this->oldImage = imagecreatefromgif($this->fileName); 97 | break; 98 | case 'JPG': 99 | $this->oldImage = imagecreatefromjpeg($this->fileName); 100 | break; 101 | case 'PNG': 102 | $this->oldImage = imagecreatefrompng($this->fileName); 103 | break; 104 | case 'STRING': 105 | $this->oldImage = imagecreatefromstring($this->fileName); 106 | break; 107 | } 108 | 109 | $this->currentDimensions = array ( 110 | 'width' => imagesx($this->oldImage), 111 | 'height' => imagesy($this->oldImage) 112 | ); 113 | } 114 | 115 | public function __destruct() 116 | { 117 | if (is_resource($this->oldImage)) { 118 | imagedestroy($this->oldImage); 119 | } 120 | 121 | if (is_resource($this->workingImage)) { 122 | imagedestroy($this->workingImage); 123 | } 124 | } 125 | 126 | /** 127 | * Pad an image to desired dimensions. Moves the image into the center and fills the rest with $color. 128 | * @param $width 129 | * @param $height 130 | * @param array $color 131 | * @return GD 132 | */ 133 | public function pad($width, $height, $color = array(255, 255, 255)) 134 | { 135 | // no resize - woohoo! 136 | if ($width == $this->currentDimensions['width'] && $height == $this->currentDimensions['height']) { 137 | return $this; 138 | } 139 | 140 | // create the working image 141 | if (function_exists('imagecreatetruecolor')) { 142 | $this->workingImage = imagecreatetruecolor($width, $height); 143 | } else { 144 | $this->workingImage = imagecreate($width, $height); 145 | } 146 | 147 | // create the fill color 148 | $fillColor = imagecolorallocate( 149 | $this->workingImage, 150 | $color[0], 151 | $color[1], 152 | $color[2] 153 | ); 154 | 155 | // fill our working image with the fill color 156 | imagefill( 157 | $this->workingImage, 158 | 0, 159 | 0, 160 | $fillColor 161 | ); 162 | 163 | // copy the image into the center of our working image 164 | imagecopyresampled( 165 | $this->workingImage, 166 | $this->oldImage, 167 | intval(($width-$this->currentDimensions['width']) / 2), 168 | intval(($height-$this->currentDimensions['height']) / 2), 169 | 0, 170 | 0, 171 | $this->currentDimensions['width'], 172 | $this->currentDimensions['height'], 173 | $this->currentDimensions['width'], 174 | $this->currentDimensions['height'] 175 | ); 176 | 177 | // update all the variables and resources to be correct 178 | $this->oldImage = $this->workingImage; 179 | $this->currentDimensions['width'] = $width; 180 | $this->currentDimensions['height'] = $height; 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * Resizes an image to be no larger than $maxWidth or $maxHeight 187 | * 188 | * If either param is set to zero, then that dimension will not be considered as a part of the resize. 189 | * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will 190 | * also scale the image up to the maximum dimensions provided. 191 | * 192 | * @param int $maxWidth The maximum width of the image in pixels 193 | * @param int $maxHeight The maximum height of the image in pixels 194 | * @return \PHPThumb\GD 195 | */ 196 | public function resize($maxWidth = 0, $maxHeight = 0) 197 | { 198 | // make sure our arguments are valid 199 | if (!is_numeric($maxWidth)) { 200 | throw new \InvalidArgumentException('$maxWidth must be numeric'); 201 | } 202 | 203 | if (!is_numeric($maxHeight)) { 204 | throw new \InvalidArgumentException('$maxHeight must be numeric'); 205 | } 206 | 207 | // make sure we're not exceeding our image size if we're not supposed to 208 | if ($this->options['resizeUp'] === false) { 209 | $this->maxHeight = (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight; 210 | $this->maxWidth = (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth; 211 | } else { 212 | $this->maxHeight = intval($maxHeight); 213 | $this->maxWidth = intval($maxWidth); 214 | } 215 | 216 | // get the new dimensions... 217 | $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']); 218 | 219 | // create the working image 220 | if (function_exists('imagecreatetruecolor')) { 221 | $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 222 | } else { 223 | $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 224 | } 225 | 226 | $this->preserveAlpha(); 227 | 228 | // and create the newly sized image 229 | imagecopyresampled( 230 | $this->workingImage, 231 | $this->oldImage, 232 | 0, 233 | 0, 234 | 0, 235 | 0, 236 | $this->newDimensions['newWidth'], 237 | $this->newDimensions['newHeight'], 238 | $this->currentDimensions['width'], 239 | $this->currentDimensions['height'] 240 | ); 241 | 242 | // update all the variables and resources to be correct 243 | $this->oldImage = $this->workingImage; 244 | $this->currentDimensions['width'] = $this->newDimensions['newWidth']; 245 | $this->currentDimensions['height'] = $this->newDimensions['newHeight']; 246 | 247 | return $this; 248 | } 249 | 250 | /** 251 | * Adaptively Resizes the Image 252 | * 253 | * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the 254 | * remaining overflow (from the center) to get the image to be the size specified 255 | * 256 | * @param int $maxWidth 257 | * @param int $maxHeight 258 | * @return \PHPThumb\GD 259 | */ 260 | public function adaptiveResize($width, $height) 261 | { 262 | // make sure our arguments are valid 263 | if ((!is_numeric($width) || $width == 0) && (!is_numeric($height) || $height == 0)) { 264 | throw new \InvalidArgumentException('$width and $height must be numeric and greater than zero'); 265 | } 266 | 267 | if (!is_numeric($width) || $width == 0) { 268 | $width = ($height * $this->currentDimensions['width']) / $this->currentDimensions['height']; 269 | } 270 | 271 | if (!is_numeric($height) || $height == 0) { 272 | $height = ($width * $this->currentDimensions['height']) / $this->currentDimensions['width']; 273 | } 274 | 275 | // make sure we're not exceeding our image size if we're not supposed to 276 | if ($this->options['resizeUp'] === false) { 277 | $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; 278 | $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; 279 | } else { 280 | $this->maxHeight = intval($height); 281 | $this->maxWidth = intval($width); 282 | } 283 | 284 | $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); 285 | 286 | // resize the image to be close to our desired dimensions 287 | $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 288 | 289 | // reset the max dimensions... 290 | if ($this->options['resizeUp'] === false) { 291 | $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; 292 | $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; 293 | } else { 294 | $this->maxHeight = intval($height); 295 | $this->maxWidth = intval($width); 296 | } 297 | 298 | // create the working image 299 | if (function_exists('imagecreatetruecolor')) { 300 | $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); 301 | } else { 302 | $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); 303 | } 304 | 305 | $this->preserveAlpha(); 306 | 307 | $cropWidth = $this->maxWidth; 308 | $cropHeight = $this->maxHeight; 309 | $cropX = 0; 310 | $cropY = 0; 311 | 312 | // now, figure out how to crop the rest of the image... 313 | if ($this->currentDimensions['width'] > $this->maxWidth) { 314 | $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); 315 | } elseif ($this->currentDimensions['height'] > $this->maxHeight) { 316 | $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); 317 | } 318 | 319 | imagecopyresampled( 320 | $this->workingImage, 321 | $this->oldImage, 322 | 0, 323 | 0, 324 | $cropX, 325 | $cropY, 326 | $cropWidth, 327 | $cropHeight, 328 | $cropWidth, 329 | $cropHeight 330 | ); 331 | 332 | // update all the variables and resources to be correct 333 | $this->oldImage = $this->workingImage; 334 | $this->currentDimensions['width'] = $this->maxWidth; 335 | $this->currentDimensions['height'] = $this->maxHeight; 336 | 337 | return $this; 338 | } 339 | 340 | /** 341 | * Adaptively Resizes the Image and Crops Using a Percentage 342 | * 343 | * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the 344 | * remaining overflow using a provided percentage to get the image to be the size specified. 345 | * 346 | * The percentage mean different things depending on the orientation of the original image. 347 | * 348 | * For Landscape images: 349 | * --------------------- 350 | * 351 | * A percentage of 1 would crop the image all the way to the left, which would be the same as 352 | * using adaptiveResizeQuadrant() with $quadrant = 'L' 353 | * 354 | * A percentage of 50 would crop the image to the center which would be the same as using 355 | * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize() 356 | * 357 | * A percentage of 100 would crop the image to the image all the way to the right, etc, etc. 358 | * Note that you can use any percentage between 1 and 100. 359 | * 360 | * For Portrait images: 361 | * -------------------- 362 | * 363 | * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom 364 | * 365 | * @param int $maxWidth 366 | * @param int $maxHeight 367 | * @param int $percent 368 | * @return \PHPThumb\GD 369 | */ 370 | public function adaptiveResizePercent($width, $height, $percent = 50) 371 | { 372 | // make sure our arguments are valid 373 | if (!is_numeric($width) || $width == 0) { 374 | throw new \InvalidArgumentException('$width must be numeric and greater than zero'); 375 | } 376 | 377 | if (!is_numeric($height) || $height == 0) { 378 | throw new \InvalidArgumentException('$height must be numeric and greater than zero'); 379 | } 380 | 381 | // make sure we're not exceeding our image size if we're not supposed to 382 | if ($this->options['resizeUp'] === false) { 383 | $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; 384 | $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; 385 | } else { 386 | $this->maxHeight = intval($height); 387 | $this->maxWidth = intval($width); 388 | } 389 | 390 | $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); 391 | 392 | // resize the image to be close to our desired dimensions 393 | $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 394 | 395 | // reset the max dimensions... 396 | if ($this->options['resizeUp'] === false) { 397 | $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; 398 | $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; 399 | } else { 400 | $this->maxHeight = intval($height); 401 | $this->maxWidth = intval($width); 402 | } 403 | 404 | // create the working image 405 | if (function_exists('imagecreatetruecolor')) { 406 | $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); 407 | } else { 408 | $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); 409 | } 410 | 411 | $this->preserveAlpha(); 412 | 413 | $cropWidth = $this->maxWidth; 414 | $cropHeight = $this->maxHeight; 415 | $cropX = 0; 416 | $cropY = 0; 417 | 418 | // Crop the rest of the image using the quadrant 419 | 420 | if ($percent > 100) { 421 | $percent = 100; 422 | } elseif ($percent < 1) { 423 | $percent = 1; 424 | } 425 | 426 | if ($this->currentDimensions['width'] > $this->maxWidth) { 427 | // Image is landscape 428 | $maxCropX = $this->currentDimensions['width'] - $this->maxWidth; 429 | $cropX = intval(($percent / 100) * $maxCropX); 430 | 431 | } elseif ($this->currentDimensions['height'] > $this->maxHeight) { 432 | // Image is portrait 433 | $maxCropY = $this->currentDimensions['height'] - $this->maxHeight; 434 | $cropY = intval(($percent / 100) * $maxCropY); 435 | } 436 | 437 | imagecopyresampled( 438 | $this->workingImage, 439 | $this->oldImage, 440 | 0, 441 | 0, 442 | $cropX, 443 | $cropY, 444 | $cropWidth, 445 | $cropHeight, 446 | $cropWidth, 447 | $cropHeight 448 | ); 449 | 450 | // update all the variables and resources to be correct 451 | $this->oldImage = $this->workingImage; 452 | $this->currentDimensions['width'] = $this->maxWidth; 453 | $this->currentDimensions['height'] = $this->maxHeight; 454 | 455 | return $this; 456 | } 457 | 458 | /** 459 | * Adaptively Resizes the Image and Crops Using a Quadrant 460 | * 461 | * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the 462 | * remaining overflow using the quadrant to get the image to be the size specified. 463 | * 464 | * The quadrants available are Top, Bottom, Center, Left, and Right: 465 | * 466 | * 467 | * +---+---+---+ 468 | * | | T | | 469 | * +---+---+---+ 470 | * | L | C | R | 471 | * +---+---+---+ 472 | * | | B | | 473 | * +---+---+---+ 474 | * 475 | * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't 476 | * make sence since only the Left and Right would be available, then the Center quadrant will be used 477 | * to crop. This would have exactly the same result as using adaptiveResize(). 478 | * The same goes if your image is portrait and you choose either the Left or Right quadrants. 479 | * 480 | * @param int $maxWidth 481 | * @param int $maxHeight 482 | * @param string $quadrant T, B, C, L, R 483 | * @return \PHPThumb\GD 484 | */ 485 | public function adaptiveResizeQuadrant($width, $height, $quadrant = 'C') 486 | { 487 | // make sure our arguments are valid 488 | if (!is_numeric($width) || $width == 0) { 489 | throw new \InvalidArgumentException('$width must be numeric and greater than zero'); 490 | } 491 | 492 | if (!is_numeric($height) || $height == 0) { 493 | throw new \InvalidArgumentException('$height must be numeric and greater than zero'); 494 | } 495 | 496 | // make sure we're not exceeding our image size if we're not supposed to 497 | if ($this->options['resizeUp'] === false) { 498 | $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; 499 | $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; 500 | } else { 501 | $this->maxHeight = intval($height); 502 | $this->maxWidth = intval($width); 503 | } 504 | 505 | $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); 506 | 507 | // resize the image to be close to our desired dimensions 508 | $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 509 | 510 | // reset the max dimensions... 511 | if ($this->options['resizeUp'] === false) { 512 | $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; 513 | $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; 514 | } else { 515 | $this->maxHeight = intval($height); 516 | $this->maxWidth = intval($width); 517 | } 518 | 519 | // create the working image 520 | if (function_exists('imagecreatetruecolor')) { 521 | $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); 522 | } else { 523 | $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); 524 | } 525 | 526 | $this->preserveAlpha(); 527 | 528 | $cropWidth = $this->maxWidth; 529 | $cropHeight = $this->maxHeight; 530 | $cropX = 0; 531 | $cropY = 0; 532 | 533 | // Crop the rest of the image using the quadrant 534 | 535 | if ($this->currentDimensions['width'] > $this->maxWidth) { 536 | // Image is landscape 537 | switch ($quadrant) { 538 | case 'L': 539 | $cropX = 0; 540 | break; 541 | case 'R': 542 | $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth)); 543 | break; 544 | case 'C': 545 | default: 546 | $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); 547 | break; 548 | } 549 | } elseif ($this->currentDimensions['height'] > $this->maxHeight) { 550 | // Image is portrait 551 | switch ($quadrant) { 552 | case 'T': 553 | $cropY = 0; 554 | break; 555 | case 'B': 556 | $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight)); 557 | break; 558 | case 'C': 559 | default: 560 | $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); 561 | break; 562 | } 563 | } 564 | 565 | imagecopyresampled( 566 | $this->workingImage, 567 | $this->oldImage, 568 | 0, 569 | 0, 570 | $cropX, 571 | $cropY, 572 | $cropWidth, 573 | $cropHeight, 574 | $cropWidth, 575 | $cropHeight 576 | ); 577 | 578 | // update all the variables and resources to be correct 579 | $this->oldImage = $this->workingImage; 580 | $this->currentDimensions['width'] = $this->maxWidth; 581 | $this->currentDimensions['height'] = $this->maxHeight; 582 | 583 | return $this; 584 | } 585 | 586 | /** 587 | * Resizes an image by a given percent uniformly, 588 | * Percentage should be whole number representation (i.e. 1-100) 589 | * 590 | * @param int $percent 591 | * @return GD 592 | * @throws \InvalidArgumentException 593 | */ 594 | public function resizePercent($percent = 0) 595 | { 596 | if (!is_numeric($percent)) { 597 | throw new \InvalidArgumentException ('$percent must be numeric'); 598 | } 599 | 600 | $this->percent = intval($percent); 601 | 602 | $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']); 603 | 604 | if (function_exists('imagecreatetruecolor')) { 605 | $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 606 | } else { 607 | $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); 608 | } 609 | 610 | $this->preserveAlpha(); 611 | 612 | imagecopyresampled( 613 | $this->workingImage, 614 | $this->oldImage, 615 | 0, 616 | 0, 617 | 0, 618 | 0, 619 | $this->newDimensions['newWidth'], 620 | $this->newDimensions['newHeight'], 621 | $this->currentDimensions['width'], 622 | $this->currentDimensions['height'] 623 | ); 624 | 625 | $this->oldImage = $this->workingImage; 626 | $this->currentDimensions['width'] = $this->newDimensions['newWidth']; 627 | $this->currentDimensions['height'] = $this->newDimensions['newHeight']; 628 | 629 | return $this; 630 | } 631 | 632 | /** 633 | * Crops an image from the center with provided dimensions 634 | * 635 | * If no height is given, the width will be used as a height, thus creating a square crop 636 | * 637 | * @param int $cropWidth 638 | * @param int $cropHeight 639 | * @return \PHPThumb\GD 640 | */ 641 | public function cropFromCenter($cropWidth, $cropHeight = null) 642 | { 643 | if (!is_numeric($cropWidth)) { 644 | throw new \InvalidArgumentException('$cropWidth must be numeric'); 645 | } 646 | 647 | if ($cropHeight !== null && !is_numeric($cropHeight)) { 648 | throw new \InvalidArgumentException('$cropHeight must be numeric'); 649 | } 650 | 651 | if ($cropHeight === null) { 652 | $cropHeight = $cropWidth; 653 | } 654 | 655 | $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; 656 | $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; 657 | 658 | $cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2); 659 | $cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2); 660 | 661 | $this->crop($cropX, $cropY, $cropWidth, $cropHeight); 662 | 663 | return $this; 664 | } 665 | 666 | /** 667 | * Vanilla Cropping - Crops from x,y with specified width and height 668 | * 669 | * @param int $startX 670 | * @param int $startY 671 | * @param int $cropWidth 672 | * @param int $cropHeight 673 | * @return \PHPThumb\GD 674 | */ 675 | public function crop($startX, $startY, $cropWidth, $cropHeight) 676 | { 677 | // validate input 678 | if (!is_numeric($startX)) { 679 | throw new \InvalidArgumentException('$startX must be numeric'); 680 | } 681 | 682 | if (!is_numeric($startY)) { 683 | throw new \InvalidArgumentException('$startY must be numeric'); 684 | } 685 | 686 | if (!is_numeric($cropWidth)) { 687 | throw new \InvalidArgumentException('$cropWidth must be numeric'); 688 | } 689 | 690 | if (!is_numeric($cropHeight)) { 691 | throw new \InvalidArgumentException('$cropHeight must be numeric'); 692 | } 693 | 694 | // do some calculations 695 | $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; 696 | $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; 697 | 698 | // ensure everything's in bounds 699 | if (($startX + $cropWidth) > $this->currentDimensions['width']) { 700 | $startX = ($this->currentDimensions['width'] - $cropWidth); 701 | } 702 | 703 | if (($startY + $cropHeight) > $this->currentDimensions['height']) { 704 | $startY = ($this->currentDimensions['height'] - $cropHeight); 705 | } 706 | 707 | if ($startX < 0) { 708 | $startX = 0; 709 | } 710 | 711 | if ($startY < 0) { 712 | $startY = 0; 713 | } 714 | 715 | // create the working image 716 | if (function_exists('imagecreatetruecolor')) { 717 | $this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight); 718 | } else { 719 | $this->workingImage = imagecreate($cropWidth, $cropHeight); 720 | } 721 | 722 | $this->preserveAlpha(); 723 | 724 | imagecopyresampled( 725 | $this->workingImage, 726 | $this->oldImage, 727 | 0, 728 | 0, 729 | $startX, 730 | $startY, 731 | $cropWidth, 732 | $cropHeight, 733 | $cropWidth, 734 | $cropHeight 735 | ); 736 | 737 | $this->oldImage = $this->workingImage; 738 | $this->currentDimensions['width'] = $cropWidth; 739 | $this->currentDimensions['height'] = $cropHeight; 740 | 741 | return $this; 742 | } 743 | 744 | /** 745 | * Rotates image either 90 degrees clockwise or counter-clockwise 746 | * 747 | * @param string $direction 748 | * @retunrn \PHPThumb\GD 749 | */ 750 | public function rotateImage($direction = 'CW') 751 | { 752 | if ($direction == 'CW') { 753 | $this->rotateImageNDegrees(90); 754 | } else { 755 | $this->rotateImageNDegrees(-90); 756 | } 757 | 758 | return $this; 759 | } 760 | 761 | /** 762 | * Rotates image specified number of degrees 763 | * 764 | * @param int $degrees 765 | * @return \PHPThumb\GD 766 | */ 767 | public function rotateImageNDegrees($degrees) 768 | { 769 | if (!is_numeric($degrees)) { 770 | throw new \InvalidArgumentException('$degrees must be numeric'); 771 | } 772 | 773 | if (!function_exists('imagerotate')) { 774 | throw new \RuntimeException('Your version of GD does not support image rotation'); 775 | } 776 | 777 | $this->workingImage = imagerotate($this->oldImage, $degrees, 0); 778 | 779 | $newWidth = $this->currentDimensions['height']; 780 | $newHeight = $this->currentDimensions['width']; 781 | $this->oldImage = $this->workingImage; 782 | $this->currentDimensions['width'] = $newWidth; 783 | $this->currentDimensions['height'] = $newHeight; 784 | 785 | return $this; 786 | } 787 | 788 | /** 789 | * Applies a filter to the image 790 | * 791 | * @param int $filter 792 | * @return \PHPThumb\GD 793 | */ 794 | public function imageFilter($filter, $arg1 = false, $arg2 = false, $arg3 = false, $arg4 = false) 795 | { 796 | if (!is_numeric($filter)) { 797 | throw new \InvalidArgumentException('$filter must be numeric'); 798 | } 799 | 800 | if (!function_exists('imagefilter')) { 801 | throw new \RuntimeException('Your version of GD does not support image filters'); 802 | } 803 | 804 | $result = false; 805 | if ($arg1 === false) { 806 | $result = imagefilter($this->oldImage, $filter); 807 | } elseif ($arg2 === false) { 808 | $result = imagefilter($this->oldImage, $filter, $arg1); 809 | } elseif ($arg3 === false) { 810 | $result = imagefilter($this->oldImage, $filter, $arg1, $arg2); 811 | } elseif ($arg4 === false) { 812 | $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3); 813 | } else { 814 | $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3, $arg4); 815 | } 816 | 817 | if (!$result) { 818 | throw new \RuntimeException('GD imagefilter failed'); 819 | } 820 | 821 | $this->workingImage = $this->oldImage; 822 | 823 | return $this; 824 | } 825 | 826 | /** 827 | * Shows an image 828 | * 829 | * This function will show the current image by first sending the appropriate header 830 | * for the format, and then outputting the image data. If headers have already been sent, 831 | * a runtime exception will be thrown 832 | * 833 | * @param bool $rawData Whether or not the raw image stream should be output 834 | * @return \PHPThumb\GD 835 | */ 836 | public function show($rawData = false) 837 | { 838 | //Execute any plugins 839 | if ($this->plugins) { 840 | foreach ($this->plugins as $plugin) { 841 | /* @var $plugin \PHPThumb\PluginInterface */ 842 | $plugin->execute($this); 843 | } 844 | } 845 | 846 | if (headers_sent() && php_sapi_name() != 'cli') { 847 | throw new \RuntimeException('Cannot show image, headers have already been sent'); 848 | } 849 | 850 | // When the interlace option equals true or false call imageinterlace else leave it to default 851 | if ($this->options['interlace'] === true) { 852 | imageinterlace($this->oldImage, 1); 853 | } elseif ($this->options['interlace'] === false) { 854 | imageinterlace($this->oldImage, 0); 855 | } 856 | 857 | switch ($this->format) { 858 | case 'GIF': 859 | if ($rawData === false) { 860 | header('Content-type: image/gif'); 861 | } 862 | imagegif($this->oldImage); 863 | break; 864 | case 'JPG': 865 | if ($rawData === false) { 866 | header('Content-type: image/jpeg'); 867 | } 868 | imagejpeg($this->oldImage, null, $this->options['jpegQuality']); 869 | break; 870 | case 'PNG': 871 | case 'STRING': 872 | if ($rawData === false) { 873 | header('Content-type: image/png'); 874 | } 875 | imagepng($this->oldImage); 876 | break; 877 | } 878 | 879 | return $this; 880 | } 881 | 882 | /** 883 | * Returns the Working Image as a String 884 | * 885 | * This function is useful for getting the raw image data as a string for storage in 886 | * a database, or other similar things. 887 | * 888 | * @return string 889 | */ 890 | public function getImageAsString() 891 | { 892 | $data = null; 893 | ob_start(); 894 | $this->show(true); 895 | $data = ob_get_contents(); 896 | ob_end_clean(); 897 | 898 | return $data; 899 | } 900 | 901 | /** 902 | * Saves an image 903 | * 904 | * This function will make sure the target directory is writeable, and then save the image. 905 | * 906 | * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this 907 | * is set as an option ($this->options['correctPermissions']). If the target cannot be made writeable, then a 908 | * \RuntimeException is thrown. 909 | * 910 | * @param string $fileName The full path and filename of the image to save 911 | * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG] 912 | * @return \PHPThumb\GD 913 | */ 914 | public function save($fileName, $format = null) 915 | { 916 | $validFormats = array('GIF', 'JPG', 'PNG'); 917 | $format = ($format !== null) ? strtoupper($format) : $this->format; 918 | 919 | if (!in_array($format, $validFormats)) { 920 | throw new \InvalidArgumentException("Invalid format type specified in save function: {$format}"); 921 | } 922 | 923 | // make sure the directory is writeable 924 | if (!is_writeable(dirname($fileName))) { 925 | // try to correct the permissions 926 | if ($this->options['correctPermissions'] === true) { 927 | @chmod(dirname($fileName), 0777); 928 | 929 | // throw an exception if not writeable 930 | if (!is_writeable(dirname($fileName))) { 931 | throw new \RuntimeException("File is not writeable, and could not correct permissions: {$fileName}"); 932 | } 933 | } else { // throw an exception if not writeable 934 | throw new \RuntimeException("File not writeable: {$fileName}"); 935 | } 936 | } 937 | 938 | // When the interlace option equals true or false call imageinterlace else leave it to default 939 | if ($this->options['interlace'] === true) { 940 | imageinterlace($this->oldImage, 1); 941 | } elseif ($this->options['interlace'] === false) { 942 | imageinterlace($this->oldImage, 0); 943 | } 944 | 945 | switch ($format) { 946 | case 'GIF': 947 | imagegif($this->oldImage, $fileName); 948 | break; 949 | case 'JPG': 950 | imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']); 951 | break; 952 | case 'PNG': 953 | imagepng($this->oldImage, $fileName); 954 | break; 955 | } 956 | 957 | return $this; 958 | } 959 | 960 | ################################# 961 | # ----- GETTERS / SETTERS ----- # 962 | ################################# 963 | 964 | /** 965 | * Sets options for all operations. 966 | * @param array $options 967 | * @return GD 968 | */ 969 | public function setOptions(array $options = array()) 970 | { 971 | // we've yet to init the default options, so create them here 972 | if (sizeof($this->options) == 0) { 973 | $defaultOptions = array( 974 | 'resizeUp' => false, 975 | 'jpegQuality' => 100, 976 | 'correctPermissions' => false, 977 | 'preserveAlpha' => true, 978 | 'alphaMaskColor' => array (255, 255, 255), 979 | 'preserveTransparency' => true, 980 | 'transparencyMaskColor' => array (0, 0, 0), 981 | 'interlace' => null 982 | ); 983 | } else { // otherwise, let's use what we've got already 984 | $defaultOptions = $this->options; 985 | } 986 | 987 | $this->options = array_merge($defaultOptions, $options); 988 | 989 | return $this; 990 | } 991 | 992 | /** 993 | * Returns $currentDimensions. 994 | * 995 | * @see \PHPThumb\GD::$currentDimensions 996 | */ 997 | public function getCurrentDimensions() 998 | { 999 | return $this->currentDimensions; 1000 | } 1001 | 1002 | /** 1003 | * @param $currentDimensions 1004 | * @return GD 1005 | */ 1006 | public function setCurrentDimensions($currentDimensions) 1007 | { 1008 | $this->currentDimensions = $currentDimensions; 1009 | 1010 | return $this; 1011 | } 1012 | 1013 | /** 1014 | * @return int 1015 | */ 1016 | public function getMaxHeight() 1017 | { 1018 | return $this->maxHeight; 1019 | } 1020 | 1021 | /** 1022 | * @param $maxHeight 1023 | * @return GD 1024 | */ 1025 | public function setMaxHeight($maxHeight) 1026 | { 1027 | $this->maxHeight = $maxHeight; 1028 | 1029 | return $this; 1030 | } 1031 | 1032 | /** 1033 | * @return int 1034 | */ 1035 | public function getMaxWidth() 1036 | { 1037 | return $this->maxWidth; 1038 | } 1039 | 1040 | /** 1041 | * @param $maxWidth 1042 | * @return GD 1043 | */ 1044 | public function setMaxWidth($maxWidth) 1045 | { 1046 | $this->maxWidth = $maxWidth; 1047 | 1048 | return $this; 1049 | } 1050 | 1051 | /** 1052 | * Returns $newDimensions. 1053 | * 1054 | * @see \PHPThumb\GD::$newDimensions 1055 | */ 1056 | public function getNewDimensions() 1057 | { 1058 | return $this->newDimensions; 1059 | } 1060 | 1061 | /** 1062 | * Sets $newDimensions. 1063 | * 1064 | * @param object $newDimensions 1065 | * @see \PHPThumb\GD::$newDimensions 1066 | */ 1067 | public function setNewDimensions($newDimensions) 1068 | { 1069 | $this->newDimensions = $newDimensions; 1070 | 1071 | return $this; 1072 | } 1073 | 1074 | /** 1075 | * Returns $options. 1076 | * 1077 | * @see \PHPThumb\GD::$options 1078 | */ 1079 | public function getOptions() 1080 | { 1081 | return $this->options; 1082 | } 1083 | 1084 | /** 1085 | * Returns $percent. 1086 | * 1087 | * @see \PHPThumb\GD::$percent 1088 | */ 1089 | public function getPercent() 1090 | { 1091 | return $this->percent; 1092 | } 1093 | 1094 | /** 1095 | * Sets $percent. 1096 | * 1097 | * @param object $percent 1098 | * @see \PHPThumb\GD::$percent 1099 | */ 1100 | public function setPercent($percent) 1101 | { 1102 | $this->percent = $percent; 1103 | 1104 | return $this; 1105 | } 1106 | 1107 | /** 1108 | * Returns $oldImage. 1109 | * 1110 | * @see \PHPThumb\GD::$oldImage 1111 | */ 1112 | public function getOldImage() 1113 | { 1114 | return $this->oldImage; 1115 | } 1116 | 1117 | /** 1118 | * Sets $oldImage. 1119 | * 1120 | * @param object $oldImage 1121 | * @see \PHPThumb\GD::$oldImage 1122 | */ 1123 | public function setOldImage($oldImage) 1124 | { 1125 | $this->oldImage = $oldImage; 1126 | 1127 | return $this; 1128 | } 1129 | 1130 | /** 1131 | * Returns $workingImage. 1132 | * 1133 | * @see \PHPThumb\GD::$workingImage 1134 | */ 1135 | public function getWorkingImage() 1136 | { 1137 | return $this->workingImage; 1138 | } 1139 | 1140 | /** 1141 | * Sets $workingImage. 1142 | * 1143 | * @param object $workingImage 1144 | * @see \PHPThumb\GD::$workingImage 1145 | */ 1146 | public function setWorkingImage($workingImage) 1147 | { 1148 | $this->workingImage = $workingImage; 1149 | 1150 | return $this; 1151 | } 1152 | 1153 | 1154 | ################################# 1155 | # ----- UTILITY FUNCTIONS ----- # 1156 | ################################# 1157 | 1158 | /** 1159 | * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions 1160 | * 1161 | * @return array 1162 | * @param int $width 1163 | * @param int $height 1164 | */ 1165 | protected function calcWidth($width, $height) 1166 | { 1167 | $newWidthPercentage = (100 * $this->maxWidth) / $width; 1168 | $newHeight = ($height * $newWidthPercentage) / 100; 1169 | 1170 | return array( 1171 | 'newWidth' => intval($this->maxWidth), 1172 | 'newHeight' => intval($newHeight) 1173 | ); 1174 | } 1175 | 1176 | /** 1177 | * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions 1178 | * 1179 | * @return array 1180 | * @param int $width 1181 | * @param int $height 1182 | */ 1183 | protected function calcHeight($width, $height) 1184 | { 1185 | $newHeightPercentage = (100 * $this->maxHeight) / $height; 1186 | $newWidth = ($width * $newHeightPercentage) / 100; 1187 | 1188 | return array( 1189 | 'newWidth' => ceil($newWidth), 1190 | 'newHeight' => ceil($this->maxHeight) 1191 | ); 1192 | } 1193 | 1194 | /** 1195 | * Calculates a new width and height for the image based on $this->percent and the provided dimensions 1196 | * 1197 | * @return array 1198 | * @param int $width 1199 | * @param int $height 1200 | */ 1201 | protected function calcPercent($width, $height) 1202 | { 1203 | $newWidth = ($width * $this->percent) / 100; 1204 | $newHeight = ($height * $this->percent) / 100; 1205 | 1206 | return array( 1207 | 'newWidth' => ceil($newWidth), 1208 | 'newHeight' => ceil($newHeight) 1209 | ); 1210 | } 1211 | 1212 | /** 1213 | * Calculates the new image dimensions 1214 | * 1215 | * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight 1216 | * 1217 | * @param int $width 1218 | * @param int $height 1219 | */ 1220 | protected function calcImageSize($width, $height) 1221 | { 1222 | $newSize = array( 1223 | 'newWidth' => $width, 1224 | 'newHeight' => $height 1225 | ); 1226 | 1227 | if ($this->maxWidth > 0) { 1228 | $newSize = $this->calcWidth($width, $height); 1229 | 1230 | if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) { 1231 | $newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']); 1232 | } 1233 | } 1234 | 1235 | if ($this->maxHeight > 0) { 1236 | $newSize = $this->calcHeight($width, $height); 1237 | 1238 | if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) { 1239 | $newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']); 1240 | } 1241 | } 1242 | 1243 | $this->newDimensions = $newSize; 1244 | } 1245 | 1246 | /** 1247 | * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height 1248 | * 1249 | * @param int $width 1250 | * @param int $height 1251 | */ 1252 | protected function calcImageSizeStrict($width, $height) 1253 | { 1254 | // first, we need to determine what the longest resize dimension is.. 1255 | if ($this->maxWidth >= $this->maxHeight) { 1256 | // and determine the longest original dimension 1257 | if ($width > $height) { 1258 | $newDimensions = $this->calcHeight($width, $height); 1259 | 1260 | if ($newDimensions['newWidth'] < $this->maxWidth) { 1261 | $newDimensions = $this->calcWidth($width, $height); 1262 | } 1263 | } elseif ($height >= $width) { 1264 | $newDimensions = $this->calcWidth($width, $height); 1265 | 1266 | if ($newDimensions['newHeight'] < $this->maxHeight) { 1267 | $newDimensions = $this->calcHeight($width, $height); 1268 | } 1269 | } 1270 | } elseif ($this->maxHeight > $this->maxWidth) { 1271 | if ($width >= $height) { 1272 | $newDimensions = $this->calcWidth($width, $height); 1273 | 1274 | if ($newDimensions['newHeight'] < $this->maxHeight) { 1275 | $newDimensions = $this->calcHeight($width, $height); 1276 | } 1277 | } elseif ($height > $width) { 1278 | $newDimensions = $this->calcHeight($width, $height); 1279 | 1280 | if ($newDimensions['newWidth'] < $this->maxWidth) { 1281 | $newDimensions = $this->calcWidth($width, $height); 1282 | } 1283 | } 1284 | } 1285 | 1286 | $this->newDimensions = $newDimensions; 1287 | } 1288 | 1289 | /** 1290 | * Calculates new dimensions based on $this->percent and the provided dimensions 1291 | * 1292 | * @param int $width 1293 | * @param int $height 1294 | */ 1295 | protected function calcImageSizePercent($width, $height) 1296 | { 1297 | if ($this->percent > 0) { 1298 | $this->newDimensions = $this->calcPercent($width, $height); 1299 | } 1300 | } 1301 | 1302 | /** 1303 | * Determines the file format by mime-type 1304 | * 1305 | * This function will throw exceptions for invalid images / mime-types 1306 | * 1307 | */ 1308 | protected function determineFormat() 1309 | { 1310 | $formatInfo = getimagesize($this->fileName); 1311 | 1312 | // non-image files will return false 1313 | if ($formatInfo === false) { 1314 | if ($this->remoteImage) { 1315 | throw new \Exception("Could not determine format of remote image: {$this->fileName}"); 1316 | } else { 1317 | throw new \Exception("File is not a valid image: {$this->fileName}"); 1318 | } 1319 | } 1320 | 1321 | $mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null; 1322 | 1323 | switch ($mimeType) { 1324 | case 'image/gif': 1325 | $this->format = 'GIF'; 1326 | break; 1327 | case 'image/jpeg': 1328 | $this->format = 'JPG'; 1329 | break; 1330 | case 'image/png': 1331 | $this->format = 'PNG'; 1332 | break; 1333 | default: 1334 | throw new \Exception("Image format not supported: {$mimeType}"); 1335 | } 1336 | } 1337 | 1338 | /** 1339 | * Makes sure the correct GD implementation exists for the file type 1340 | * 1341 | */ 1342 | protected function verifyFormatCompatiblity() 1343 | { 1344 | $isCompatible = true; 1345 | $gdInfo = gd_info(); 1346 | 1347 | switch ($this->format) { 1348 | case 'GIF': 1349 | $isCompatible = $gdInfo['GIF Create Support']; 1350 | break; 1351 | case 'JPG': 1352 | $isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false; 1353 | break; 1354 | case 'PNG': 1355 | $isCompatible = $gdInfo[$this->format . ' Support']; 1356 | break; 1357 | default: 1358 | $isCompatible = false; 1359 | } 1360 | 1361 | if (!$isCompatible) { 1362 | // one last check for "JPEG" instead 1363 | $isCompatible = $gdInfo['JPEG Support']; 1364 | 1365 | if (!$isCompatible) { 1366 | throw new \Exception("Your GD installation does not support {$this->format} image types"); 1367 | } 1368 | } 1369 | } 1370 | 1371 | /** 1372 | * Preserves the alpha or transparency for PNG and GIF files 1373 | * 1374 | * Alpha / transparency will not be preserved if the appropriate options are set to false. 1375 | * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a 1376 | * champ... that's the nature of GIFs tho, so no huge surprise. 1377 | * 1378 | * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :) 1379 | * 1380 | */ 1381 | protected function preserveAlpha() 1382 | { 1383 | if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true) { 1384 | imagealphablending($this->workingImage, false); 1385 | 1386 | $colorTransparent = imagecolorallocatealpha( 1387 | $this->workingImage, 1388 | $this->options['alphaMaskColor'][0], 1389 | $this->options['alphaMaskColor'][1], 1390 | $this->options['alphaMaskColor'][2], 1391 | 0 1392 | ); 1393 | 1394 | imagefill($this->workingImage, 0, 0, $colorTransparent); 1395 | imagesavealpha($this->workingImage, true); 1396 | } 1397 | // preserve transparency in GIFs... this is usually pretty rough tho 1398 | if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true) { 1399 | $colorTransparent = imagecolorallocate( 1400 | $this->workingImage, 1401 | $this->options['transparencyMaskColor'][0], 1402 | $this->options['transparencyMaskColor'][1], 1403 | $this->options['transparencyMaskColor'][2] 1404 | ); 1405 | 1406 | imagecolortransparent($this->workingImage, $colorTransparent); 1407 | imagetruecolortopalette($this->workingImage, true, 256); 1408 | } 1409 | } 1410 | } 1411 | -------------------------------------------------------------------------------- /src/PHPThumb/PHPThumb.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright (c) 2009, Ian Selby/Gen X Design 8 | * 9 | * Author(s): Ian Selby 10 | * 11 | * Licensed under the MIT License 12 | * Redistributions of files must retain the above copyright notice. 13 | * 14 | * @author Ian Selby 15 | * @copyright Copyright (c) 2009 Gen X Design 16 | * @link http://phpthumb.gxdlabs.com 17 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 18 | */ 19 | 20 | abstract class PHPThumb 21 | { 22 | /** 23 | * The name of the file we're manipulating 24 | * This must include the path to the file (absolute paths recommended) 25 | * 26 | * @var string 27 | */ 28 | protected $fileName; 29 | 30 | /** 31 | * What the file format is (mime-type) 32 | * 33 | * @var string 34 | */ 35 | protected $format; 36 | 37 | /** 38 | * Whether or not the image is hosted remotely 39 | * 40 | * @var bool 41 | */ 42 | protected $remoteImage; 43 | 44 | /** 45 | * An array of attached plugins to execute in order. 46 | * @var array 47 | */ 48 | protected $plugins; 49 | 50 | /** 51 | * @param $fileName 52 | * @param array $options 53 | * @param array $plugins 54 | */ 55 | public function __construct($fileName, array $options = array(), array $plugins = array()) 56 | { 57 | $this->fileName = $fileName; 58 | $this->remoteImage = false; 59 | 60 | if(!$this->validateRequestedResource($fileName)) { 61 | throw new \InvalidArgumentException("Image file not found: {$fileName}"); 62 | } 63 | 64 | $this->setOptions($options); 65 | 66 | $this->plugins = $plugins; 67 | } 68 | 69 | abstract public function setOptions(array $options = array()); 70 | 71 | /** 72 | * Check the provided filename/url. If it is a url, validate that it is properly 73 | * formatted. If it is a file, check to make sure that it actually exists on 74 | * the filesystem. 75 | * 76 | * @param $filename 77 | * @return bool 78 | */ 79 | protected function validateRequestedResource($filename) 80 | { 81 | if(false !== filter_var($filename, FILTER_VALIDATE_URL)) { 82 | $this->remoteImage = true; 83 | return true; 84 | } 85 | 86 | if(file_exists($filename)) { 87 | return true; 88 | } 89 | 90 | return false; 91 | } 92 | 93 | /** 94 | * Returns the filename. 95 | * @return string 96 | */ 97 | public function getFileName() 98 | { 99 | return $this->fileName; 100 | } 101 | 102 | /** 103 | * Sets the filename. 104 | * @param $fileName 105 | * @return PHPThumb 106 | */ 107 | public function setFileName($fileName) 108 | { 109 | $this->fileName = $fileName; 110 | 111 | return $this; 112 | } 113 | 114 | /** 115 | * Returns the format. 116 | * @return string 117 | */ 118 | public function getFormat() 119 | { 120 | return $this->format; 121 | } 122 | 123 | /** 124 | * Sets the format. 125 | * @param $format 126 | * @return PHPThumb 127 | */ 128 | public function setFormat($format) 129 | { 130 | $this->format = $format; 131 | 132 | return $this; 133 | } 134 | 135 | /** 136 | * Returns whether the image exists remotely, i.e. it was loaded via a URL. 137 | * @return bool 138 | */ 139 | public function getIsRemoteImage() 140 | { 141 | return $this->remoteImage; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/PHPThumb/PluginInterface.php: -------------------------------------------------------------------------------- 1 | 12 | * Copyright (c) 2009, Ian Selby/Gen X Design 13 | * 14 | * Author(s): Ian Selby 15 | * 16 | * Licensed under the MIT License 17 | * Redistributions of files must retain the above copyright notice. 18 | * 19 | * @author Ian Selby 20 | * @copyright Copyright (c) 2009 Gen X Design 21 | * @link http://phpthumb.gxdlabs.com 22 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 23 | * @version 3.0 24 | * @package PhpThumb 25 | * @filesource 26 | */ 27 | 28 | /** 29 | * GD Reflection Lib Plugin 30 | * 31 | * This plugin allows you to create those fun Apple(tm)-style reflections in your images 32 | * 33 | * @package PhpThumb 34 | * @subpackage Plugins 35 | */ 36 | class Reflection implements \PHPThumb\PluginInterface 37 | { 38 | protected $currentDimensions; 39 | protected $workingImage; 40 | protected $newImage; 41 | protected $options; 42 | 43 | protected $percent; 44 | protected $reflection; 45 | protected $white; 46 | protected $border; 47 | protected $borderColor; 48 | 49 | public function __construct($percent, $reflection, $white, $border, $borderColor) 50 | { 51 | $this->percent = $percent; 52 | $this->reflection = $reflection; 53 | $this->white = $white; 54 | $this->border = $border; 55 | $this->borderColor = $borderColor; 56 | } 57 | 58 | /** 59 | * @param \PHPThumb\PHPThumb $phpthumb 60 | * @return \PHPThumb\PHPThumb 61 | */ 62 | public function execute($phpthumb) 63 | { 64 | $this->currentDimensions = $phpthumb->getCurrentDimensions(); 65 | $this->workingImage = $phpthumb->getWorkingImage(); 66 | $this->newImage = $phpthumb->getOldImage(); 67 | $this->options = $phpthumb->getOptions(); 68 | 69 | $width = $this->currentDimensions['width']; 70 | $height = $this->currentDimensions['height']; 71 | $this->reflectionHeight = intval($height * ($this->reflection / 100)); 72 | $newHeight = $height + $this->reflectionHeight; 73 | $reflectedPart = $height * ($this->percent / 100); 74 | 75 | $this->workingImage = imagecreatetruecolor($width, $newHeight); 76 | 77 | imagealphablending($this->workingImage, true); 78 | 79 | $colorToPaint = imagecolorallocatealpha( 80 | $this->workingImage, 81 | 255, 82 | 255, 83 | 255, 84 | 0 85 | ); 86 | 87 | imagefilledrectangle( 88 | $this->workingImage, 89 | 0, 90 | 0, 91 | $width, 92 | $newHeight, 93 | $colorToPaint 94 | ); 95 | 96 | imagecopyresampled( 97 | $this->workingImage, 98 | $this->newImage, 99 | 0, 100 | 0, 101 | 0, 102 | $reflectedPart, 103 | $width, 104 | $this->reflectionHeight, 105 | $width, 106 | ($height - $reflectedPart) 107 | ); 108 | 109 | $this->imageFlipVertical(); 110 | 111 | imagecopy( 112 | $this->workingImage, 113 | $this->newImage, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | $width, 119 | $height 120 | ); 121 | 122 | imagealphablending($this->workingImage, true); 123 | 124 | for ($i = 0; $i < $this->reflectionHeight; $i++) { 125 | $colorToPaint = imagecolorallocatealpha( 126 | $this->workingImage, 127 | 255, 128 | 255, 129 | 255, 130 | ($i / $this->reflectionHeight * -1 + 1) * $this->white 131 | ); 132 | 133 | imagefilledrectangle( 134 | $this->workingImage, 135 | 0, 136 | $height + $i, 137 | $width, 138 | $height + $i, 139 | $colorToPaint 140 | ); 141 | } 142 | 143 | if ($this->border == true) { 144 | $rgb = $this->hex2rgb($this->borderColor, false); 145 | $colorToPaint = imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]); 146 | 147 | //top line 148 | imageline( 149 | $this->workingImage, 150 | 0, 151 | 0, 152 | $width, 153 | 0, 154 | $colorToPaint 155 | ); 156 | 157 | //bottom line 158 | imageline( 159 | $this->workingImage, 160 | 0, 161 | $height, 162 | $width, 163 | $height, 164 | $colorToPaint 165 | ); 166 | 167 | //left line 168 | imageline( 169 | $this->workingImage, 170 | 0, 171 | 0, 172 | 0, 173 | $height, 174 | $colorToPaint 175 | ); 176 | 177 | //right line 178 | imageline( 179 | $this->workingImage, 180 | $width - 1, 181 | 0, 182 | $width - 1, 183 | $height, 184 | $colorToPaint 185 | ); 186 | } 187 | 188 | if ($phpthumb->getFormat() == 'PNG') { 189 | $colorTransparent = imagecolorallocatealpha( 190 | $this->workingImage, 191 | $this->options['alphaMaskColor'][0], 192 | $this->options['alphaMaskColor'][1], 193 | $this->options['alphaMaskColor'][2], 194 | 0 195 | ); 196 | 197 | imagefill($this->workingImage, 0, 0, $colorTransparent); 198 | imagesavealpha($this->workingImage, true); 199 | } 200 | 201 | $phpthumb->setOldImage($this->workingImage); 202 | $this->currentDimensions['width'] = $width; 203 | $this->currentDimensions['height'] = $newHeight; 204 | $phpthumb->setCurrentDimensions($this->currentDimensions); 205 | 206 | return $phpthumb; 207 | } 208 | 209 | /** 210 | * Flips the image vertically 211 | * 212 | */ 213 | protected function imageFlipVertical () 214 | { 215 | $x_i = imagesx($this->workingImage); 216 | $y_i = imagesy($this->workingImage); 217 | 218 | for ($x = 0; $x < $x_i; $x++) { 219 | for ($y = 0; $y < $y_i; $y++) { 220 | imagecopy( 221 | $this->workingImage, 222 | $this->workingImage, 223 | $x, 224 | $y_i - $y - 1, 225 | $x, 226 | $y, 227 | 1, 228 | 1 229 | ); 230 | } 231 | } 232 | } 233 | 234 | /** 235 | * Converts a hex color to rgb tuples 236 | * 237 | * @return mixed 238 | * @param string $hex 239 | * @param bool $asString 240 | */ 241 | protected function hex2rgb ($hex, $asString = false) 242 | { 243 | // strip off any leading # 244 | if (0 === strpos($hex, '#')) { 245 | $hex = substr($hex, 1); 246 | } elseif (0 === strpos($hex, '&H')) { 247 | $hex = substr($hex, 2); 248 | } 249 | 250 | // break into hex 3-tuple 251 | $cutpoint = ceil(strlen($hex) / 2)-1; 252 | $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3); 253 | 254 | // convert each tuple to decimal 255 | $rgb[0] = (isset($rgb[0]) ? hexdec($rgb[0]) : 0); 256 | $rgb[1] = (isset($rgb[1]) ? hexdec($rgb[1]) : 0); 257 | $rgb[2] = (isset($rgb[2]) ? hexdec($rgb[2]) : 0); 258 | 259 | return ($asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /tests/PHPThumb/GDTest.php: -------------------------------------------------------------------------------- 1 | gif = new GD(__DIR__ . '/../resources/test.gif'); 16 | $this->jpg = new GD(__DIR__ . '/../resources/test.jpg'); 17 | $this->png = new GD(__DIR__ . '/../resources/test.png'); 18 | } 19 | 20 | public function testLoadFileTypes() 21 | { 22 | self::assertSame('GIF', $this->gif->getFormat()); 23 | self::assertSame('JPG', $this->jpg->getFormat()); 24 | self::assertSame('PNG', $this->png->getFormat()); 25 | } 26 | 27 | /** 28 | * This test might seem pointless but it runs the __destruct and gets us to 29 | * 100% code coverage. 30 | */ 31 | public function testImageDestroy() 32 | { 33 | $testImage = new GD(__DIR__ . '/../resources/test.gif'); 34 | unset($testImage); 35 | self::assertSame(false, isset($testImage)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/PHPThumb/LoadTest.php: -------------------------------------------------------------------------------- 1 | thumb = new GD(__DIR__ . '/../resources/test.jpg'); 14 | } 15 | 16 | public function testLoadFile() 17 | { 18 | self::assertSame(array('width' => 500, 'height' => 375), $this->thumb->getCurrentDimensions()); 19 | self::assertSame(array( 20 | 'resizeUp' => false, 21 | 'jpegQuality' => 100, 22 | 'correctPermissions' => false, 23 | 'preserveAlpha' => true, 24 | 'alphaMaskColor' => array ( 25 | 0 => 255, 26 | 1 => 255, 27 | 2 => 255), 28 | 'preserveTransparency' => true, 29 | 'transparencyMaskColor' => array ( 30 | 0 => 0, 31 | 1 => 0, 32 | 2 => 0), 33 | 'interlace' => null), $this->thumb->getOptions()); 34 | 35 | self::assertSame('JPG', $this->thumb->getFormat()); 36 | self::assertSame(__DIR__ . '/../resources/test.jpg', $this->thumb->getFileName()); 37 | } 38 | 39 | public function testSetFormat() 40 | { 41 | $this->thumb->setFormat('PNG'); 42 | self::assertSame('PNG', $this->thumb->getFormat()); 43 | } 44 | 45 | public function testSetFileName() 46 | { 47 | $this->thumb->setFilename('mytest.jpg'); 48 | self::assertSame('mytest.jpg', $this->thumb->getFilename()); 49 | } 50 | 51 | public function testLoadExternalImage() 52 | { 53 | /* $gravatarThumb = new GD('https://en.gravatar.com/userimage/1132703/2ccbcfbea4a1b3b8d955c1e7746b882b.jpg'); 54 | self::assertSame(true, $gravatarThumb->getIsRemoteImage()); */ 55 | } 56 | 57 | /** 58 | * @expectedException \InvalidArgumentException 59 | */ 60 | public function testNonexistentFile() 61 | { 62 | $madeupThumb = new GD('nosuchimage.jpg'); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/resources/test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterexploder/PHPThumb/54b18cd00ab0a00dc90aa9871de0638efa93986a/tests/resources/test.gif -------------------------------------------------------------------------------- /tests/resources/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterexploder/PHPThumb/54b18cd00ab0a00dc90aa9871de0638efa93986a/tests/resources/test.jpg -------------------------------------------------------------------------------- /tests/resources/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterexploder/PHPThumb/54b18cd00ab0a00dc90aa9871de0638efa93986a/tests/resources/test.png --------------------------------------------------------------------------------