PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/protected/extensions/tiny_mce/assets/plugins/images/connector/php/Image_Toolbox.class.php

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