PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/filemanager/include/php_image_magician.php

https://github.com/molnarzoli82/viola
PHP | 3320 lines | 1624 code | 614 blank | 1082 comment | 289 complexity | 873b98d1cd68064b004ce98c73b40ab4 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0

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

  1. <?php
  2. # ========================================================================#
  3. #
  4. # This work is licensed under the Creative Commons Attribution 3.0 Unported
  5. # License. To view a copy of this license,
  6. # visit http://creativecommons.org/licenses/by/3.0/ or send a letter to
  7. # Creative Commons, 444 Castro Street, Suite 900, Mountain View, California,
  8. # 94041, USA.
  9. #
  10. # All rights reserved.
  11. #
  12. # Author: Jarrod Oberto
  13. # Version: 1.5.1
  14. # Date: 10-05-11
  15. # Purpose: Provide tools for image manipulation using GD
  16. # Param In: See functions.
  17. # Param Out: Produces a resized image
  18. # Requires : Requires PHP GD library.
  19. # Usage Example:
  20. # include("lib/php_image_magician.php");
  21. # $magicianObj = new resize('images/car.jpg');
  22. # $magicianObj -> resizeImage(150, 100, 0);
  23. # $magicianObj -> saveImage('images/car_small.jpg', 100);
  24. #
  25. # - See end of doc for more examples -
  26. #
  27. # Supported file types include: jpg, png, gif, bmp, psd (read)
  28. #
  29. #
  30. #
  31. # The following functions are taken from phpThumb() [available from
  32. # http://phpthumb.sourceforge.net], and are used with written permission
  33. # from James Heinrich.
  34. # - GD2BMPstring
  35. # - GetPixelColor
  36. # - LittleEndian2String
  37. #
  38. # The following functions are from Marc Hibbins and are used with written
  39. # permission (are also under the Attribution-ShareAlike
  40. # [http://creativecommons.org/licenses/by-sa/3.0/] license.
  41. # -
  42. #
  43. # PhpPsdReader is used with written permission from Tim de Koning.
  44. # [http://www.kingsquare.nl/phppsdreader]
  45. #
  46. #
  47. #
  48. # Modificatoin history
  49. # Date Initials Ver Description
  50. # 10-05-11 J.C.O 0.0 Initial build
  51. # 01-06-11 J.C.O 0.1.1 * Added reflections
  52. # * Added Rounded corners
  53. # * You can now use PNG interlacing
  54. # * Added shadow
  55. # * Added caption box
  56. # * Added vintage filter
  57. # * Added dynamic image resizing (resize on the fly)
  58. # * minor bug fixes
  59. # 05-06-11 J.C.O 0.1.1.1 * Fixed undefined variables
  60. # 17-06-11 J.C.O 0.1.2 * Added image_batch_class.php class
  61. # * Minor bug fixes
  62. # 26-07-11 J.C.O 0.1.4 * Added support for external images
  63. # * Can now set the crop poisition
  64. # 03-08-11 J.C.O 0.1.5 * Added reset() method to reset resource to
  65. # original input file.
  66. # * Added method addTextToCaptionBox() to
  67. # simplify adding text to a caption box.
  68. # * Added experimental writeIPTC. (not finished)
  69. # * Added experimental readIPTC. (not finished)
  70. # 11-08-11 J.C.O * Added initial border presets.
  71. # 30-08-11 J.C.O * Added 'auto' crop option to crop portrait
  72. # images near the top.
  73. # 08-09-11 J.C.O * Added cropImage() method to allow standalone
  74. # cropping.
  75. # 17-09-11 J.C.O * Added setCropFromTop() set method - set the
  76. # percentage to crop from the top when using
  77. # crop 'auto' option.
  78. # * Added setTransparency() set method - allows you
  79. # to turn transparency off (like when saving
  80. # as a jpg).
  81. # * Added setFillColor() set method - set the
  82. # background color to use instead of transparency.
  83. # 05-11-11 J.C.O 0.1.5.1 * Fixed interlacing option
  84. # 0-07-12 J.C.O 1.0
  85. #
  86. # Known issues & Limitations:
  87. # -------------------------------
  88. # Not so much an issue, the image is destroyed on the deconstruct rather than
  89. # when we have finished with it. The reason for this is that we don't know
  90. # when we're finished with it as you can both save the image and display
  91. # it directly to the screen (imagedestroy($this->imageResized))
  92. #
  93. # Opening BMP files is slow. A test with 884 bmp files processed in a loop
  94. # takes forever - over 5 min. This test inlcuded opening the file, then
  95. # getting and displaying its width and height.
  96. #
  97. # $forceStretch:
  98. # -------------------------------
  99. # On by default.
  100. # $forceStretch can be disabled by calling method setForceStretch with false
  101. # parameter. If disabled, if an images original size is smaller than the size
  102. # specified by the user, the original size will be used. This is useful when
  103. # dealing with small images.
  104. #
  105. # If enabled, images smaller than the size specified will be stretched to
  106. # that size.
  107. #
  108. # Tips:
  109. # -------------------------------
  110. # * If you're resizing a transparent png and saving it as a jpg, set
  111. # $keepTransparency to false with: $magicianObj->setTransparency(false);
  112. #
  113. # FEATURES:
  114. # * EASY TO USE
  115. # * BMP SUPPORT (read & write)
  116. # * PSD (photoshop) support (read)
  117. # * RESIZE IMAGES
  118. # - Preserve transparency (png, gif)
  119. # - Apply sharpening (jpg) (requires PHP >= 5.1.0)
  120. # - Set image quality (jpg, png)
  121. # - Resize modes:
  122. # - exact size
  123. # - resize by width (auto height)
  124. # - resize by height (auto width)
  125. # - auto (automatically determine the best of the above modes to use)
  126. # - crop - resize as best as it can then crop the rest
  127. # - Force stretching of smaller images (upscale)
  128. # * APPLY FILTERS
  129. # - Convert to grey scale
  130. # - Convert to black and white
  131. # - Convert to sepia
  132. # - Convert to negative
  133. # * ROTATE IMAGES
  134. # - Rotate using predefined "left", "right", or "180"; or any custom degree amount
  135. # * EXTRACT EXIF DATA (requires exif module)
  136. # - make
  137. # - model
  138. # - date
  139. # - exposure
  140. # - aperture
  141. # - f-stop
  142. # - iso
  143. # - focal length
  144. # - exposure program
  145. # - metering mode
  146. # - flash status
  147. # - creator
  148. # - copyright
  149. # * ADD WATERMARK
  150. # - Specify exact x, y placement
  151. # - Or, specify using one of the 9 pre-defined placements such as "tl"
  152. # (for top left), "m" (for middle), "br" (for bottom right)
  153. # - also specify padding from edge amount (optional).
  154. # - Set opacity of watermark (png).
  155. # * ADD BORDER
  156. # * USE HEX WHEN SPECIFYING COLORS (eg: #ffffff)
  157. # * SAVE IMAGE OR OUTPUT TO SCREEN
  158. #
  159. #
  160. # ========================================================================#
  161. class imageLib
  162. {
  163. private $fileName;
  164. private $image;
  165. protected $imageResized;
  166. private $widthOriginal; # Always be the original width
  167. private $heightOriginal;
  168. private $width; # Current width (width after resize)
  169. private $height;
  170. private $imageSize;
  171. private $fileExtension;
  172. private $debug = true;
  173. private $errorArray = array();
  174. private $forceStretch = true;
  175. private $aggresiveSharpening = false;
  176. private $transparentArray = array('.png', '.gif');
  177. private $keepTransparency = true;
  178. private $fillColorArray = array('r'=>255, 'g'=>255, 'b'=>255);
  179. private $sharpenArray = array('jpg');
  180. private $psdReaderPath;
  181. private $filterOverlayPath;
  182. private $isInterlace;
  183. private $captionBoxPositionArray = array();
  184. private $fontDir = 'fonts';
  185. private $cropFromTopPercent = 10;
  186. ## --------------------------------------------------------
  187. function __construct($fileName)
  188. # Author: Jarrod Oberto
  189. # Date: 27-02-08
  190. # Purpose: Constructor
  191. # Param in: $fileName: File name and path.
  192. # Param out: n/a
  193. # Reference:
  194. # Notes:
  195. #
  196. {
  197. if (!$this->testGDInstalled()) { if ($this->debug) { throw new Exception('The GD Library is not installed.'); }else{ throw new Exception(); }};
  198. $this->initialise();
  199. // *** Save the image file name. Only store this incase you want to display it
  200. $this->fileName = $fileName;
  201. $this->fileExtension = fix_strtolower(strrchr($fileName, '.'));
  202. // *** Open up the file
  203. $this->image = $this->openImage($fileName);
  204. // *** Assign here so we don't modify the original
  205. $this->imageResized = $this->image;
  206. // *** If file is an image
  207. if ($this->testIsImage($this->image))
  208. {
  209. // *** Get width and height
  210. $this->width = imagesx($this->image);
  211. $this->widthOriginal = imagesx($this->image);
  212. $this->height = imagesy($this->image);
  213. $this->heightOriginal = imagesy($this->image);
  214. /* Added 15-09-08
  215. * Get the filesize using this build in method.
  216. * Stores an array of size
  217. *
  218. * $this->imageSize[1] = width
  219. * $this->imageSize[2] = height
  220. * $this->imageSize[3] = width x height
  221. *
  222. */
  223. $this->imageSize = getimagesize($this->fileName);
  224. } else {
  225. $this->errorArray[] = 'File is not an image';
  226. }
  227. }
  228. ## --------------------------------------------------------
  229. private function initialise () {
  230. $this->psdReaderPath = dirname(__FILE__) . '/classPhpPsdReader.php';
  231. $this->filterOverlayPath = dirname(__FILE__) . '/filters';
  232. // *** Set if image should be interlaced or not.
  233. $this->isInterlace = false;
  234. }
  235. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  236. Resize
  237. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  238. public function resizeImage($newWidth, $newHeight, $option = 0, $sharpen = false, $autoRotate = false)
  239. # Author: Jarrod Oberto
  240. # Date: 27-02-08
  241. # Purpose: Resizes the image
  242. # Param in: $newWidth:
  243. # $newHeight:
  244. # $option: 0 / exact = defined size;
  245. # 1 / portrait = keep aspect set height;
  246. # 2 / landscape = keep aspect set width;
  247. # 3 / auto = auto;
  248. # 4 / crop= resize and crop;
  249. #
  250. # $option can also be an array containing options for
  251. # cropping. E.G., array('crop', 'r')
  252. #
  253. # This array only applies to 'crop' and the 'r' refers to
  254. # "crop right". Other value include; tl, t, tr, l, m (default),
  255. # r, bl, b, br, or you can specify your own co-ords (which
  256. # isn't recommended.
  257. #
  258. # $sharpen: true: sharpen (jpg only);
  259. # false: don't sharpen
  260. # Param out: n/a
  261. # Reference:
  262. # Notes: To clarify the $option input:
  263. # 0 = The exact height and width dimensions you set.
  264. # 1 = Whatever height is passed in will be the height that
  265. # is set. The width will be calculated and set automatically
  266. # to a the value that keeps the original aspect ratio.
  267. # 2 = The same but based on the width. We try make the image the
  268. # biggest size we can while stil fitting inside the box size
  269. # 3 = Depending whether the image is landscape or portrait, this
  270. # will automatically determine whether to resize via
  271. # dimension 1,2 or 0
  272. # 4 = Will resize and then crop the image for best fit
  273. #
  274. # forceStretch can be applied to options 1,2,3 and 4
  275. #
  276. {
  277. // *** We can pass in an array of options to change the crop position
  278. $cropPos = 'm';
  279. if (is_array($option) && fix_strtolower($option[0]) == 'crop') {
  280. $cropPos = $option[1]; # get the crop option
  281. } else if (strpos($option, '-') !== false) {
  282. // *** Or pass in a hyphen seperated option
  283. $optionPiecesArray = explode('-', $option);
  284. $cropPos = end($optionPiecesArray);
  285. }
  286. // *** Check the option is valid
  287. $option = $this->prepOption($option);
  288. // *** Make sure the file passed in is valid
  289. if (!$this->image) { if ($this->debug) { throw new Exception('file ' . $this->getFileName() .' is missing or invalid'); }else{ throw new Exception(); }};
  290. // *** Get optimal width and height - based on $option
  291. $dimensionsArray = $this->getDimensions($newWidth, $newHeight, $option);
  292. $optimalWidth = $dimensionsArray['optimalWidth'];
  293. $optimalHeight = $dimensionsArray['optimalHeight'];
  294. // *** Resample - create image canvas of x, y size
  295. $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight);
  296. $this->keepTransparancy($optimalWidth, $optimalHeight, $this->imageResized);
  297. imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height);
  298. // *** If '4', then crop too
  299. if ($option == 4 || $option == 'crop') {
  300. if (($optimalWidth >= $newWidth && $optimalHeight >= $newHeight)) {
  301. $this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos);
  302. }
  303. }
  304. // *** If Rotate.
  305. if ($autoRotate) {
  306. $exifData = $this->getExif(false);
  307. if (count($exifData) > 0) {
  308. switch($exifData['orientation']) {
  309. case 8:
  310. $this->imageResized = imagerotate($this->imageResized,90,0);
  311. break;
  312. case 3:
  313. $this->imageResized = imagerotate($this->imageResized,180,0);
  314. break;
  315. case 6:
  316. $this->imageResized = imagerotate($this->imageResized,-90,0);
  317. break;
  318. }
  319. }
  320. }
  321. // *** Sharpen image (if jpg and the user wishes to do so)
  322. if ($sharpen && in_array($this->fileExtension, $this->sharpenArray)) {
  323. // *** Sharpen
  324. $this->sharpen();
  325. }
  326. }
  327. ## --------------------------------------------------------
  328. public function cropImage($newWidth, $newHeight, $cropPos = 'm')
  329. # Author: Jarrod Oberto
  330. # Date: 08-09-11
  331. # Purpose: Crops the image
  332. # Param in: $newWidth: crop with
  333. # $newHeight: crop height
  334. # $cropPos: Can be any of the following:
  335. # tl, t, tr, l, m, r, bl, b, br, auto
  336. # Or:
  337. # a custom position such as '30x50'
  338. # Param out: n/a
  339. # Reference:
  340. # Notes:
  341. #
  342. {
  343. // *** Make sure the file passed in is valid
  344. if (!$this->image) { if ($this->debug) { throw new Exception('file ' . $this->getFileName() .' is missing or invalid'); }else{ throw new Exception(); }};
  345. $this->imageResized = $this->image;
  346. $this->crop($this->width, $this->height, $newWidth, $newHeight, $cropPos);
  347. }
  348. ## --------------------------------------------------------
  349. private function keepTransparancy($width, $height, $im)
  350. # Author: Jarrod Oberto
  351. # Date: 08-04-11
  352. # Purpose: Keep transparency for png and gif image
  353. # Param in:
  354. # Param out: n/a
  355. # Reference:
  356. # Notes:
  357. #
  358. {
  359. // *** If PNG, perform some transparency retention actions (gif untested)
  360. if (in_array($this->fileExtension, $this->transparentArray) && $this->keepTransparency) {
  361. imagealphablending($im, false);
  362. imagesavealpha($im, true);
  363. $transparent = imagecolorallocatealpha($im, 255, 255, 255, 127);
  364. imagefilledrectangle($im, 0, 0, $width, $height, $transparent);
  365. } else {
  366. $color = imagecolorallocate($im, $this->fillColorArray['r'], $this->fillColorArray['g'], $this->fillColorArray['b']);
  367. imagefilledrectangle($im, 0, 0, $width, $height, $color);
  368. }
  369. }
  370. ## --------------------------------------------------------
  371. private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos)
  372. # Author: Jarrod Oberto
  373. # Date: 15-09-08
  374. # Purpose: Crops the image
  375. # Param in: $newWidth:
  376. # $newHeight:
  377. # Param out: n/a
  378. # Reference:
  379. # Notes:
  380. #
  381. {
  382. // *** Get cropping co-ordinates
  383. $cropArray = $this->getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos);
  384. $cropStartX = $cropArray['x'];
  385. $cropStartY = $cropArray['y'];
  386. // *** Crop this bad boy
  387. $crop = imagecreatetruecolor($newWidth , $newHeight);
  388. $this->keepTransparancy($optimalWidth, $optimalHeight, $crop);
  389. imagecopyresampled($crop, $this->imageResized, 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight);
  390. $this->imageResized = $crop;
  391. // *** Set new width and height to our variables
  392. $this->width = $newWidth;
  393. $this->height = $newHeight;
  394. }
  395. ## --------------------------------------------------------
  396. private function getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $pos='m')
  397. #
  398. # Author: Jarrod Oberto
  399. # Date: July 11
  400. # Purpose: Set the cropping area.
  401. # Params in:
  402. # Params out: (array) the crop x and y co-ordinates.
  403. # Notes: When specifying the exact pixel crop position (eg 10x15), be
  404. # very careful as it's easy to crop out of the image leaving
  405. # black borders.
  406. #
  407. {
  408. $pos = fix_strtolower($pos);
  409. // *** If co-ords have been entered
  410. if (strstr($pos, 'x')) {
  411. $pos = str_replace(' ', '', $pos);
  412. $xyArray = explode('x', $pos);
  413. list($cropStartX, $cropStartY) = $xyArray;
  414. } else {
  415. switch ($pos) {
  416. case 'tl':
  417. $cropStartX = 0;
  418. $cropStartY = 0;
  419. break;
  420. case 't':
  421. $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
  422. $cropStartY = 0;
  423. break;
  424. case 'tr':
  425. $cropStartX = $optimalWidth - $newWidth;
  426. $cropStartY = 0;
  427. break;
  428. case 'l':
  429. $cropStartX = 0;
  430. $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
  431. break;
  432. case 'm':
  433. $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
  434. $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
  435. break;
  436. case 'r':
  437. $cropStartX = $optimalWidth - $newWidth;
  438. $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
  439. break;
  440. case 'bl':
  441. $cropStartX = 0;
  442. $cropStartY = $optimalHeight - $newHeight;
  443. break;
  444. case 'b':
  445. $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
  446. $cropStartY = $optimalHeight - $newHeight;
  447. break;
  448. case 'br':
  449. $cropStartX = $optimalWidth - $newWidth;
  450. $cropStartY = $optimalHeight - $newHeight;
  451. break;
  452. case 'auto':
  453. // *** If image is a portrait crop from top, not center. v1.5
  454. if ($optimalHeight > $optimalWidth) {
  455. $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
  456. $cropStartY = ($this->cropFromTopPercent /100) * $optimalHeight;
  457. } else {
  458. // *** Else crop from the center
  459. $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
  460. $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
  461. }
  462. break;
  463. default:
  464. // *** Default to center
  465. $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
  466. $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
  467. break;
  468. }
  469. }
  470. return array('x' => $cropStartX, 'y' => $cropStartY);
  471. }
  472. ## --------------------------------------------------------
  473. private function getDimensions($newWidth, $newHeight, $option)
  474. # Author: Jarrod Oberto
  475. # Date: 17-11-09
  476. # Purpose: Get new image dimensions based on user specificaions
  477. # Param in: $newWidth:
  478. # $newHeight:
  479. # Param out: Array of new width and height values
  480. # Reference:
  481. # Notes: If $option = 3 then this function is call recursivly
  482. #
  483. # To clarify the $option input:
  484. # 0 = The exact height and width dimensions you set.
  485. # 1 = Whatever height is passed in will be the height that
  486. # is set. The width will be calculated and set automatically
  487. # to a the value that keeps the original aspect ratio.
  488. # 2 = The same but based on the width.
  489. # 3 = Depending whether the image is landscape or portrait, this
  490. # will automatically determine whether to resize via
  491. # dimension 1,2 or 0.
  492. # 4 = Resize the image as much as possible, then crop the
  493. # remainder.
  494. {
  495. switch (strval($option))
  496. {
  497. case '0':
  498. case 'exact':
  499. $optimalWidth = $newWidth;
  500. $optimalHeight= $newHeight;
  501. break;
  502. case '1':
  503. case 'portrait':
  504. $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight);
  505. $optimalWidth = $dimensionsArray['optimalWidth'];
  506. $optimalHeight = $dimensionsArray['optimalHeight'];
  507. break;
  508. case '2':
  509. case 'landscape':
  510. $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight);
  511. $optimalWidth = $dimensionsArray['optimalWidth'];
  512. $optimalHeight = $dimensionsArray['optimalHeight'];
  513. break;
  514. case '3':
  515. case 'auto':
  516. $dimensionsArray = $this->getSizeByAuto($newWidth, $newHeight);
  517. $optimalWidth = $dimensionsArray['optimalWidth'];
  518. $optimalHeight = $dimensionsArray['optimalHeight'];
  519. break;
  520. case '4':
  521. case 'crop':
  522. $dimensionsArray = $this->getOptimalCrop($newWidth, $newHeight);
  523. $optimalWidth = $dimensionsArray['optimalWidth'];
  524. $optimalHeight = $dimensionsArray['optimalHeight'];
  525. break;
  526. }
  527. return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);
  528. }
  529. ## --------------------------------------------------------
  530. private function getSizeByFixedHeight($newWidth, $newHeight)
  531. {
  532. // *** If forcing is off...
  533. if (!$this->forceStretch) {
  534. // *** ...check if actual height is less than target height
  535. if ($this->height < $newHeight) {
  536. return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
  537. }
  538. }
  539. $ratio = $this->width / $this->height;
  540. $newWidth = $newHeight * $ratio;
  541. //return $newWidth;
  542. return array('optimalWidth' => $newWidth, 'optimalHeight' => $newHeight);
  543. }
  544. ## --------------------------------------------------------
  545. private function getSizeByFixedWidth($newWidth, $newHeight)
  546. {
  547. // *** If forcing is off...
  548. if (!$this->forceStretch) {
  549. // *** ...check if actual width is less than target width
  550. if ($this->width < $newWidth) {
  551. return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
  552. }
  553. }
  554. $ratio = $this->height / $this->width;
  555. $newHeight = $newWidth * $ratio;
  556. //return $newHeight;
  557. return array('optimalWidth' => $newWidth, 'optimalHeight' => $newHeight);
  558. }
  559. ## --------------------------------------------------------
  560. private function getSizeByAuto($newWidth, $newHeight)
  561. # Author: Jarrod Oberto
  562. # Date: 19-08-08
  563. # Purpose: Depending on the height, choose to resize by 0, 1, or 2
  564. # Param in: The new height and new width
  565. # Notes:
  566. #
  567. {
  568. // *** If forcing is off...
  569. if (!$this->forceStretch) {
  570. // *** ...check if actual size is less than target size
  571. if ($this->width < $newWidth && $this->height < $newHeight) {
  572. return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
  573. }
  574. }
  575. if ($this->height < $this->width)
  576. // *** Image to be resized is wider (landscape)
  577. {
  578. //$optimalWidth = $newWidth;
  579. //$optimalHeight= $this->getSizeByFixedWidth($newWidth);
  580. $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight);
  581. $optimalWidth = $dimensionsArray['optimalWidth'];
  582. $optimalHeight = $dimensionsArray['optimalHeight'];
  583. }
  584. elseif ($this->height > $this->width)
  585. // *** Image to be resized is taller (portrait)
  586. {
  587. //$optimalWidth = $this->getSizeByFixedHeight($newHeight);
  588. //$optimalHeight= $newHeight;
  589. $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight);
  590. $optimalWidth = $dimensionsArray['optimalWidth'];
  591. $optimalHeight = $dimensionsArray['optimalHeight'];
  592. }
  593. else
  594. // *** Image to be resizerd is a square
  595. {
  596. if ($newHeight < $newWidth) {
  597. //$optimalWidth = $newWidth;
  598. //$optimalHeight= $this->getSizeByFixedWidth($newWidth);
  599. $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight);
  600. $optimalWidth = $dimensionsArray['optimalWidth'];
  601. $optimalHeight = $dimensionsArray['optimalHeight'];
  602. } else if ($newHeight > $newWidth) {
  603. //$optimalWidth = $this->getSizeByFixedHeight($newHeight);
  604. //$optimalHeight= $newHeight;
  605. $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight);
  606. $optimalWidth = $dimensionsArray['optimalWidth'];
  607. $optimalHeight = $dimensionsArray['optimalHeight'];
  608. } else {
  609. // *** Sqaure being resized to a square
  610. $optimalWidth = $newWidth;
  611. $optimalHeight= $newHeight;
  612. }
  613. }
  614. return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);
  615. }
  616. ## --------------------------------------------------------
  617. private function getOptimalCrop($newWidth, $newHeight)
  618. # Author: Jarrod Oberto
  619. # Date: 17-11-09
  620. # Purpose: Get optimal crop dimensions
  621. # Param in: width and height as requested by user (fig 3)
  622. # Param out: Array of optimal width and height (fig 2)
  623. # Reference:
  624. # Notes: The optimal width and height return are not the same as the
  625. # same as the width and height passed in. For example:
  626. #
  627. #
  628. # |-----------------| |------------| |-------|
  629. # | | => |**| |**| => | |
  630. # | | |**| |**| | |
  631. # | | |------------| |-------|
  632. # |-----------------|
  633. # original optimal crop
  634. # size size size
  635. # Fig 1 2 3
  636. #
  637. # 300 x 250 150 x 125 150 x 100
  638. #
  639. # The optimal size is the smallest size (that is closest to the crop size)
  640. # while retaining proportion/ratio.
  641. #
  642. # The crop size is the optimal size that has been cropped on one axis to
  643. # make the image the exact size specified by the user.
  644. #
  645. # * represent cropped area
  646. #
  647. {
  648. // *** If forcing is off...
  649. if (!$this->forceStretch) {
  650. // *** ...check if actual size is less than target size
  651. if ($this->width < $newWidth && $this->height < $newHeight) {
  652. return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
  653. }
  654. }
  655. $heightRatio = $this->height / $newHeight;
  656. $widthRatio = $this->width / $newWidth;
  657. if ($heightRatio < $widthRatio) {
  658. $optimalRatio = $heightRatio;
  659. } else {
  660. $optimalRatio = $widthRatio;
  661. }
  662. $optimalHeight = round( $this->height / $optimalRatio );
  663. $optimalWidth = round( $this->width / $optimalRatio );
  664. return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);
  665. }
  666. ## --------------------------------------------------------
  667. private function sharpen()
  668. # Author: Jarrod Oberto
  669. # Date: 08 04 2011
  670. # Purpose: Sharpen image
  671. # Param in: n/a
  672. # Param out: n/a
  673. # Reference:
  674. # Notes:
  675. # Credit: Incorporates Joe Lencioni (August 6, 2008) code
  676. {
  677. if (version_compare(PHP_VERSION, '5.1.0') >= 0) {
  678. // ***
  679. if ($this->aggresiveSharpening) { # A more aggressive sharpening solution
  680. $sharpenMatrix = array( array( -1, -1, -1 ),
  681. array( -1, 16, -1 ),
  682. array( -1, -1, -1 ) );
  683. $divisor = 8;
  684. $offset = 0;
  685. imageconvolution($this->imageResized, $sharpenMatrix, $divisor, $offset);
  686. }
  687. else # More subtle and personally more desirable
  688. {
  689. $sharpness = $this->findSharp($this->widthOriginal, $this->width);
  690. $sharpenMatrix = array(
  691. array(-1, -2, -1),
  692. array(-2, $sharpness + 12, -2), //Lessen the effect of a filter by increasing the value in the center cell
  693. array(-1, -2, -1)
  694. );
  695. $divisor = $sharpness; // adjusts brightness
  696. $offset = 0;
  697. imageconvolution($this->imageResized, $sharpenMatrix, $divisor, $offset);
  698. }
  699. }
  700. else
  701. {
  702. if ($this->debug) { throw new Exception('Sharpening required PHP 5.1.0 or greater.'); }
  703. }
  704. }
  705. ## --------------------------------------------------------
  706. private function sharpen2($level)
  707. {
  708. $sharpenMatrix = array(
  709. array($level, $level, $level),
  710. array($level, (8*$level)+1, $level), //Lessen the effect of a filter by increasing the value in the center cell
  711. array($level, $level, $level)
  712. );
  713. }
  714. ## --------------------------------------------------------
  715. private function findSharp($orig, $final)
  716. # Author: Ryan Rud (http://adryrun.com)
  717. # Purpose: Find optimal sharpness
  718. # Param in: n/a
  719. # Param out: n/a
  720. # Reference:
  721. # Notes:
  722. #
  723. {
  724. $final = $final * (750.0 / $orig);
  725. $a = 52;
  726. $b = -0.27810650887573124;
  727. $c = .00047337278106508946;
  728. $result = $a + $b * $final + $c * $final * $final;
  729. return max(round($result), 0);
  730. }
  731. ## --------------------------------------------------------
  732. private function prepOption($option)
  733. # Author: Jarrod Oberto
  734. # Purpose: Prep option like change the passed in option to lowercase
  735. # Param in: (str/int) $option: eg. 'exact', 'crop'. 0, 4
  736. # Param out: lowercase string
  737. # Reference:
  738. # Notes:
  739. #
  740. {
  741. if (is_array($option)) {
  742. if (fix_strtolower($option[0]) == 'crop' && count($option) == 2) {
  743. return 'crop';
  744. } else {
  745. throw new Exception('Crop resize option array is badly formatted.');
  746. }
  747. } else if (strpos($option, 'crop') !== false) {
  748. return 'crop';
  749. }
  750. if (is_string($option)) {
  751. return fix_strtolower($option);
  752. }
  753. return $option;
  754. }
  755. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  756. Presets
  757. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  758. #
  759. # Preset are pre-defined templates you can apply to your image.
  760. #
  761. # These are inteded to be applied to thumbnail images.
  762. #
  763. public function borderPreset($preset)
  764. {
  765. switch ($preset)
  766. {
  767. case 'simple':
  768. $this->addBorder(7, '#fff');
  769. $this->addBorder(6, '#f2f1f0');
  770. $this->addBorder(2, '#fff');
  771. $this->addBorder(1, '#ccc');
  772. break;
  773. default:
  774. break;
  775. }
  776. }
  777. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  778. Draw border
  779. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  780. public function addBorder($thickness = 1, $rgbArray = array(255, 255, 255))
  781. # Author: Jarrod Oberto
  782. # Date: 05-05-11
  783. # Purpose: Add a border to the image
  784. # Param in:
  785. # Param out:
  786. # Reference:
  787. # Notes: This border is added to the INSIDE of the image
  788. #
  789. {
  790. if ($this->imageResized) {
  791. $rgbArray = $this->formatColor($rgbArray);
  792. $r = $rgbArray['r'];
  793. $g = $rgbArray['g'];
  794. $b = $rgbArray['b'];
  795. $x1 = 0;
  796. $y1 = 0;
  797. $x2 = ImageSX($this->imageResized) - 1;
  798. $y2 = ImageSY($this->imageResized) - 1;
  799. $rgbArray = ImageColorAllocate($this->imageResized, $r, $g, $b);
  800. for($i = 0; $i < $thickness; $i++) {
  801. ImageRectangle($this->imageResized, $x1++, $y1++, $x2--, $y2--, $rgbArray);
  802. }
  803. }
  804. }
  805. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  806. Gray Scale
  807. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  808. public function greyScale()
  809. # Author: Jarrod Oberto
  810. # Date: 07-05-2011
  811. # Purpose: Make image greyscale
  812. # Param in: n/a
  813. # Param out:
  814. # Reference:
  815. # Notes:
  816. #
  817. {
  818. if ($this->imageResized) {
  819. imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
  820. }
  821. }
  822. ## --------------------------------------------------------
  823. public function greyScaleEnhanced()
  824. # Author: Jarrod Oberto
  825. # Date: 07-05-2011
  826. # Purpose: Make image greyscale
  827. # Param in: n/a
  828. # Param out:
  829. # Reference:
  830. # Notes:
  831. #
  832. {
  833. if ($this->imageResized) {
  834. imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
  835. imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -15);
  836. imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, 2);
  837. $this->sharpen($this->width);
  838. }
  839. }
  840. ## --------------------------------------------------------
  841. public function greyScaleDramatic()
  842. # Alias of gd_filter_monopin
  843. {
  844. $this->gd_filter_monopin();
  845. }
  846. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  847. Black 'n White
  848. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  849. public function blackAndWhite()
  850. # Author: Jarrod Oberto
  851. # Date: 07-05-2011
  852. # Purpose: Make image black and white
  853. # Param in: n/a
  854. # Param out:
  855. # Reference:
  856. # Notes:
  857. #
  858. {
  859. if ($this->imageResized) {
  860. imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
  861. imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -1000);
  862. }
  863. }
  864. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  865. Negative
  866. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  867. public function negative()
  868. # Author: Jarrod Oberto
  869. # Date: 07-05-2011
  870. # Purpose: Make image negative
  871. # Param in: n/a
  872. # Param out:
  873. # Reference:
  874. # Notes:
  875. #
  876. {
  877. if ($this->imageResized) {
  878. imagefilter($this->imageResized, IMG_FILTER_NEGATE);
  879. }
  880. }
  881. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  882. Sepia
  883. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  884. public function sepia()
  885. # Author: Jarrod Oberto
  886. # Date: 07-05-2011
  887. # Purpose: Make image sepia
  888. # Param in: n/a
  889. # Param out:
  890. # Reference:
  891. # Notes:
  892. #
  893. {
  894. if ($this->imageResized) {
  895. imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
  896. imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, -10);
  897. imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -20);
  898. imagefilter($this->imageResized, IMG_FILTER_COLORIZE, 60, 30, -15);
  899. }
  900. }
  901. ## --------------------------------------------------------
  902. public function sepia2()
  903. {
  904. if ($this->imageResized) {
  905. $total = imagecolorstotal( $this->imageResized );
  906. for ( $i = 0; $i < $total; $i++ ) {
  907. $index = imagecolorsforindex( $this->imageResized, $i );
  908. $red = ( $index["red"] * 0.393 + $index["green"] * 0.769 + $index["blue"] * 0.189 ) / 1.351;
  909. $green = ( $index["red"] * 0.349 + $index["green"] * 0.686 + $index["blue"] * 0.168 ) / 1.203;
  910. $blue = ( $index["red"] * 0.272 + $index["green"] * 0.534 + $index["blue"] * 0.131 ) / 2.140;
  911. imagecolorset( $this->imageResized, $i, $red, $green, $blue );
  912. }
  913. }
  914. }
  915. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  916. Vintage
  917. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  918. public function vintage()
  919. # Alias of gd_filter_monopin
  920. {
  921. $this->gd_filter_vintage();
  922. }
  923. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  924. Presets By Marc Hibbins
  925. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  926. /** Apply 'Monopin' preset */
  927. public function gd_filter_monopin()
  928. {
  929. if ($this->imageResized) {
  930. imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
  931. imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, -15);
  932. imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -15);
  933. $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'vignette', 100);
  934. }
  935. }
  936. ## --------------------------------------------------------
  937. public function gd_filter_vintage()
  938. {
  939. if ($this->imageResized) {
  940. $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'vignette', 45);
  941. imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, 20);
  942. imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -35);
  943. imagefilter($this->imageResized, IMG_FILTER_COLORIZE, 60, -10, 35);
  944. imagefilter($this->imageResized, IMG_FILTER_SMOOTH, 7);
  945. $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'scratch', 10);
  946. }
  947. }
  948. ## --------------------------------------------------------
  949. /** Apply a PNG overlay */
  950. private function gd_apply_overlay($im, $type, $amount)
  951. #
  952. # Original Author: Marc Hibbins
  953. # License: Attribution-ShareAlike 3.0
  954. # Purpose:
  955. # Params in:
  956. # Params out:
  957. # Notes:
  958. #
  959. {
  960. $width = imagesx($im);
  961. $height = imagesy($im);
  962. $filter = imagecreatetruecolor($width, $height);
  963. imagealphablending($filter, false);
  964. imagesavealpha($filter, true);
  965. $transparent = imagecolorallocatealpha($filter, 255, 255, 255, 127);
  966. imagefilledrectangle($filter, 0, 0, $width, $height, $transparent);
  967. // *** Resize overlay
  968. $overlay = $this->filterOverlayPath . '/' . $type . '.png';
  969. $png = imagecreatefrompng($overlay);
  970. imagecopyresampled($filter, $png, 0, 0, 0, 0, $width, $height, imagesx($png), imagesy($png));
  971. $comp = imagecreatetruecolor($width, $height);
  972. imagecopy($comp, $im, 0, 0, 0, 0, $width, $height);
  973. imagecopy($comp, $filter, 0, 0, 0, 0, $width, $height);
  974. imagecopymerge($im, $comp, 0, 0, 0, 0, $width, $height, $amount);
  975. imagedestroy($comp);
  976. return $im;
  977. }
  978. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  979. Colorise
  980. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  981. public function image_colorize($rgb) {
  982. imageTrueColorToPalette($this->imageResized,true,256);
  983. $numColors = imageColorsTotal($this->imageResized);
  984. for ($x = 0; $x < $numColors; $x++) {
  985. list($r,$g,$b) = array_values(imageColorsForIndex($this->imageResized,$x));
  986. // calculate grayscale in percent
  987. $grayscale = ($r + $g + $b) / 3 / 0xff;
  988. imageColorSet($this->imageResized,$x,
  989. $grayscale * $rgb[0],
  990. $grayscale * $rgb[1],
  991. $grayscale * $rgb[2]
  992. );
  993. }
  994. return true;
  995. }
  996. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  997. Reflection
  998. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  999. public function addReflection($reflectionHeight = 50, $startingTransparency = 30, $inside = false, $bgColor = '#fff', $stretch=false, $divider = 0)
  1000. {
  1001. // *** Convert color
  1002. $rgbArray = $this->formatColor($bgColor);
  1003. $r = $rgbArray['r'];
  1004. $g = $rgbArray['g'];
  1005. $b = $rgbArray['b'];
  1006. $im = $this->imageResized;
  1007. $li = imagecreatetruecolor($this->width, 1);
  1008. $bgc = imagecolorallocate($li, $r, $g, $b);
  1009. imagefilledrectangle($li, 0, 0, $this->width, 1, $bgc);
  1010. $bg = imagecreatetruecolor($this->width, $reflectionHeight);
  1011. $wh = imagecolorallocate($im, 255, 255, 255);
  1012. $im = imagerotate($im, -180, $wh);
  1013. imagecopyresampled($bg, $im, 0, 0, 0, 0, $this->width, $this->height, $this->width, $this->height);
  1014. $im = $bg;
  1015. $bg = imagecreatetruecolor($this->width, $reflectionHeight);
  1016. for ($x = 0; $x < $this->width; $x++) {
  1017. imagecopy($bg, $im, $x, 0, $this->width-$x -1, 0, 1, $reflectionHeight);
  1018. }
  1019. $im = $bg;
  1020. $transaprencyAmount = $this->invertTransparency($startingTransparency, 100);
  1021. // *** Fade
  1022. if ($stretch) {
  1023. $step = 100/($reflectionHeight + $startingTransparency);
  1024. } else{
  1025. $step = 100/$reflectionHeight;
  1026. }
  1027. for($i=0; $i<=$reflectionHeight; $i++){
  1028. if($startingTransparency>100) $startingTransparency = 100;
  1029. if($startingTransparency< 1) $startingTransparency = 1;
  1030. imagecopymerge($bg, $li, 0, $i, 0, 0, $this->width, 1, $startingTransparency);
  1031. $startingTransparency+=$step;
  1032. }
  1033. // *** Apply fade
  1034. imagecopymerge($im, $li, 0, 0, 0, 0, $this->width, $divider, 100); // Divider
  1035. // *** width, height of reflection.
  1036. $x = imagesx($im);
  1037. $y = imagesy($im);
  1038. // *** Determines if the reflection should be displayed inside or outside the image
  1039. if ($inside) {
  1040. // Create new blank image with sizes.
  1041. $final = imagecreatetruecolor($this->width, $this->height);
  1042. imagecopymerge ($final, $this->imageResized, 0, 0, 0, $reflectionHeight, $this->width, $this->height - $reflectionHeight, 100);
  1043. imagecopymerge ($final, $im, 0, $this->height - $reflectionHeight, 0, 0, $x, $y, 100);
  1044. } else {
  1045. // Create new blank image with sizes.
  1046. $final = imagecreatetruecolor($this->width, $this->height + $y);
  1047. imagecopymerge ($final, $this->imageResized, 0, 0, 0, 0, $this->width, $this->height, 100);
  1048. imagecopymerge ($final, $im, 0, $this->height, 0, 0, $x, $y, 100);
  1049. }
  1050. $this->imageResized = $final;
  1051. imagedestroy($li);
  1052. imagedestroy($im);
  1053. }
  1054. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1055. Rotate
  1056. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  1057. public function rotate($value = 90, $bgColor = 'transparent')
  1058. # Author: Jarrod Oberto
  1059. # Date: 07-05-2011
  1060. # Purpose: Rotate image
  1061. # Param in: (mixed) $degrees: (int) number of degress to rotate image
  1062. # (str) param "left": rotate left
  1063. # (str) param "right": rotate right
  1064. # (str) param "upside": upside-down image
  1065. # Param out:
  1066. # Reference:
  1067. # Notes: The default direction of imageRotate() is counter clockwise.
  1068. #
  1069. {
  1070. if ($this->imageResized) {
  1071. if (is_integer($value)) {
  1072. $degrees = $value;
  1073. }
  1074. // *** Convert color
  1075. $rgbArray = $this->formatColor($bgColor);
  1076. $r = $rgbArray['r'];
  1077. $g = $rgbArray['g'];
  1078. $b = $rgbArray['b'];
  1079. if (isset($rgbArray['a'])) {$a = $rgbArray['a']; }
  1080. if (is_string($value)) {
  1081. $value = fix_strtolower($value);
  1082. switch ($value) {
  1083. case 'left':
  1084. $degrees = 90;
  1085. break;
  1086. case 'right':
  1087. $degrees = 270;
  1088. break;
  1089. case 'upside':
  1090. $degrees = 180;
  1091. break;
  1092. default:
  1093. break;
  1094. }
  1095. }
  1096. // *** The default direction of imageRotate() is counter clockwise
  1097. // * This makes it clockwise
  1098. $degrees = 360 - $degrees;
  1099. // *** Create background color
  1100. $bg = ImageColorAllocateAlpha($this->imageResized, $r, $g, $b, $a);
  1101. // *** Fill with background
  1102. ImageFill($this->imageResized, 0, 0 , $bg);
  1103. // *** Rotate
  1104. $this->imageResized = imagerotate($this->imageResized, $degrees, $bg); // Rotate 45 degrees and allocated the transparent colour as the one to make transparent (obviously)
  1105. // Ensure alpha transparency
  1106. ImageSaveAlpha($this->imageResized,true);
  1107. }
  1108. }
  1109. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1110. Round corners
  1111. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  1112. public function roundCorners($radius = 5, $bgColor = 'transparent')
  1113. # Author: Jarrod Oberto
  1114. # Date: 19-05-2011
  1115. # Purpose: Create rounded corners on your image
  1116. # Param in: (int) radius = the amount of curvature
  1117. # (mixed) $bgColor = the corner background color
  1118. # Param out: n/a
  1119. # Reference:
  1120. # Notes:
  1121. #
  1122. {
  1123. // *** Check if the user wants transparency
  1124. $isTransparent = false;
  1125. if (!is_array($bgColor)) {
  1126. if (fix_strtolower($bgColor) == 'transparent') {
  1127. $isTransparent = true;
  1128. }
  1129. }
  1130. // *** If we use transparency, we need to color our curved mask with a unique color
  1131. if ($isTransparent) {
  1132. $bgColor = $this->findUnusedGreen();
  1133. }
  1134. // *** Convert color
  1135. $rgbArray = $this->formatColor($bgColor);
  1136. $r = $rgbArray['r'];
  1137. $g = $rgbArray['g'];
  1138. $b = $rgbArray['b'];
  1139. if (isset($rgbArray['a'])) {$a = $rgbArray['a']; }
  1140. // *** Create top-left corner mask (square)
  1141. $cornerImg = imagecreatetruecolor($radius, $radius);
  1142. //$cornerImg = imagecreate($radius, $radius);
  1143. //imagealphablending($cornerImg, true);
  1144. //imagesavealpha($cornerImg, true);
  1145. //imagealphablending($this->imageResized, false);
  1146. //imagesavealpha($this->imageResized, true);
  1147. // *** Give it a color
  1148. $maskColor = imagecolorallocate($cornerImg, 0, 0, 0);
  1149. // *** Replace the mask color (black) to transparent
  1150. imagecolortransparent($cornerImg, $maskColor);
  1151. // *** Create the image background color
  1152. $imagebgColor = imagecolorallocate($cornerImg, $r, $g, $b);
  1153. // *** Fill the corner area to the user defined color
  1154. imagefill($cornerImg, 0, 0, $imagebgColor);
  1155. imagefilledellipse($cornerImg, $radius, $radius, $radius * 2, $radius * 2, $maskColor );
  1156. // *** Map to top left corner
  1157. imagecopymerge($this->imageResized, $cornerImg, 0, 0, 0, 0, $radius, $radius, 100); #tl
  1158. // *** Map rounded corner to other corners by rotating and applying the mask
  1159. $cornerImg = imagerotate($cornerImg, 90, 0);
  1160. imagecopymerge($this->imageResized, $cornerImg, 0, $this->height - $radius, 0, 0, $radius, $radius, 100); #bl
  1161. $cornerImg = imagerotate($cornerImg, 90, 0);
  1162. imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, $this->height - $radius, 0, 0, $radius, $radius, 100); #br
  1163. $cornerImg = imagerotate($cornerImg, 90, 0);
  1164. imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, 0, 0, 0, $radius, $radius, 100); #tr
  1165. // *** If corners are to be transparent, we fill our chromakey color as transparent.
  1166. if ($isTransparent) {
  1167. //imagecolortransparent($this->imageResized, $imagebgColor);
  1168. $this->imageResized = $this->transparentImage($this->imageResized);
  1169. imagesavealpha($this->imageResized, true);
  1170. }
  1171. }
  1172. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1173. Shadow
  1174. *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
  1175. public function addShadow($shadowAngle=45, $blur=15, $bgColor='transparent')
  1176. #
  1177. # Author: Jarrod Oberto (Adapted from Pascal Naidon)
  1178. # Ref: http://www.les-stooges.org/pascal/webdesign/vignettes/index.php?la=en
  1179. # Purpose: Add a drop shadow to your image
  1180. # Params in: (int) $angle: the angle of the shadow
  1181. # (int) $blur: the blur distance
  1182. # (mixed) $bgColor: the color of the background
  1183. # Params out:
  1184. # Notes:
  1185. #
  1186. {
  1187. // *** A higher number results in a smoother shadow
  1188. define('STEPS', $blur*2);
  1189. // *** Set the shadow distance
  1190. $shadowDistance = $blur*0.25;
  1191. // *** Set blur width and height
  1192. $blurWidth = $blurHeight = $blur;
  1193. if ($shadowAngle == 0) {
  1194. $distWidth = 0;
  1195. $distHeight = 0;
  1196. } else {
  1197. $distWidth = $shadowDistance * cos(deg2rad($shadowAngle));
  1198. $distHeight = $shadowDistance * sin(deg2rad($shadowAngle));
  1199. }
  1200. // *** Convert color
  1201. if (fix_strtolower($bgColor) != 'transparent') {
  1202. $rgbArray = $this->formatColor($bgColor);
  1203. $r0 = $rgbArray['r'];
  1204. $g0 = $rgbArray['g'];
  1205. $b0 = $rgbArray['b'];
  1206. }
  1207. $image = $this->imageResized;
  1208. $width = $this->width;
  1209. $height = $this->height;
  1210. $newImage = imagecreatetruecolor($width, $height);
  1211. imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $width, $height);
  1212. // *** RGB
  1213. $rgb = imagecreatetruecolor($width+$blurWidth,$height+$blurHeight);
  1214. $colour = imagecolorallocate($rgb, 0, 0, 0);
  1215. imagefilledrectangle($rgb, 0, 0, $width+$blurWidth, $height+$blurHeight, $colour);
  1216. $colour = imagecolorallocate($rgb, 255, 255, 255);
  1217. //imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
  1218. imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
  1219. //imagecopymerge($rgb, $newImage, 1+$blurWidth*0.5-$distWidth, 1+$blurHeight*0.5-$distHeight, 0,0, $width, $height, 100);
  1220. imagecopymerge($rgb, $newImage, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, 0,0, $width+$blurWidth, $height+$blurHeight, 100);
  1221. // *** Shadow (alpha)
  1222. $shadow = imagecreatetruecolor($width+$blurWidth,$height+$blurHeight);
  1223. imagealphablending($shadow, false);
  1224. $colour = imagecolorallocate($shadow, 0, 0, 0);
  1225. imagefilledrectangle($shadow, 0, 0, $width+$blurWidth, $height+$blurHeight, $colour);
  1226. for($i=0;$i<=STEPS;$i++) {
  1227. $t = ((1.0*$i)/STEPS);
  1228. $intensity = 255*$t*$t;
  1229. $colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity);
  1230. $points = array(
  1231. $blurWidth*$t,

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