PageRenderTime 97ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Classes/ImageBatchProcessor.php

https://bitbucket.org/baruffaldi/webapp-urltube
PHP | 585 lines | 518 code | 27 blank | 40 comment | 46 complexity | abdb8f0b5f0bd8c3f6d785235c4e846e MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, MIT
  1. <?php
  2. /**
  3. * ImageBatchProcessor class, version 1.0 (for PHP >= 4.3)
  4. * (c) 2008 Vagharshak Tozalakyan <vagh{at}tozalakyan{dot}com>
  5. *
  6. * This class can be used to perform different kind of operations over a group
  7. * of images. It can proportionally resize images (create thumbnails), rotate
  8. * images, convert between different image formats, append textual labels and/or
  9. * small graphic watermarks to images, etc.
  10. *
  11. * Transformation parameters may be applied to all images in a directory or
  12. * separately to each image in a set - the images in source or destination sets
  13. * may be located in the same or different directories.
  14. *
  15. * The class also contains a traversal method which walks through a directory
  16. * and calls a callback function for each item. The method may be used, for
  17. * example, to rename all images (or other files) in a directory using
  18. * predefined naming template (photo01.jpg, photo02.jpg, ...).
  19. *
  20. * Permission is hereby granted, free of charge, to any person obtaining a copy
  21. * of this software and associated documentation files (the "Software"), to deal
  22. * in the Software without restriction, including without limitation the rights
  23. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  24. * copies of the Software, and to permit persons to whom the Software is
  25. * furnished to do so, subject to the following conditions:
  26. *
  27. * The above copyright notice and this permission notice shall be included in
  28. * all copies or substantial portions of the Software.
  29. *
  30. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  31. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  32. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  33. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  34. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  35. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  36. * THE SOFTWARE.
  37. *
  38. * @version 1.0
  39. * @author Vagharshak Tozalakyan <vagh{at}tozalakyan{dot}com>
  40. * @license http://www.opensource.org/licenses/mit-license.php
  41. */
  42. define('IBP_IMAGE_REGEXP', '/^(.*)(\.jpg|\.jpeg|\.gif|\.png)$/is');
  43. define('IBP_ALL_REGEXP', '/^(.*)$/is');
  44. define('TI_MAX_IMG_SIZE', 100000);
  45. define('TI_JPEG', 'image/jpeg');
  46. define('TI_PNG', 'image/png');
  47. define('TI_GIF', 'image/gif');
  48. define('TI_INTERLACE_OFF', 0);
  49. define('TI_INTERLACE_ON', 1);
  50. define('TI_STDOUT', '');
  51. define('TI_RESOURCE', '-1000');
  52. define('TI_NO_LOGO', '');
  53. define('TI_NO_LABEL', '');
  54. define('TI_POS_LEFT', 0);
  55. define('TI_POS_RIGHT', 1);
  56. define('TI_POS_CENTER', 2);
  57. define('TI_POS_TOP', 3);
  58. define('TI_POS_BOTTOM', 4);
  59. class ThumbnailImage
  60. {
  61. var $srcFile = '';
  62. var $destFile = TI_STDOUT;
  63. var $destType = TI_JPEG;
  64. var $interlace = TI_INTERLACE_OFF;
  65. var $jpegQuality = -1;
  66. var $maxWidth = 100;
  67. var $maxHeight = 100;
  68. var $fitToMax = false;
  69. var $logo = array();
  70. var $label = array();
  71. var $rotateAngle = 0;
  72. var $rotateBgColor = '#ffffff';
  73. var $srcWidth = 0;
  74. var $srcHeight = 0;
  75. function ThumbnailImage($srcFile = '')
  76. {
  77. $this->srcFile = $srcFile;
  78. $this->logo['file'] = TI_NO_LOGO;
  79. $this->logo['vertPos'] = TI_POS_TOP;
  80. $this->logo['horzPos'] = TI_POS_LEFT;
  81. $this->label['text'] = TI_NO_LABEL;
  82. $this->label['vertPos'] = TI_POS_BOTTOM;
  83. $this->label['horzPos'] = TI_POS_RIGHT;
  84. $this->label['font'] = '';
  85. $this->label['size'] = 20;
  86. $this->label['color'] = '#000000';
  87. $this->label['angle'] = 0;
  88. }
  89. function parseColor($hexColor)
  90. {
  91. if (strpos($hexColor, '#') === 0) {
  92. $hexColor = substr($hexColor, 1);
  93. }
  94. $r = hexdec(substr($hexColor, 0, 2));
  95. $g = hexdec(substr($hexColor, 2, 2));
  96. $b = hexdec(substr($hexColor, 4, 2));
  97. return array ($r, $g, $b);
  98. }
  99. function getImageStr($imageFile)
  100. {
  101. if (function_exists('file_get_contents')) {
  102. $str = @file_get_contents($imageFile);
  103. if (!$str) {
  104. $err = sprintf('Failed reading image data from <b>%s</b>', $imageFile);
  105. trigger_error($err, E_USER_ERROR);
  106. }
  107. return $str;
  108. }
  109. $f = fopen($imageFile, 'rb');
  110. if (!$f) {
  111. $err = sprintf('Failed reading image data from <b>%s</b>', $imageFile);
  112. trigger_error($err, E_USER_ERROR);
  113. }
  114. $fsz = @filesize($imageFile);
  115. if (!$fsz) {
  116. $fsz = TI_MAX_IMG_SIZE;
  117. }
  118. $str = fread($f, $fsz);
  119. fclose ($f);
  120. return $str;
  121. }
  122. function loadImage($imageFile, &$imageWidth, &$imageHeight)
  123. {
  124. $imageWidth = 0;
  125. $imageHeight = 0;
  126. $imageData = $this->getImageStr($imageFile);
  127. $image = imagecreatefromstring($imageData);
  128. if (!$image) {
  129. $err = sprintf('Cannot create the copy of <b>%s</b>', $imageFile);
  130. trigger_error($err, E_USER_ERROR);
  131. }
  132. if ($this->rotateAngle && function_exists('imagerotate')) {
  133. list($r, $g, $b) = $this->parseColor($this->rotateBgColor);
  134. $bgColor = imagecolorallocate($image, $r, $g, $b);
  135. $image = imagerotate($image, $this->rotateAngle, $bgColor);
  136. }
  137. $imageWidth = imagesx($image);
  138. $imageHeight = imagesy($image);
  139. $this->srcWidth = $imageWidth;
  140. $this->srcHeight = $imageHeight;
  141. return $image;
  142. }
  143. function getThumbSize($srcWidth, $srcHeight)
  144. {
  145. $maxWidth = $this->maxWidth;
  146. $maxHeight = $this->maxHeight;
  147. $xRatio = $maxWidth / $srcWidth;
  148. $yRatio = $maxHeight / $srcHeight;
  149. $isSmall = ($srcWidth <= $maxWidth && $srcHeight <= $maxHeight);
  150. if (!$this->fitToMax && $isSmall) {
  151. $destWidth = $srcWidth;
  152. $destHeight = $srcHeight;
  153. } elseif ($xRatio * $srcHeight < $maxHeight) {
  154. $destWidth = $maxWidth;
  155. $destHeight = ceil($xRatio * $srcHeight);
  156. } else {
  157. $destWidth = ceil($yRatio * $srcWidth);
  158. $destHeight = $maxHeight;
  159. }
  160. return array ($destWidth, $destHeight);
  161. }
  162. function addLogo($thumbWidth, $thumbHeight, &$thumbImg)
  163. {
  164. extract($this->logo);
  165. $logoImage = $this->loadImage($file, $logoWidth, $logoHeight);
  166. if ($vertPos == TI_POS_CENTER) {
  167. $yPos = ceil($thumbHeight / 2 - $logoHeight / 2 );
  168. } elseif ($vertPos == TI_POS_BOTTOM) {
  169. $yPos = $thumbHeight - $logoHeight;
  170. } else {
  171. $yPos = 0;
  172. }
  173. if ($horzPos == TI_POS_CENTER) {
  174. $xPos = ceil($thumbWidth / 2 - $logoWidth / 2);
  175. } elseif ($horzPos == TI_POS_RIGHT) {
  176. $xPos = $thumbWidth - $logoWidth;
  177. } else {
  178. $xPos = 0;
  179. }
  180. if (!imagecopy($thumbImg, $logoImage, $xPos, $yPos, 0, 0, $logoWidth, $logoHeight)) {
  181. trigger_error('Cannot copy the logo image', E_USER_ERROR);
  182. }
  183. }
  184. function addLabel($thumbWidth, $thumbHeight, &$thumbImg)
  185. {
  186. extract($this->label);
  187. list($r, $g, $b) = $this->parseColor($color);
  188. $colorId = imagecolorallocate($thumbImg, $r, $g, $b);
  189. $textBox = imagettfbbox($size, $angle, $font, $text);
  190. $textWidth = $textBox[2] - $textBox[0];
  191. $textHeight = abs($textBox[1] - $textBox[7]);
  192. if ($vertPos == TI_POS_TOP) {
  193. $yPos = 5 + $textHeight;
  194. } elseif ($vertPos == TI_POS_CENTER) {
  195. $yPos = ceil($thumbHeight / 2 - $textHeight / 2);
  196. } elseif ($vertPos == TI_POS_BOTTOM) {
  197. $yPos = $thumbHeight - $textHeight;
  198. }
  199. if ($horzPos == TI_POS_LEFT) {
  200. $xPos = 5;
  201. } elseif ($horzPos == TI_POS_CENTER) {
  202. $xPos = ceil($thumbWidth / 2 - $textWidth / 2);
  203. } elseif ($horzPos == TI_POS_RIGHT) {
  204. $xPos = $thumbWidth - $textWidth - 5;
  205. }
  206. imagettftext($thumbImg, $size, $angle, $xPos, $yPos, $colorId, $font, $text);
  207. }
  208. function outputThumbImage($destImage)
  209. {
  210. imageinterlace($destImage, $this->interlace);
  211. header('Content-type: ' . $this->destType);
  212. if ($this->destType == TI_JPEG) {
  213. imagejpeg($destImage, '', $this->jpegQuality);
  214. } elseif ($this->destType == TI_GIF) {
  215. imagegif($destImage);
  216. } elseif ($this->destType == TI_PNG) {
  217. imagepng($destImage);
  218. }
  219. }
  220. function saveThumbImage($imageFile, $destImage)
  221. {
  222. imageinterlace($destImage, $this->interlace);
  223. if ($this->destType == TI_JPEG) {
  224. imagejpeg($destImage, $this->destFile, $this->jpegQuality);
  225. } elseif ($this->destType == TI_GIF) {
  226. imagegif($destImage, $this->destFile);
  227. } elseif ($this->destType == TI_PNG) {
  228. imagepng($destImage, $this->destFile);
  229. }
  230. }
  231. function output()
  232. {
  233. $srcImage = $this->loadImage($this->srcFile, $srcWidth, $srcHeight);
  234. $destSize = $this->getThumbSize($srcWidth, $srcHeight);
  235. $destWidth = $destSize[0];
  236. $destHeight = $destSize[1];
  237. $destImage = imagecreatetruecolor($destWidth, $destHeight);
  238. if (!$destImage) {
  239. trigger_error('Cannot create final image', E_USER_ERROR);
  240. }
  241. imagecopyresampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
  242. if ($this->logo['file'] != TI_NO_LOGO) {
  243. $this->addLogo($destWidth, $destHeight, $destImage);
  244. }
  245. if ($this->label['text'] != TI_NO_LABEL) {
  246. $this->addLabel($destWidth, $destHeight, $destImage);
  247. }
  248. if ($this->destFile == TI_STDOUT) {
  249. $this->outputThumbImage($destImage);
  250. } elseif ($this->destFile == TI_RESOURCE) {
  251. imagedestroy($srcImage);
  252. return $destImage;
  253. } else {
  254. $this->saveThumbImage($this->destFile, $destImage);
  255. }
  256. imagedestroy($srcImage);
  257. imagedestroy($destImage);
  258. }
  259. }
  260. class ImageBatchTransformation
  261. {
  262. var $source = '';
  263. var $destination = '';
  264. var $format = TI_JPEG;
  265. var $jpegQuality = -1;
  266. var $interlace = TI_INTERLACE_OFF;
  267. var $maxWidth = 800;
  268. var $maxHeight = 600;
  269. var $fitToMax = false;
  270. var $logo = array();
  271. var $label = array();
  272. var $rotateAngle = 0;
  273. var $rotateBgColor = '#ffffff';
  274. var $replaceExisted = true;
  275. function ImageBatchTransformation()
  276. {
  277. $this->logo['file'] = TI_NO_LOGO;
  278. $this->logo['vertPos'] = TI_POS_TOP;
  279. $this->logo['horzPos'] = TI_POS_LEFT;
  280. $this->label['text'] = TI_NO_LABEL;
  281. $this->label['vertPos'] = TI_POS_BOTTOM;
  282. $this->label['horzPos'] = TI_POS_RIGHT;
  283. $this->label['font'] = '';
  284. $this->label['size'] = 20;
  285. $this->label['color'] = '#000000';
  286. $this->label['angle'] = 0;
  287. }
  288. }
  289. class ImageBatchProcessor
  290. {
  291. var $thumbnail = null;
  292. var $extensions = array(TI_JPEG => '.jpg', TI_GIF => '.gif', TI_PNG => '.png');
  293. function ImageBatchProcessor()
  294. {
  295. $this->transform = new ImageBatchTransformation();
  296. $this->thumbnail = new ThumbnailImage();
  297. }
  298. function applyTransformation($transformObj, &$thumbnailObj)
  299. {
  300. $thumbnailObj->srcFile = $transformObj->source;
  301. $thumbnailObj->destFile = $transformObj->destination;
  302. $thumbnailObj->destType = $transformObj->format;
  303. $thumbnailObj->interlace = $transformObj->interlace;
  304. $thumbnailObj->jpegQuality = $transformObj->jpegQuality;
  305. $thumbnailObj->maxWidth = $transformObj->maxWidth;
  306. $thumbnailObj->maxHeight = $transformObj->maxHeight;
  307. $thumbnailObj->fitToMax = $transformObj->fitToMax;
  308. $thumbnailObj->logo = $transformObj->logo;
  309. $thumbnailObj->label = $transformObj->label;
  310. $thumbnailObj->rotateAngle = $transformObj->rotateAngle;
  311. $thumbnailObj->rotateBgColor = $transformObj->rotateBgColor;
  312. }
  313. function normalizePath($path)
  314. {
  315. $path = str_replace('\\', '/', trim($path));
  316. if (!empty($path) && substr($path, -1) != '/') {
  317. $path .= '/';
  318. }
  319. return $path;
  320. }
  321. function process($transformObj, $filter = IBP_IMAGE_REGEXP, $count = 0)
  322. {
  323. $srcDir = $this->normalizePath($transformObj->source);
  324. $destDir = $this->normalizePath($transformObj->destination);
  325. $this->applyTransformation($transformObj, $this->thumbnail);
  326. if (!($dir = opendir($srcDir))) {
  327. return false;
  328. }
  329. $i = 0;
  330. while (false !== ($f = readdir($dir))) {
  331. if ($f == '.' || $f == '..' || !preg_match($filter, $f)) {
  332. continue;
  333. }
  334. $ext = substr($f, strrpos($f, '.'));
  335. if ($count <= 0 || $i < $count) {
  336. $this->thumbnail->srcFile = $srcDir . $f;
  337. $this->thumbnail->destFile = $destDir . basename($f, $ext) . $this->extensions[$transformObj->format];
  338. if ($transformObj->replaceExisted || !file_exists($this->thumbnail->destFile)) {
  339. $this->thumbnail->output();
  340. $i++;
  341. }
  342. }
  343. }
  344. closedir($dir);
  345. return $i;
  346. }
  347. function processEx($transformArray)
  348. {
  349. foreach ($transformArray as $i => $transformObj) {
  350. $this->applyTransformation($transformObj, $this->thumbnail);
  351. if ($transformObj->replaceExisted || !file_exists($transformObj->destination)) {
  352. $this->thumbnail->output();
  353. }
  354. }
  355. return $i + 1;
  356. }
  357. function dirWalk($path, $callback, $filter = IBP_ALL_REGEXP)
  358. {
  359. $path = $this->normalizePath($path);
  360. $files = array();
  361. if (!($dir = opendir($path))) {
  362. return false;
  363. }
  364. while (false !== ($f = readdir($dir))) {
  365. if ($f == '.' || $f == '..' || !preg_match($filter, $f)) {
  366. continue;
  367. }
  368. $ext = substr($f, strrpos($f, '.'));
  369. $files[] = array(basename($f, $ext), $ext);
  370. }
  371. closedir($dir);
  372. $numFiles = sizeof($files);
  373. $l = strlen(strval($numFiles));
  374. foreach ($files as $i => $file) {
  375. $oldName = $file[0] . $file[1];
  376. $padded = str_pad(strval($i + 1), $l, '0', STR_PAD_LEFT);
  377. $newName = $callback($path, $i, $padded, $oldName, $file[0], $file[1]);
  378. }
  379. return $numFiles;
  380. }
  381. }
  382. //
  383. // +-----------------------------------+
  384. // | Image Filter v 1.0 |
  385. // | http://www.SysTurn.com |
  386. // +-----------------------------------+
  387. //
  388. //
  389. // This program is free software; you can redistribute it and/or modify
  390. // it under the terms of the ISLAMIC RULES and GNU Lesser General Public
  391. // License either version 2, or (at your option) any later version.
  392. //
  393. // ISLAMIC RULES should be followed and respected if they differ
  394. // than terms of the GNU LESSER GENERAL PUBLIC LICENSE
  395. //
  396. // This program is distributed in the hope that it will be useful,
  397. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  398. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  399. // GNU General Public License for more details.
  400. //
  401. // You should have received a copy of the license with this software;
  402. // If not, please contact support @ S y s T u r n .com to receive a copy.
  403. //
  404. class ImageFilter
  405. { #R G B
  406. var $colorA = 7944996; #79 3B 24
  407. var $colorB = 16696767; #FE C5 BF
  408. var $arA = array();
  409. var $arB = array();
  410. function ImageFilter()
  411. {
  412. $this->arA['R'] = ($this->colorA >> 16) & 0xFF;
  413. $this->arA['G'] = ($this->colorA >> 8) & 0xFF;
  414. $this->arA['B'] = $this->colorA & 0xFF;
  415. $this->arB['R'] = ($this->colorB >> 16) & 0xFF;
  416. $this->arB['G'] = ($this->colorB >> 8) & 0xFF;
  417. $this->arB['B'] = $this->colorB & 0xFF;
  418. }
  419. function GetScore($image)
  420. {
  421. $x = 0; $y = 0;
  422. $img = $this->_GetImageResource($image, $x, $y);
  423. if(!$img) return false;
  424. $score = 0;
  425. $xPoints = array($x/8, $x/4, ($x/8 + $x/4), $x-($x/8 + $x/4), $x-($x/4), $x-($x/8));
  426. $yPoints = array($y/8, $y/4, ($y/8 + $y/4), $y-($y/8 + $y/4), $y-($y/8), $y-($y/8));
  427. $zPoints = array($xPoints[2], $yPoints[1], $xPoints[3], $y);
  428. for($i=1; $i<=$x; $i++)
  429. {
  430. for($j=1; $j<=$y; $j++)
  431. {
  432. $color = imagecolorat($img, $i, $j);
  433. if($color >= $this->colorA && $color <= $this->colorB)
  434. {
  435. $color = array('R'=> ($color >> 16) & 0xFF, 'G'=> ($color >> 8) & 0xFF, 'B'=> $color & 0xFF);
  436. if($color['G'] >= $this->arA['G'] && $color['G'] <= $this->arB['G'] && $color['B'] >= $this->arA['B'] && $color['B'] <= $this->arB['B'])
  437. {
  438. if($i >= $zPoints[0] && $j >= $zPoints[1] && $i <= $zPoints[2] && $j <= $zPoints[3])
  439. {
  440. $score += 3;
  441. }
  442. elseif($i <= $xPoints[0] || $i >=$xPoints[5] || $j <= $yPoints[0] || $j >= $yPoints[5])
  443. {
  444. $score += 0.10;
  445. }
  446. elseif($i <= $xPoints[0] || $i >=$xPoints[4] || $j <= $yPoints[0] || $j >= $yPoints[4])
  447. {
  448. $score += 0.40;
  449. }
  450. else
  451. {
  452. $score += 1.50;
  453. }
  454. }
  455. }
  456. }
  457. }
  458. imagedestroy($img);
  459. $score = sprintf('%01.2f', ($score * 100) / ($x * $y));
  460. if($score > 100) $score = 100;
  461. return $score;
  462. }
  463. function GetScoreAndFill($image, $outputImage)
  464. {
  465. $x = 0; $y = 0;
  466. $img = $this->_GetImageResource($image, $x, $y);
  467. if(!$img) return false;
  468. $score = 0;
  469. $xPoints = array($x/8, $x/4, ($x/8 + $x/4), $x-($x/8 + $x/4), $x-($x/4), $x-($x/8));
  470. $yPoints = array($y/8, $y/4, ($y/8 + $y/4), $y-($y/8 + $y/4), $y-($y/8), $y-($y/8));
  471. $zPoints = array($xPoints[2], $yPoints[1], $xPoints[3], $y);
  472. for($i=1; $i<=$x; $i++)
  473. {
  474. for($j=1; $j<=$y; $j++)
  475. {
  476. $color = imagecolorat($img, $i, $j);
  477. if($color >= $this->colorA && $color <= $this->colorB)
  478. {
  479. $color = array('R'=> ($color >> 16) & 0xFF, 'G'=> ($color >> 8) & 0xFF, 'B'=> $color & 0xFF);
  480. if($color['G'] >= $this->arA['G'] && $color['G'] <= $this->arB['G'] && $color['B'] >= $this->arA['B'] && $color['B'] <= $this->arB['B'])
  481. {
  482. if($i >= $zPoints[0] && $j >= $zPoints[1] && $i <= $zPoints[2] && $j <= $zPoints[3])
  483. {
  484. $score += 3;
  485. imagefill($img, $i, $j, 16711680);
  486. }
  487. elseif($i <= $xPoints[0] || $i >=$xPoints[5] || $j <= $yPoints[0] || $j >= $yPoints[5])
  488. {
  489. $score += 0.10;
  490. imagefill($img, $i, $j, 14540253);
  491. }
  492. elseif($i <= $xPoints[0] || $i >=$xPoints[4] || $j <= $yPoints[0] || $j >= $yPoints[4])
  493. {
  494. $score += 0.40;
  495. imagefill($img, $i, $j, 16514887);
  496. }
  497. else
  498. {
  499. $score += 1.50;
  500. imagefill($img, $i, $j, 512);
  501. }
  502. }
  503. }
  504. }
  505. }
  506. imagejpeg($img, $outputImage);
  507. imagedestroy($img);
  508. $score = sprintf('%01.2f', ($score * 100) / ($x * $y));
  509. if($score > 100) $score = 100;
  510. return $score;
  511. }
  512. function _GetImageResource($image, &$x, &$y)
  513. {
  514. $info = GetImageSize($image);
  515. $x = $info[0];
  516. $y = $info[1];
  517. switch( $info[2] )
  518. {
  519. case IMAGETYPE_GIF:
  520. return @ImageCreateFromGif($image);
  521. case IMAGETYPE_JPEG:
  522. return @ImageCreateFromJpeg($image);
  523. case IMAGETYPE_PNG:
  524. return @ImageCreateFromPng($image);
  525. default:
  526. return false;
  527. }
  528. }
  529. }