PageRenderTime 63ms CodeModel.GetById 2ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/class/class.thumbnail.php

http://avecms.googlecode.com/
PHP | 1405 lines | 965 code | 89 blank | 351 comment | 197 complexity | fd0b4660ad90f17ba658433599cb1461 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * Image_Toolbox.class.php -- PHP image manipulation class
   4 *
   5 * Copyright (C) 2003 Martin Theimer <pappkamerad@decoded.net>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License <http://www.opensource.org/gpl-license.html>
  15 * for more details..
  16 *
  17 * The latest version of Image_Toolbox can be obtained from:
  18 * http://sourceforge.net/projects/image-toolbox
  19 * http://www.phpclasses.org/image_toolbox
  20 *
  21 * @author Martin Theimer <pappkamerad@decoded.net>
  22 * @copyright Copyright (C) 2003 Martin Theimer
  23 * @version 1.1.0
  24 * @package Image_Toolbox
  25 * @link http://sourceforge.net/projects/image-toolbox
  26 */
  27
  28// $Id: Image_Toolbox.class.php,v 1.9 2003/12/05 19:34:01 pappkamerad Exp $
  29
  30if (!defined('IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY')) {
  31	define('IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY', 100);
  32}
  33if (!defined('IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS')) {
  34	define('IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS', 256);
  35}
  36if (!defined('IMAGE_TOOLBOX_BIAS_HORIZONTAL')) {
  37	define('IMAGE_TOOLBOX_BIAS_HORIZONTAL', 1);
  38}
  39if (!defined('IMAGE_TOOLBOX_BIAS_VERTICAL')) {
  40	define('IMAGE_TOOLBOX_BIAS_VERTICAL', 0);
  41}
  42if (!defined('IMAGE_TOOLBOX_BLEND_COPY')) {
  43	define('IMAGE_TOOLBOX_BLEND_COPY', 1);
  44}
  45if (!defined('IMAGE_TOOLBOX_BLEND_MULTIPLY')) {
  46	define('IMAGE_TOOLBOX_BLEND_MULTIPLY', 2);
  47}
  48if (!defined('IMAGE_TOOLBOX_BLEND_SCREEN')) {
  49	define('IMAGE_TOOLBOX_BLEND_SCREEN', 3);
  50}
  51if (!defined('IMAGE_TOOLBOX_BLEND_DIFFERENCE')) {
  52	define('IMAGE_TOOLBOX_BLEND_DIFFERENCE', 4);
  53}
  54if (!defined('IMAGE_TOOLBOX_BLEND_NEGATION')) {
  55	define('IMAGE_TOOLBOX_BLEND_NEGATION', 5);
  56}
  57if (!defined('IMAGE_TOOLBOX_BLEND_EXCLUSION')) {
  58	define('IMAGE_TOOLBOX_BLEND_EXCLUSION', 6);
  59}
  60if (!defined('IMAGE_TOOLBOX_BLEND_OVERLAY')) {
  61	define('IMAGE_TOOLBOX_BLEND_OVERLAY', 7);
  62}
  63
  64/**
  65 * PHP image manipulation class
  66 *
  67 * This class provides an easy to use library to the PHP GD-based imagefunctions
  68 *
  69 * @author Martin Theimer <pappkamerad@decoded.net>
  70 * @copyright 2003, Martin Theimer
  71 * @package Image_Toolbox
  72 * @link http://sourceforge.net/projects/image-toolbox
  73 * @version 1.1.0
  74 */
  75class Image_Toolbox {
  76
  77    /**
  78     * The prefix for every error message
  79     *
  80     * @access private
  81     * @var string
  82     */
  83	var $_error_prefix = 'Image: ';
  84
  85	/**
  86     * Defines imagetypes and how they are supported by the server
  87     *
  88     * @access private
  89     * @var array
  90     */
  91	var $_types = array (
  92		1 => array (
  93			'ext' => 'gif',
  94			'mime' => 'image/gif',
  95			'supported' => 0
  96		),
  97		2 => array (
  98			'ext' => 'jpg',
  99			'mime' => 'image/jpeg',
 100			'supported' => 0
 101		),
 102		3 => array (
 103			'ext' => 'png',
 104			'mime' => 'image/png',
 105			'supported' => 0
 106		)
 107	);
 108
 109	/**
 110     * Which PHP image resize function to be used
 111     * imagecopyresampled only supported with GD >= 2.0
 112     *
 113     * @access private
 114     * @var string
 115     */
 116	var $_resize_function = 'imagecopyresampled';
 117
 118	/**
 119     * Stores all image resource data
 120     *
 121     * @access private
 122     * @var array
 123     */
 124	var $_img = array (
 125		'main' => array (
 126			'resource' => 0,
 127			'width' => 0,
 128			'height' => 0,
 129			'bias' => 0,
 130			'aspectratio' => 0,
 131			'type' => 0,
 132			'output_type' => 0,
 133			'indexedcolors' => 0,
 134			'color' => -1
 135		)
 136	);
 137
 138	/**
 139     * Which PHP image create function to be used
 140     * imagecreatetruecolor only supported with GD >= 2.0
 141     *
 142     * @access private
 143     * @var string
 144     */
 145	var $_imagecreatefunction = '';
 146
 147    /**
 148     * The class constructor.
 149     *
 150     * Determines the image features of the server and sets the according values.<br>
 151     * Additionally you can specify a image to be created/loaded. like {@link addImage() addImage}.
 152     *
 153     * If no parameter is given, no image resource will be generated<br>
 154     * Or:<br>
 155     * <i>string</i> <b>$file</b> imagefile to load<br>
 156     * Or:<br>
 157     * <i>integer</i> <b>$width</b> imagewidth of new image to be created<br>
 158     * <i>integer</i> <b>$height</b> imageheight of new image to be created<br>
 159     * <i>string</i> <b>$fillcolor</b> optional fill the new image with this color (hexformat, e.g. '#FF0000')<br>
 160     */
 161	function Image_Toolbox() {
 162		$args = func_get_args();
 163		$argc = func_num_args();
 164
 165		//get GD information. see what types we can handle
 166		$gd_info = function_exists('gd_info') ? gd_info() : $this->_gd_info();
 167		preg_match("/\A[\D]*([\d+\.]*)[\D]*\Z/", $gd_info['GD Version'], $matches);
 168		list($this->_gd_version_string, $this->_gd_version_number) = $matches;
 169		$this->_gd_version = substr($this->_gd_version_number, 0, strpos($this->_gd_version_number, '.'));
 170		if ($this->_gd_version >= 2) {
 171			$this->_imagecreatefunction = 'imagecreatetruecolor';
 172			$this->_resize_function = 'imagecopyresampled';
 173		} else {
 174			$this->_imagecreatefunction = 'imagecreate';
 175			$this->_resize_function = 'imagecopyresized';
 176		}
 177
 178		$this->_gd_ttf = $gd_info['FreeType Support'];
 179		$this->_gd_ps = $gd_info['T1Lib Support'];
 180		if ($gd_info['GIF Read Support']) {
 181			$this->_types[1]['supported'] = 1;
 182			if ($gd_info['GIF Create Support']) {
 183				$this->_types[1]['supported'] = 2;
 184			}
 185		}
 186		if ((isset($gd_info['JPG Support']) && $gd_info['JPG Support']) || (isset($gd_info['JPEG Support']) && $gd_info['JPEG Support'])) {
 187			$this->_types[2]['supported'] = 2;
 188		}
 189		if ($gd_info['PNG Support']) {
 190			$this->_types[3]['supported'] = 2;
 191		}
 192
 193		//load or create main image
 194		if ($argc == 0) {
 195			return true;
 196		} else {
 197			if ($this->_addImage($argc, $args)) {
 198				foreach ($this->_img['operator'] as $key => $value) {
 199					$this->_img['main'][$key] = $value;
 200				}
 201				$this->_img['main']['output_type'] = $this->_img['main']['type'];
 202				unset($this->_img['operator']);
 203				return true;
 204			} else {
 205				trigger_error($this->_error_prefix . 'No appropriate constructor found.', E_USER_ERROR);
 206				return null;
 207			}
 208		}
 209	}
 210
 211	/**
 212     * Returns an assocative array with information about the image features of this server
 213     *
 214     * Array values:
 215     * <ul>
 216     * <li>'gd_version' -> what GD version is installed on this server (e.g. 2.0)</li>
 217     * <li>'gif' -> 0 = not supported, 1 = reading is supported, 2 = creating is supported</li>
 218     * <li>'jpg' -> 0 = not supported, 1 = reading is supported, 2 = creating is supported</li>
 219     * <li>'png' -> 0 = not supported, 1 = reading is supported, 2 = creating is supported</li>
 220     * <li>'ttf' -> TTF text creation. true = supported, false = not supported
 221     * </ul>
 222     *
 223     * @return array
 224     */
 225	function getServerFeatures() {
 226		$features = array();
 227		$features['gd_version'] = $this->_gd_version_number;
 228		$features['gif'] = $this->_types[1]['supported'];
 229		$features['jpg'] = $this->_types[2]['supported'];
 230		$features['png'] = $this->_types[3]['supported'];
 231		$features['ttf'] = $this->_gd_ttf;
 232		return $features;
 233	}
 234
 235	/**
 236     * Flush all image resources and init a new one
 237     *
 238     * Parameter:<br>
 239     * <i>string</i> <b>$file</b> imagefile to load<br>
 240     * Or:<br>
 241     * <i>integer</i> <b>$width</b> imagewidth of new image to be created<br>
 242     * <i>integer</i> <b>$height</b> imageheight of new image to be created<br>
 243     * <i>string</i> <b>$fillcolor</b> optional fill the new image with this color (hexformat, e.g. '#FF0000')<br>
 244     */
 245	function newImage() {
 246		$args = func_get_args();
 247		$argc = func_num_args();
 248
 249		if ($this->_addImage($argc, $args)) {
 250			foreach ($this->_img['operator'] as $key => $value) {
 251				$this->_img['main'][$key] = $value;
 252			}
 253			$this->_img['main']['output_type'] = $this->_img['main']['type'];
 254			unset($this->_img['operator']);
 255			return true;
 256		} else {
 257			trigger_error($this->_error_prefix . 'No appropriate constructor found.', E_USER_ERROR);
 258			return null;
 259		}
 260	}
 261
 262	/**
 263     * Reimplements the original PHP {@link gd_info()} function for older PHP versions
 264     *
 265     * @access private
 266     * @return array associative array with info about the GD library of the server
 267     */
 268	function _gd_info() {
 269		$array = array(
 270        	"GD Version" => "",
 271			"FreeType Support" => false,
 272			"FreeType Linkage" => "",
 273			"T1Lib Support" => false,
 274			"GIF Read Support" => false,
 275			"GIF Create Support" => false,
 276			"JPG Support" => false,
 277			"PNG Support" => false,
 278			"WBMP Support" => false,
 279			"XBM Support" => false
 280		);
 281
 282		$gif_support = 0;
 283		ob_start();
 284		eval("phpinfo();");
 285		$info = ob_get_contents();
 286		ob_end_clean();
 287
 288		foreach(explode("\n", $info) as $line) {
 289			if(strpos($line, "GD Version") !== false)
 290				$array["GD Version"] = trim(str_replace("GD Version", "", strip_tags($line)));
 291			if(strpos($line, "FreeType Support") !== false)
 292				$array["FreeType Support"] = trim(str_replace("FreeType Support", "", strip_tags($line)));
 293			if(strpos($line, "FreeType Linkage") !== false)
 294				$array["FreeType Linkage"] = trim(str_replace("FreeType Linkage", "", strip_tags($line)));
 295			if(strpos($line, "T1Lib Support") !== false)
 296				$array["T1Lib Support"] = trim(str_replace("T1Lib Support", "", strip_tags($line)));
 297			if(strpos($line, "GIF Read Support") !== false)
 298				$array["GIF Read Support"] = trim(str_replace("GIF Read Support", "", strip_tags($line)));
 299			if(strpos($line, "GIF Create Support") !== false)
 300				$array["GIF Create Support"] = trim(str_replace("GIF Create Support", "", strip_tags($line)));
 301			if(strpos($line, "GIF Support") !== false)
 302				$gif_support = trim(str_replace("GIF Support", "", strip_tags($line)));
 303			if(strpos($line, "JPG Support") !== false)
 304				$array["JPG Support"] = trim(str_replace("JPG Support", "", strip_tags($line)));
 305			if(strpos($line, "PNG Support") !== false)
 306				$array["PNG Support"] = trim(str_replace("PNG Support", "", strip_tags($line)));
 307			if(strpos($line, "WBMP Support") !== false)
 308				$array["WBMP Support"] = trim(str_replace("WBMP Support", "", strip_tags($line)));
 309			if(strpos($line, "XBM Support") !== false)
 310				$array["XBM Support"] = trim(str_replace("XBM Support", "", strip_tags($line)));
 311		}
 312
 313		if($gif_support === "enabled") {
 314			$array["GIF Read Support"] = true;
 315			$array["GIF Create Support"] = true;
 316		}
 317
 318		if($array["FreeType Support"] === "enabled") {
 319			$array["FreeType Support"] = true;
 320		}
 321
 322        if($array["T1Lib Support"] === "enabled") {
 323            $array["T1Lib Support"] = true;
 324        }
 325
 326		if($array["GIF Read Support"] === "enabled") {
 327			$array["GIF Read Support"] = true;
 328		}
 329
 330		if($array["GIF Create Support"] === "enabled") {
 331			$array["GIF Create Support"] = true;
 332		}
 333
 334		if($array["JPG Support"] === "enabled") {
 335			$array["JPG Support"] = true;
 336		}
 337
 338		if($array["PNG Support"] === "enabled") {
 339			$array["PNG Support"] = true;
 340		}
 341
 342		if($array["WBMP Support"] === "enabled") {
 343			$array["WBMP Support"] = true;
 344		}
 345
 346		if($array["XBM Support"] === "enabled") {
 347			$array["XBM Support"] = true;
 348		}
 349
 350		return $array;
 351    }
 352
 353	/**
 354     * Convert a color defined in hexvalues to the PHP color format
 355     *
 356     * @access private
 357     * @param string $hex color value in hexformat (e.g. '#FF0000')
 358     * @return integer color value in PHP format
 359     */
 360	function _hexToPHPColor($hex) {
 361		$length = strlen($hex);
 362		$dr = hexdec(substr($hex, $length - 6, 2));
 363		$dg = hexdec(substr($hex, $length - 4, 2));
 364		$db = hexdec(substr($hex, $length - 2, 2));
 365		$color = ($dr << 16) + ($dg << 8) + $db;
 366		return $color;
 367	}
 368
 369	/**
 370     * Convert a color defined in hexvalues to corresponding dezimal values
 371     *
 372     * @access private
 373     * @param string $hex color value in hexformat (e.g. '#FF0000')
 374     * @return array associative array with color values in dezimal format (fields: 'red', 'green', 'blue')
 375     */
 376	function _hexToDecColor($hex) {
 377		$length = strlen($hex);
 378		$color['red'] = hexdec(substr($hex, $length - 6, 2));
 379		$color['green'] = hexdec(substr($hex, $length - 4, 2));
 380		$color['blue'] = hexdec(substr($hex, $length - 2, 2));
 381		return $color;
 382	}
 383
 384	/**
 385     * Generate a new image resource based on the given parameters
 386     *
 387     * Parameter:
 388     * <i>string</i> <b>$file</b> imagefile to load<br>
 389     * Or:<br>
 390     * <i>integer</i> <b>$width</b> imagewidth of new image to be created<br>
 391     * <i>integer</i> <b>$height</b> imageheight of new image to be created<br>
 392     * <i>string</i> <b>$fillcolor</b> optional fill the new image with this color (hexformat, e.g. '#FF0000')<br>
 393     *
 394     * @access private
 395     */
 396	function _addImage($argc, $args) {
 397		if (($argc == 2 || $argc == 3) && is_int($args[0]) && is_int($args[1]) && (is_string($args[2]) || !isset($args[2]))) {
 398			//neues leeres bild mit width und height (fillcolor optional)
 399			$this->_img['operator']['width'] = $args[0];
 400            $this->_img['operator']['height'] = $args[1];
 401            ($this->_img['operator']['width'] >= $this->_img['operator']['height']) ? ($this->_img['operator']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) : ($this->_img['operator']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL);
 402            $this->_img['operator']['aspectratio'] = $this->_img['operator']['width'] / $this->_img['operator']['height'];
 403            $this->_img['operator']['indexedcolors'] = 0;
 404            $functionname = $this->_imagecreatefunction;
 405            $this->_img['operator']['resource'] = $functionname($this->_img['operator']['width'], $this->_img['operator']['height']);
 406            // set default type jpg.
 407            $this->_img['operator']['type'] = 2;
 408            if (isset($args[2]) && is_string($args[2])) {
 409            	//neues bild mit farbe f?&#x192;llen
 410            	$fillcolor = $this->_hexToPHPColor($args[2]);
 411            	imagefill($this->_img['operator']['resource'], 0, 0, $fillcolor);
 412            	$this->_img['operator']['color'] = $fillcolor;
 413            } else {
 414            	$this->_img['operator']['color'] = 0;
 415			}
 416		} elseif ($argc == 1 && is_string($args[0])) {
 417			//bild aus datei laden. width und height original grâ&#x20AC;?sse
 418			$this->_img['operator'] = $this->_loadFile($args[0]);
 419			$this->_img['operator']['indexedcolors'] = imagecolorstotal($this->_img['operator']['resource']);
 420			$this->_img['operator']['color'] = -1;
 421		} else {
 422			return false;
 423		}
 424		return true;
 425	}
 426
 427	/**
 428     * Loads a image file
 429     *
 430     * @access private
 431     * @param string $filename imagefile to load
 432     * @return array associative array with the loaded filedata
 433     */
 434	function _loadFile($filename) {
 435		if (file_exists($filename)) {
 436			$info = getimagesize($filename);
 437			$filedata['width'] = $info[0];
 438			$filedata['height'] = $info[1];
 439			($filedata['width'] >= $filedata['height']) ? ($filedata['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) : ($filedata['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL);
 440           	$filedata['aspectratio'] = $filedata['width'] / $filedata['height'];
 441			$filedata['type'] = $info[2];
 442
 443			if ($this->_types[$filedata['type']]['supported'] < 1) {
 444				trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$filedata['type']]['ext'].') not supported for reading.', E_USER_ERROR);
 445				return null;
 446			}
 447			switch ($filedata['type']) {
 448				case 1:
 449					$dummy = imagecreatefromgif($filename);
 450					$functionname = $this->_imagecreatefunction;
 451					$filedata['resource'] = $functionname($filedata['width'], $filedata['height']);
 452					imagecopy($filedata['resource'], $dummy, 0, 0, 0, 0, $filedata['width'], $filedata['height']);
 453					imagedestroy($dummy);
 454					break;
 455
 456				case 2:
 457					$filedata['resource'] = imagecreatefromjpeg($filename);
 458					break;
 459
 460				case 3:
 461					$dummy = imagecreatefrompng($filename);
 462					if (imagecolorstotal($dummy) != 0) {
 463						$functionname = $this->_imagecreatefunction;
 464						$filedata['resource'] = $functionname($filedata['width'], $filedata['height']);
 465						imagecopy($filedata['resource'], $dummy, 0, 0, 0, 0, $filedata['width'], $filedata['height']);
 466					} else {
 467						$filedata['resource'] = $dummy;
 468					}
 469					unset($dummy);
 470					break;
 471
 472				default:
 473					trigger_error($this->_error_prefix . 'Imagetype not supported.', E_USER_ERROR);
 474					return null;
 475			}
 476			return $filedata;
 477		} else {
 478			trigger_error($this->_error_prefix . 'Imagefile (' . $filename . ') does not exist.', E_USER_ERROR);
 479			return null;
 480		}
 481	}
 482
 483	/**
 484     * Output a image to the browser
 485     *
 486     * $output_type can be one of the following:<br>
 487     * <ul>
 488     * <li>'gif' -> gif image (if supported) (8-bit indexed colors)</li>
 489     * <li>'png' -> png image (if supported) (truecolor)</li>
 490     * <li>'png8' -> png image (if supported) (8-bit indexed colors)</li>
 491     * <li>'jpg' -> jpeg image (if supported) (truecolor)</li>
 492     * </ul>
 493     * (default: same as original)
 494     *
 495     * $dither:<br>
 496     * If this is true than dither is used on the conversion from truecolor to 8-bit indexed imageformats (png8, gif)<br>
 497     * (default = false)
 498     *
 499     * @param string|integer $output_type type of outputted image
 500     * @param integer $output_quality jpeg quality of outputted image (default: IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY)
 501     * @param bool $dither use dither
 502     * @return bool true on success, otherwise false
 503     */
 504	function output($output_type = false, $output_quality = false, $dither = false) {
 505		if ($output_type === false) {
 506			$output_type = $this->_img['main']['output_type'];
 507		}
 508		switch ($output_type) {
 509			case 1:
 510			case 'gif':
 511			case 'GIF':
 512				if ($this->_types[1]['supported'] < 2) {
 513					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 514					return null;
 515				}
 516				header ('Content-type: ' . $this->_types[$output_type]['mime']);
 517				if ($this->_gd_version >= 2) {
 518					if ($this->_img['main']['indexedcolors'] == 0) {
 519						$dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']);
 520						imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']);
 521						if ($output_quality === false) {
 522							$output_quality = IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS;
 523						}
 524						imagetruecolortopalette($dummy, $dither, $output_quality);
 525					}
 526					imagegif($dummy);
 527					imagedestroy($dummy);
 528				}
 529				else {
 530					imagegif($this->_img['main']['resource']);
 531				}
 532				break;
 533
 534			case 2:
 535			case '2':
 536			case 'jpg':
 537			case 'jpeg':
 538			case 'JPG':
 539			case 'JPEG':
 540				if ($this->_types[2]['supported'] < 2) {
 541					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 542					return null;
 543				}
 544				header ('Content-type: ' . $this->_types[$output_type]['mime']);
 545				if ($output_quality === false) {
 546					$output_quality = IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY;
 547				}
 548				imagejpeg($this->_img['main']['resource'], '', $output_quality);
 549				break;
 550
 551			case 3:
 552			case '3':
 553			case 'png':
 554			case 'PNG':
 555			case 'png24':
 556			case 'PNG24':
 557				if ($this->_types[3]['supported'] < 2) {
 558					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 559					return null;
 560				}
 561				header ('Content-type: ' . $this->_types[$output_type]['mime']);
 562				imagepng($this->_img['main']['resource']);
 563				break;
 564
 565			case 4:
 566			case '4':
 567			case 'png8':
 568			case 'PNG8':
 569				if ($this->_types[3]['supported'] < 2) {
 570					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 571					return null;
 572				}
 573				header ('Content-type: ' . $this->_types[$output_type]['mime']);
 574				if ($this->_gd_version >= 2) {
 575					if ($this->_img['main']['indexedcolors'] == 0) {
 576						$dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']);
 577						imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']);
 578						if ($output_quality === false) {
 579							$output_quality = IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS;
 580						}
 581						imagetruecolortopalette($dummy, $dither, $output_quality);
 582					}
 583					imagepng($dummy);
 584					imagedestroy($dummy);
 585				}
 586				else {
 587					imagepng($this->_img['main']['resource']);
 588				}
 589				break;
 590
 591			default:
 592				trigger_error($this->_error_prefix . 'Output-Imagetype not supported.', E_USER_ERROR);
 593				return null;
 594		}
 595		return true;
 596	}
 597
 598	/**
 599     * Save a image to disk
 600     *
 601     * $output_type can be one of the following:<br>
 602     * <ul>
 603     * <li>'gif' -> gif image (if supported) (8-bit indexed colors)</li>
 604     * <li>'png' -> png image (if supported) (truecolor)</li>
 605     * <li>'png8' -> png image (if supported) (8-bit indexed colors)</li>
 606     * <li>'jpg' -> jpeg image (if supported) (truecolor)</li>
 607     * </ul>
 608     * (default: same as original)
 609     *
 610     * $dither:<br>
 611     * If this is true than dither is used on the conversion from truecolor to 8-bit indexed imageformats (png8, gif)<br>
 612     * (default = false)
 613     *
 614     * @param string $filename filename of saved image
 615     * @param string|integer $output_type type of saved image
 616     * @param integer $output_quality jpeg quality of saved image (default: IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY)
 617     * @param bool $dither use dither
 618     * @return bool true on success, otherwise false
 619     */
 620	function save($filename, $output_type = false, $output_quality = false, $dither = false) {
 621		if ($output_type === false) {
 622			$output_type = $this->_img['main']['output_type'];
 623		}
 624		switch ($output_type) {
 625			case 1:
 626			case 'gif':
 627			case 'GIF':
 628				if ($this->_types[1]['supported'] < 2) {
 629					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 630					return null;
 631				}
 632				if ($this->_gd_version >= 2) {
 633					if ($this->_img['main']['indexedcolors'] == 0) {
 634						$dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']);
 635						imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']);
 636						if ($output_quality === false) {
 637							$output_quality = IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS;
 638						}
 639						imagetruecolortopalette($dummy, $dither, $output_quality);
 640					}
 641					imagegif($dummy, $filename);
 642					imagedestroy($dummy);
 643				}
 644				else {
 645					imagegif($this->_img['main']['resource']);
 646				}
 647				break;
 648
 649			case 2:
 650			case '2':
 651			case 'jpg':
 652			case 'jpeg':
 653			case 'JPG':
 654			case 'JPEG':
 655				if ($this->_types[2]['supported'] < 2) {
 656					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 657					return null;
 658				}
 659				if ($output_quality === false) {
 660					$output_quality = IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY;
 661				}
 662				imagejpeg($this->_img['main']['resource'], $filename, $output_quality);
 663				break;
 664
 665			case 3:
 666			case '3':
 667			case 'png':
 668			case 'PNG':
 669			case 'png24':
 670			case 'PNG24':
 671				if ($this->_types[3]['supported'] < 2) {
 672					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 673					return null;
 674				}
 675				header ('Content-type: ' . $this->_types[$output_type]['mime']);
 676				imagepng($this->_img['main']['resource'], $filename);
 677				break;
 678
 679			case 4:
 680			case '4':
 681			case 'png8':
 682			case 'PNG8':
 683				if ($this->_types[3]['supported'] < 2) {
 684					trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR);
 685					return null;
 686				}
 687				if ($this->_gd_version >= 2) {
 688					if ($this->_img['main']['indexedcolors'] == 0) {
 689						$dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']);
 690						imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']);
 691						if ($output_quality === false) {
 692							$output_quality = IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS;
 693						}
 694						imagetruecolortopalette($dummy, $dither, $output_quality);
 695					}
 696					imagepng($dummy, $filename);
 697					imagedestroy($dummy);
 698				}
 699				else {
 700					imagepng($this->_img['main']['resource'], $filename);
 701				}
 702				break;
 703
 704			default:
 705				trigger_error($this->_error_prefix . 'Output-Imagetype not supported.', E_USER_ERROR);
 706				return null;
 707		}
 708		return true;
 709	}
 710
 711	/**
 712     * Sets the resize method of choice
 713     *
 714     * $method can be one of the following:<br>
 715     * <ul>
 716     * <li>'resize' -> supported by every version of GD (fast but ugly resize of image)</li>
 717     * <li>'resample' -> only supported by GD version >= 2.0 (slower but antialiased resize of image)</li>
 718     * <li>'workaround' -> supported by every version of GD (workaround function for bicubic resizing, downsizing, VERY slow!, taken from php.net comments)</li>
 719     * <li>'workaround2' -> supported by every version of GD (alternative workaround function for bicubic resizing, down- and upsizing, VERY VERY slow!, taken from php.net comments)</li>
 720     * </ul>
 721     *
 722     * @param string|integer $method resize method
 723     * @return bool true on success, otherwise false
 724     */
 725	function setResizeMethod($method) {
 726		switch ($method) {
 727			case 1:
 728			case '1':
 729			case 'resize':
 730				$this->_resize_function = 'imagecopyresized';
 731				break;
 732
 733			case 2:
 734			case '2':
 735			case 'resample':
 736				if (!function_exists('imagecopyresampled')) {
 737					// no error message. just return false.
 738					return null;
 739				}
 740				$this->_resize_function = 'imagecopyresampled';
 741				break;
 742
 743			case 3:
 744			case '3':
 745			case 'resample_workaround':
 746			case 'workaround':
 747			case 'bicubic':
 748				$this->_resize_function = '$this->_imageCopyResampledWorkaround';
 749				break;
 750
 751			case 4:
 752			case '4':
 753			case 'resample_workaround2':
 754			case 'workaround2':
 755			case 'bicubic2':
 756				$this->_resize_function = '$this->_imageCopyResampledWorkaround2';
 757				break;
 758
 759			default:
 760				trigger_error($this->_error_prefix . 'Resizemethod not supported.', E_USER_ERROR);
 761				return null;
 762		}
 763		return true;
 764	}
 765
 766	/**
 767     * Resize the current image
 768     *
 769     * if $width = 0 the new width will be calculated from the $height value preserving the correct aspectratio.<br>
 770     *
 771     * if $height = 0 the new height will be calculated from the $width value preserving the correct aspectratio.<br>
 772     *
 773     * $mode can be one of the following:<br>
 774     * <ul>
 775     * <li>0 -> image will be resized to the new output size, regardless of the original aspectratio. (default)</li>
 776     * <li>1 -> image will be cropped if necessary to preserve the aspectratio and avoid image distortions.</li>
 777     * <li>2 -> image will be resized preserving its original aspectratio. differences to the new outputsize will be filled with $bgcolor</li>
 778     * </ul>
 779     *
 780     * if $autorotate is set to true the given $width and $height values may "change place" if the given image bias is different from the original one.<br>
 781     * if either $width or $height is 0, the new size will be applied to either the new width or the new height based on the bias value of the original image.<br>
 782     * (default = false)
 783     *
 784     * @param integer $width new width of image
 785     * @param integer $height new height of image
 786     * @param integer $mode resize mode
 787     * @param bool $autorotate use autorotating
 788     * @param string $bgcolor background fillcolor (hexformat, e.g. '#FF0000')
 789     * @return bool true on success, otherwise false
 790     */
 791	function newOutputSize($width, $height, $mode = 0, $autorotate = false, $bgcolor = '#000000') {
 792		if ($width > 0 && $height > 0 && is_int($width) && is_int($height)) {
 793			//ignore aspectratio
 794			if (!$mode) {
 795				//do not crop to get correct aspectratio
 796				($width >= $height) ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL);
 797				if ($this->_img['main']['bias'] == $this->_img['target']['bias'] || !$autorotate) {
 798					$this->_img['target']['width'] = $width;
 799					$this->_img['target']['height'] = $height;
 800				} else {
 801					$this->_img['target']['width'] = $height;
 802					$this->_img['target']['height'] = $width;
 803				}
 804				$this->_img['target']['aspectratio'] = $this->_img['target']['width'] / $this->_img['target']['height'];
 805
 806				$cpy_w = $this->_img['main']['width'];
 807				$cpy_h = $this->_img['main']['height'];
 808				$cpy_w_offset = 0;
 809				$cpy_h_offset = 0;
 810			} elseif ($mode == 1) {
 811				//crop to get correct aspectratio
 812				($width >= $height) ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL);
 813				if ($this->_img['main']['bias'] == $this->_img['target']['bias'] || !$autorotate) {
 814					$this->_img['target']['width'] = $width;
 815					$this->_img['target']['height'] = $height;
 816				} else {
 817					$this->_img['target']['width'] = $height;
 818					$this->_img['target']['height'] = $width;
 819				}
 820				$this->_img['target']['aspectratio'] = $this->_img['target']['width'] / $this->_img['target']['height'];
 821
 822				if ($this->_img['main']['width'] / $this->_img['target']['width'] >= $this->_img['main']['height'] / $this->_img['target']['height']) {
 823					$cpy_h = $this->_img['main']['height'];
 824					$cpy_w = (integer) $this->_img['main']['height'] * $this->_img['target']['aspectratio'];
 825					$cpy_w_offset = (integer) ($this->_img['main']['width'] - $cpy_w) / 2;
 826					$cpy_h_offset = 0;
 827				} else {
 828					$cpy_w = $this->_img['main']['width'];
 829					$cpy_h = (integer) $this->_img['main']['width'] / $this->_img['target']['aspectratio'];
 830					$cpy_h_offset = (integer) ($this->_img['main']['height'] - $cpy_h) / 2;
 831					$cpy_w_offset = 0;
 832				}
 833			}
 834			elseif ($mode == 2) {
 835				//fill remaining background with a color to keep aspectratio
 836				$final_aspectratio = $width / $height;
 837				if ($final_aspectratio < $this->_img['main']['aspectratio']) {
 838					$this->_img['target']['width'] = $width;
 839					$this->_img['target']['height'] = (integer) $width / $this->_img['main']['aspectratio'];
 840					$cpy_w_offset2 = 0;
 841					$cpy_h_offset2 = (integer) (($height - $this->_img['target']['height']) / 2);
 842				}
 843				else {
 844					$this->_img['target']['height'] = $height;
 845					$this->_img['target']['width'] = (integer) $height * $this->_img['main']['aspectratio'];
 846					$cpy_h_offset2 = 0;
 847					$cpy_w_offset2 = (integer) (($width - $this->_img['target']['width']) / 2);
 848				}
 849				$this->_img['target']['aspectratio'] = $this->_img['main']['aspectratio'];
 850				$cpy_w = $this->_img['main']['width'];
 851				$cpy_h = $this->_img['main']['height'];
 852				$cpy_w_offset = 0;
 853				$cpy_h_offset = 0;
 854			}
 855		} elseif (($width == 0 && $height > 0) || ($width > 0 && $height == 0) && is_int($width) && is_int($height)) {
 856			//keep aspectratio
 857			if ($autorotate == true) {
 858				if ($this->_img['main']['bias'] == IMAGE_TOOLBOX_BIAS_HORIZONTAL && $width > 0) {
 859					$height = $width;
 860					$width = 0;
 861				} elseif ($this->_img['main']['bias'] == IMAGE_TOOLBOX_BIAS_VERTICAL && $height > 0) {
 862					$width = $height;
 863					$height = 0;
 864				}
 865			}
 866			($width >= $height) ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL);
 867			if ($width != 0) {
 868				$this->_img['target']['width'] = $width;
 869				$this->_img['target']['height'] = (integer) $width / $this->_img['main']['aspectratio'];
 870			} else {
 871				$this->_img['target']['height'] = $height;
 872				$this->_img['target']['width'] = (integer) $height * $this->_img['main']['aspectratio'];
 873			}
 874			$this->_img['target']['aspectratio'] = $this->_img['main']['aspectratio'];
 875
 876			$cpy_w = $this->_img['main']['width'];
 877			$cpy_h = $this->_img['main']['height'];
 878			$cpy_w_offset = 0;
 879			$cpy_h_offset = 0;
 880		} else {
 881			trigger_error($this->_error_prefix . 'Outputwidth and -height must be integers greater zero.', E_USER_ERROR);
 882			return null;
 883		}
 884
 885		//create resized picture
 886		$functionname = $this->_imagecreatefunction;
 887		$dummy = $functionname($this->_img['target']['width'] + 1, $this->_img['target']['height'] + 1);
 888		eval($this->_resize_function . '($dummy, $this->_img["main"]["resource"], 0, 0, $cpy_w_offset, $cpy_h_offset, $this->_img["target"]["width"], $this->_img["target"]["height"], $cpy_w, $cpy_h);');
 889		if ($mode == 2) {
 890			$this->_img['target']['resource'] = $functionname($width, $height);
 891			$fillcolor = $this->_hexToPHPColor($bgcolor);
 892            imagefill($this->_img['target']['resource'], 0, 0, $fillcolor);
 893		} else {
 894			$this->_img['target']['resource'] = $functionname($this->_img['target']['width'], $this->_img['target']['height']);
 895			$cpy_w_offset2 = 0;
 896			$cpy_h_offset2 = 0;
 897		}
 898		imagecopy($this->_img['target']['resource'], $dummy, $cpy_w_offset2, $cpy_h_offset2, 0, 0, $this->_img['target']['width'], $this->_img['target']['height']);
 899		imagedestroy($dummy);
 900
 901		if ($mode == 2) {
 902			$this->_img['target']['width'] = $width;
 903            $this->_img['target']['height'] = $height;
 904        }
 905		//update _img['main'] with new data
 906		foreach ($this->_img['target'] as $key => $value) {
 907			$this->_img['main'][$key] = $value;
 908		}
 909		unset ($this->_img['target']);
 910
 911		return true;
 912	}
 913
 914	/**
 915     * Adds a new image resource based on the given parameters.
 916     *
 917     * It does not overwrite the existing image resource.<br>
 918     * Instead it is used to load a second image to merge with the existing image.
 919     *
 920     * Parameter:<br>
 921     * <i>string</i> <b>$file</b> imagefile to load<br>
 922     * Or:<br>
 923     * <i>integer</i> <b>$width</b> imagewidth of new image to be created<br>
 924     * <i>integer</i> <b>$height</b> imageheight of new image to be created<br>
 925     * <i>string</i> <b>$fillcolor</b> optional fill the new image with this color (hexformat, e.g. '#FF0000')<br>
 926     */
 927	function addImage() {
 928		$args = func_get_args();
 929		$argc = func_num_args();
 930
 931		if ($this->_addImage($argc, $args)) {
 932			return true;
 933		} else {
 934			trigger_error($this->_error_prefix . 'failed to add image.', E_USER_ERROR);
 935			return false;
 936		}
 937	}
 938
 939	/**
 940     * Blend two images.
 941     *
 942     * Original image and the image loaded with {@link addImage() addImage}<br>
 943     * NOTE: This operation can take very long and is not intended for realtime use.
 944     * (but of course depends on the power of your server :) )
 945     *
 946     * IMPORTANT: {@link imagecopymerge() imagecopymerged} doesn't work with PHP 4.3.2. Bug ID: {@link http://bugs.php.net/bug.php?id=24816 24816}<br>
 947     *
 948     * $x:<br>
 949     * negative values are possible.<br>
 950     * You can also use the following keywords ('left', 'center' or 'middle', 'right').<br>
 951     * Additionally you can specify an offset in pixel with the keywords like this 'left +10'.<br>
 952     * (default = 0)
 953     *
 954     * $y:<br>
 955     * negative values are possible.<br>
 956     * You can also use the following keywords ('top', 'center' or 'middle', 'bottom').<br>
 957     * Additionally you can specify an offset in pixel with the keywords like this 'bottom -10'.<br>
 958     * (default = 0)
 959     *
 960     * Possible values for $mode:
 961     * <ul>
 962     *  <li>IMAGE_TOOLBOX_BLEND_COPY</li>
 963     *  <li>IMAGE_TOOLBOX_BLEND_MULTIPLY</li>
 964     *  <li>IMAGE_TOOLBOX_BLEND_SCREEN</li>
 965     *  <li>IMAGE_TOOLBOX_BLEND_DIFFERENCE</li>
 966     *  <li>IMAGE_TOOLBOX_BLEND_EXCLUSION</li>
 967     *  <li>IMAGE_TOOLBOX_BLEND_OVERLAY</li>
 968     * </ul>
 969     *
 970     * $percent:<br>
 971     * alpha value in percent of blend effect (0 - 100)<br>
 972     * (default = 100)
 973     *
 974     * @param string|integer $x Horizontal position of second image.
 975     * @param integer $y Vertical position of second image. negative values are possible.
 976     * @param integer $mode blend mode.
 977     * @param integer $percent alpha value
 978     */
 979	function blend($x = 0, $y = 0, $mode = IMAGE_TOOLBOX_BLEND_COPY, $percent = 100) {
 980		if (is_string($x) || is_string($y)) {
 981			list($xalign, $xalign_offset) = explode(" ", $x);
 982			list($yalign, $yalign_offset) = explode(" ", $y);
 983		}
 984		if (is_string($x)) {
 985			switch ($xalign) {
 986				case 'left':
 987					$dst_x = 0 + $xalign_offset;
 988					$src_x = 0;
 989					$src_w = $this->_img['operator']['width'];
 990					break;
 991
 992				case 'right':
 993					$dst_x = ($this->_img['main']['width'] - $this->_img['operator']['width']) + $xalign_offset;
 994					$src_x = 0;
 995					$src_w = $this->_img['operator']['width'];
 996					break;
 997
 998				case 'middle':
 999				case 'center':
1000					$dst_x = (($this->_img['main']['width'] / 2) - ($this->_img['operator']['width'] / 2)) + $yalign_offset;
1001					$src_x = 0;
1002					$src_w = $this->_img['operator']['width'];
1003					break;
1004			}
1005		} else {
1006			if ($x >= 0) {
1007				$dst_x = $x;
1008				$src_x = 0;
1009				$src_w = $this->_img['operator']['width'];
1010			} else {
1011				$dst_x = 0;
1012				$src_x = abs($x);
1013				$src_w = $this->_img['operator']['width'] - $src_x;
1014			}
1015		}
1016		if (is_string($y)) {
1017			switch ($yalign) {
1018				case 'top':
1019					$dst_y = 0 + $yalign_offset;
1020					$src_y = 0;
1021					$src_h = $this->_img['operator']['height'];
1022					break;
1023
1024				case 'bottom':
1025					$dst_y = ($this->_img['main']['height'] - $this->_img['operator']['height']) + $yalign_offset;
1026					$src_y = 0;
1027					$src_h = $this->_img['operator']['height'];
1028					break;
1029
1030				case 'middle':
1031				case 'center':
1032					$dst_y = (($this->_img['main']['height'] / 2) - ($this->_img['operator']['height'] / 2)) + $yalign_offset;
1033					$src_y = 0;
1034					$src_h = $this->_img['operator']['height'];
1035					break;
1036			}
1037		} else {
1038			if ($y >= 0) {
1039				$dst_y = $y;
1040				$src_y = 0;
1041				$src_h = $this->_img['operator']['height'];
1042			} else {
1043				$dst_y = 0;
1044				$src_y = abs($y);
1045				$src_h = $this->_img['operator']['height'] - $src_y;
1046			}
1047		}
1048		$this->_imageBlend($mode, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent);
1049		return true;
1050	}
1051
1052	/**
1053     * Blend two images.
1054     *
1055     * @access private
1056     */
1057	function _imageBlend($mode, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent) {
1058		if ($mode == IMAGE_TOOLBOX_BLEND_COPY) {
1059			if ($percent == 100) {
1060				imagecopy($this->_img['main']['resource'], $this->_img['operator']['resource'], $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
1061			} else {
1062				imagecopymerge($this->_img['main']['resource'], $this->_img['operator']['resource'], $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent);
1063			}
1064		} else {
1065			$functionname = $this->_imagecreatefunction;
1066			$dummy = $functionname($src_w, $src_h);
1067			for ($y=0; $y < $src_h; $y++) {
1068				for ($x=0; $x < $src_w; $x++) {
1069					$colorindex = imagecolorat($this->_img['main']['resource'], $dst_x + $x, $dst_y + $y);
1070					$colorrgb1 = imagecolorsforindex($this->_img['main']['resource'], $colorindex);
1071					$colorindex = imagecolorat($this->_img['operator']['resource'], $src_x + $x, $src_y + $y);
1072					$colorrgb2 = imagecolorsforindex($this->_img['operator']['resource'], $colorindex);
1073					$colorblend = $this->_calculateBlendvalue($mode, $colorrgb1, $colorrgb2);
1074					$newcolor = imagecolorallocate($dummy, $colorblend['red'], $colorblend['green'], $colorblend['blue']);
1075					imagesetpixel($dummy, $x, $y, $newcolor);
1076				}
1077			}
1078
1079			$this->_img['target']['resource'] = $functionname($this->_img['main']['width'], $this->_img['main']['height']);
1080			imagecopy($this->_img['target']['resource'], $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']);
1081			imagecopymerge($this->_img['target']['resource'], $dummy, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent);
1082
1083			$this->_img['main']['resource'] = $this->_img['target']['resource'];
1084			unset($this->_img['target']);
1085		}
1086	}
1087
1088	/**
1089     * Calculate blend values for given blend mode
1090     *
1091     * @access private
1092     */
1093	function _calculateBlendvalue($mode, $colorrgb1, $colorrgb2) {
1094		switch ($mode) {
1095			case IMAGE_TOOLBOX_BLEND_MULTIPLY:
1096				$c['red'] = ($colorrgb1['red'] * $colorrgb2['red']) >> 8;
1097				$c['green'] = ($colorrgb1['green'] * $colorrgb2['green']) >> 8;
1098				$c['blue'] = ($colorrgb1['blue'] * $colorrgb2['blue']) >> 8;
1099				break;
1100
1101			case IMAGE_TOOLBOX_BLEND_SCREEN:
1102				$c['red'] = 255 - ((255 - $colorrgb1['red']) * (255 - $colorrgb2['red']) >> 8);
1103				$c['green'] = 255 - ((255 - $colorrgb1['green']) * (255 - $colorrgb2['green']) >> 8);
1104				$c['blue'] = 255 - ((255 - $colorrgb1['blue']) * (255 - $colorrgb2['blue']) >> 8);
1105				break;
1106
1107			case IMAGE_TOOLBOX_BLEND_DIFFERENCE:
1108				$c['red'] = abs($colorrgb1['red'] - $colorrgb2['red']);
1109				$c['green'] = abs($colorrgb1['green'] - $colorrgb2['green']);
1110				$c['blue'] = abs($colorrgb1['blue'] - $colorrgb2['blue']);
1111				break;
1112
1113			case IMAGE_TOOLBOX_BLEND_NEGATION:
1114				$c['red'] = 255 - abs(255 - $colorrgb1['red'] - $colorrgb2['red']);
1115				$c['green'] = 255 - abs(255 - $colorrgb1['green'] - $colorrgb2['green']);
1116				$c['blue'] = 255 - abs(255 - $colorrgb1['blue'] - $colorrgb2['blue']);
1117				break;
1118
1119			case IMAGE_TOOLBOX_BLEND_EXCLUSION:
1120				$c['red'] = $colorrgb1['red'] + $colorrgb2['red'] - (($colorrgb1['red'] * $colorrgb2['red']) >> 7);
1121				$c['green'] = $colorrgb1['green'] + $colorrgb2['green'] - (($colorrgb1['green'] * $colorrgb2['green']) >> 7);
1122				$c['blue'] = $colorrgb1['blue'] + $colorrgb2['blue'] - (($colorrgb1['blue'] * $colorrgb2['blue']) >> 7);
1123				break;
1124
1125			case IMAGE_TOOLBOX_BLEND_OVERLAY:
1126				if ($colorrgb1['red'] < 128) {
1127					$c['red']= ($colorrgb1['red'] * $colorrgb2['red']) >> 7;
1128				} else {
1129					$c['red'] = 255 - ((255 - $colorrgb1['red']) * (255 - $colorrgb2['red']) >> 7);
1130				}
1131				if ($colorrgb1['green'] < 128) {
1132					$c['green'] = ($colorrgb1['green'] * $colorrgb2['green']) >> 7;
1133				} else {
1134					$c['green'] = 255 - ((255 - $colorrgb1['green']) * (255 - $colorrgb2['green']) >> 7);
1135				}
1136				if ($colorrgb1['blue'] < 128) {
1137					$c['blue'] = ($colorrgb1['blue'] * $colorrgb2['blue']) >> 7;
1138				} else {
1139					$c['blue'] = 255 - ((255 - $colorrgb1['blue']) * (255 - $colorrgb2['blue']) >> 7);
1140				}
1141				break;
1142
1143			default:
1144				break;
1145		}
1146		return $c;
1147	}
1148
1149	/**
1150     * convert iso character coding to unicode (PHP conform)
1151     * needed for TTF text generation of special characters (Latin-2)
1152     *
1153     * @access private
1154     */
1155	function _iso2uni($isoline) {
1156		$iso2uni = array(
1157			173 => "&#161;",
1158			155 => "&#162;",
1159			156 => "&#163;",
1160			15 => "&#164;",
1161			157 => "&#165;",
1162			124 => "&#166;",
1163			21 => "&#167;",
1164			249 => "&#168;",
1165			184 => "&#169;",
1166			166 => "&#170;",
1167			174 => "&#171;",
1168			170 => "&#172;",
1169			169 => "&#174;",
1170			238 => "&#175;",
1171			248 => "&#176;",
1172			241 => "&#177;",
1173			253 => "&#178;",
1174			252 => "&#179;",
1175			239 => "&#180;",
1176			230 => "&#181;",
1177			20 => "&#182;",
1178			250 => "&#183;",
1179			247 => "&#184;",
1180			251 => "&#185;",
1181			167 => "&#186;",
1182			175 => "&#187;",
1183			172 => "&#188;",
1184			171 => "&#189;",
1185			243 => "&#190;",
1186			168 => "&#191;",
1187			183 => "&#192;",
1188			181 => "&#193;",
1189			182 => "&#194;",
1190			199 => "&#195;",
1191			142 => "&#196;",
1192			143 => "&#197;",
1193			146 => "&#198;",
1194			128 => "&#199;",
1195			212 => "&#200;",
1196			144 => "&#201;",
1197			210 => "&#202;",
1198			211 => "&#203;",
1199			141 => "&#204;",
1200			161 => "&#205;",
1201			140 => "&#206;",
1202			139 => "&#207;",
1203			209 => "&#208;",
1204			165 => "&#209;",
1205			227 => "&#210;",
1206			224 => "&#211;",
1207			226 => "&#212;",
1208			229 => "&#213;",
1209			153 => "&#214;",
1210			158 => "&#215;",
1211			157 => "&#216;",
1212			235 => "&#217;",
1213			233 => "&#218;",
1214			234 => "&#219;",
1215			154 => "&#220;",
1216			237 => "&#221;",
1217			232 => "&#222;",
1218			225 => "&#223;",
1219			133 => "&#224;",
1220			160 => "&#225;",
1221			131 => "&#226;",
1222			198 => "&#227;",
1223			132 => "&#228;",
1224			134 => "&#229;",
1225			145 => "&#230;",
1226			135 => "&#231;",
1227			138 => "&#232;",
1228			130 => "&#233;",
1229			136 => "&#234;",
1230			137 => "&#235;",
1231			141 => "&#236;",
1232			161 => "&#237;",
1233			140 => "&#238;",
1234			139 => "&#239;",
1235			208 => "&#240;",
1236			164 => "&#241;",
1237			149 => "&#242;",
1238			162 => "&#243;",
1239			147 => "&#244;",
1240			228 => "&#245;",
1241			148 => "&#246;",
1242			246 => "&#247;",
1243			155 => "&#248;",
1244			151 => "&#249;",
1245			163 => "&#250;",
1246			150 => "&#251;",
1247			129 => "&#252;",
1248			236 => "&#253;",
1249			231 => "&#254;",
1250			152 => "&#255;"
1251		);
1252		$uniline = '';
1253		$len = strlen($isoline);
1254		for ($i=0; $i < $len; $i++){
1255			$thischar = substr($isoline, $i, 1);
1256			$key = ord($thischar);
1257			$uniline .= isset($iso2uni[$key]) ? $iso2uni[$key] : $thischar;
1258		}
1259		return $uniline;
1260	}
1261
1262	/**
1263     * Writes text over the image
1264     *
1265     * only TTF fonts are supported at the moment
1266     *
1267     * $x:<br>
1268     * You can also use the following keywords ('left', 'center' or 'middle', 'right').<br>
1269     * Additionally you can specify an offset in pixel with the keywords like this 'left +10'.<br>
1270     * (default = 0)
1271     *
1272     * $y:<br>
1273     * You can also use the following keywords ('top', 'center' or 'middle', 'bottom').<br>
1274     * Additionally you can specify an offset in pixel with the keywords like this 'bottom -10'.<br>
1275     * (default = 0)
1276     *
1277     * @param string $text text to be generated.
1278     * @param string $font TTF fontfile to be used. (relative paths are ok).
1279     * @param integer $size textsize.
1280     * @param string $color textcolor in hexformat (e.g. '#FF0000').
1281     * @param string|integer $x horizontal postion in pixel.
1282     * @param string|integer $y vertical postion in pixel.
1283     * @param integer $angle rotation of the text.
1284     */
1285	function addText($text, $font, $size, $color, $x, $y, $angle = 0) {
1286		global $HTTP_SERVER_VARS;
1287
1288		if (substr($font, 0, 1) == DIRECTORY_SEPARATOR || (substr($font, 1, 1) == ":" && (substr($font, 2, 1) == "\\" || substr($font, 2, 1) == "/"))) {
1289			$prepath = '';
1290		} else {
1291			$prepath = substr($HTTP_SERVER_VARS['SCRIPT_FILENAME'], 0, strrpos($HTTP_SERVER_VARS['SCRIPT_FILENAME'], DIRECTORY_SEPARATOR)) . DIRECTORY_SEPARATOR;
1292		}
1293		$text = $this->_iso2uni($text);
1294		if (is_string($x) || is_string($y)) {
1295			$textsize = imagettfbbox($size, $angle, $prepath.$font, $text);
1296			$textwidth = abs($textsize[2]);
1297			$textheight = abs($textsize[7]);
1298			list($xalign, $xalign_offset) = explode(" ", $x);
1299			list($yalign, $yalign_offset) = explode(" ", $y);
1300		}
1301		if (is_string($x)) {
1302			switch ($xalign) {
1303				case 'left':
1304					$x = 0 + $xalign_offset;
1305					break;
1306
1307				case 'right':
1308					$x = ($this->_img['main']['width'] - $textwidth) + $xalign_offset;
1309					break;
1310
1311				case 'middle':
1312				case 'center':
1313					$x = (($this->_img['main']['width'] - $textwidth) / 2) + $xalign_offset;
1314					break;
1315			}
1316		}
1317		if (is_string($y)) {
1318			switch ($yalign) {
1319				case 'top':
1320					$y = (0 + $textheight) + $yalign_offset;
1321					break;
1322
1323				case 'bottom':
1324					$y = ($this->_img['main']['height']) + $yalign_offset;
1325					break;
1326
1327				case 'middle':
1328				case 'center':
1329					$y = ((($this->_img['main']['height'] - $textheight) / 2) + $textheight) + $yalign_offset;
1330					break;
1331			}
1332		}
1333		imagettftext($this->_img['main']['resource'], $size, $angle, $x, $y, $this->_hexToPHPColor($color), $prepath . $font, $text);
1334		return true;
1335	}
1336
1337	/**
1338     * workaround function for bicubic resizing. works well for downsizing only. VERY slow. taken from php.net comments
1339     *
1340     * @access private
1341     */
1342	function _imageCopyResampledWorkaround(&$dst_img, &$src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) {
1343		/*
1344		for ($i = 0; $i < imagecolorstotal($src_img); $i++)
1345		{
1346			$colors = ImageColorsForIndex ($src_img, $i);
1347			ImageColorAllocate ($dst_img, $colors['red'],$colors['green'], $colors['blue']);
1348		}
1349		*/
1350		$scaleX = ($src_w - 1) / $dst_w;
1351		$scaleY = ($src_h - 1) / $dst_h;
1352
1353		$scaleX2 = $scaleX / 2.0;
1354		$scaleY2 = $scaleY / 2.0;
1355
1356		for ($j = $src_y; $j < $src_y + $dst_h; $j++) {
1357			$sY = $j * $scaleY;
1358			for ($i = $src_x; $i < $src_x + $dst_w; $i++) {
1359				$sX = $i * $scaleX;
1360
1361				$c1 = ImageColorsForIndex($src_img, ImageColorAt($src_img, (int) $sX, (int) $sY + $scaleY2));
1362				$c2 = ImageColorsForIndex($src_img, ImageColorAt($src_img, (int) $sX, (int) $sY));
1363				$c3 = ImageColorsForIndex($src_img, ImageColorAt($src_img, (int) $sX + $scaleX2, (int) $sY + $scaleY2));
1364				$c4 = ImageColorsForIndex($src_img, ImageColorAt($src_img, (int) $sX + $scaleX2, (int) $sY));
1365
1366				$red = (integer) (($c1['red'] + $c2['red'] + $c3['red'] + $c4['red']) / 4);
1367				$green = (integer) (($c1['green'] + $c2['green'] + $c3['green'] + $c4['green']) / 4);
1368				$blue = (integer) (($c1['blue'] + $c2['blue'] + $c3['blue'] + $c4['blue']) / 4);
1369
1370				$color = ImageColorClosest ($dst_img, $red, $green,$blue);
1371				ImageSetPixel ($dst_img, $dst_x + $i - $src_x, $dst_y + $j - $src_y,$color);
1372			}
1373		}
1374	}
1375
1376	/**
1377     * alternative workaround function for…

Large files files are truncated, but you can click here to view the full file