PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Molinos/Image/Editor.php

https://code.google.com/p/molinos-cms/
PHP | 242 lines | 164 code | 46 blank | 32 comment | 38 complexity | aa652a1762d3ad0bc0381ed8b4005060 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * ??? ??? ????????? ???????? ?? ?????????.
  4. *
  5. * @todo ???????? ?? ????? ImageAPI.
  6. *
  7. * @package Molinos_CMS
  8. * @subpackage Image
  9. * @author Justin Forest <justin.forest@gmail.com>
  10. * @copyright 2006-2011 molinos.ru
  11. * @license http://www.gnu.org/copyleft/gpl.html GPL
  12. */
  13. class Molinos_Image_Editor
  14. {
  15. private $folder;
  16. private $filename;
  17. private $source;
  18. private $output;
  19. private $nw;
  20. private $nh;
  21. public static function hookRemoteCall(Molinos_Core_Context $ctx)
  22. {
  23. $img = new Molinos_Image_Editor($ctx);
  24. $img->sendFile();
  25. exit();
  26. }
  27. // ????? ??????????, ??????? ???????????? ??? ?????????????? ???????????,
  28. // ??????????? - ? ????????????
  29. private $options = array(
  30. 'fid' => null,
  31. 'scale' => 100,
  32. 'mirrorV' => false,
  33. 'mirrorH' => false,
  34. 'angle' => 0,
  35. 'offsetX' => 0,
  36. 'offsetY' => 0,
  37. 'cropLeft' => 0,
  38. 'cropTop' => 0,
  39. 'cropRight' => 0,
  40. 'cropBottom' => 0,
  41. 'merge' => null,
  42. 'noshow' => false,
  43. );
  44. private $node = null;
  45. private $mergeNode = null;
  46. public function __construct(Molinos_Core_Context $ctx)
  47. {
  48. $nodeapi = Molinos_Core_API::getInstance('node');
  49. // ???? ????? id ?????????? ?????? ?? ??????, ????????
  50. if (null == $ctx->request->get('fid', null) or null == $ctx->request->get('scale', null))
  51. $this->sendError(500, 'usage: ?q=imgtoolkit.rpc&fid=attachment[&operation=parameter...]');
  52. foreach ($this->options as $k => $v) {
  53. if ($p = $ctx->request->get($k)) {
  54. if (in_array($k, array('noshow', 'merge', 'fid', 'mirrorH', 'mirrorV')))
  55. $this->options[$k] = $p;
  56. else
  57. $this->options[$k] = floatval($p);
  58. }
  59. // ????????? ??? ?????-?????? ??? ????
  60. $outfile .= "{$this->options[$k]},";
  61. }
  62. $outfile = trim($outfile, ',');
  63. $node = $nodeapi->load(array('class' => 'file', 'id' => $this->options['fid']));
  64. if (empty($node))
  65. self::sendError(404, 'attachment not found.');
  66. $this->node = $node;
  67. $this->filename = $node->filename;
  68. $this->folder = dirname($node->uri);
  69. $this->sourceDir = dirname($node->uri);
  70. $this->source = $node->uri;
  71. $this->output = $this->folder . '/' . $outfile;
  72. if (null != $this->options['merge']) {
  73. $this->mergeNode = $nodeapi->load(array('class' => 'file', 'id' => $this->options['merge']));
  74. if (empty($this->mergeNode))
  75. self::sendError(404, 'merge attachment not found.');
  76. }
  77. }
  78. private function sendError($code, $more = null)
  79. {
  80. $codes = array(
  81. '200' => 'OK',
  82. '400' => 'Bad Request',
  83. '404' => 'Not Found',
  84. '415' => 'Bad Media Type',
  85. '500' => 'Internal Server Error',
  86. );
  87. if (!isset($codes[$code]))
  88. $code = 500;
  89. $text = $codes[$code];
  90. header("HTTP/1.1 {$code} {$text}");
  91. header("Content-Type: text/plain; charset=utf-8");
  92. print $text;
  93. if ($more !== null)
  94. print ": ".$more;
  95. exit();
  96. }
  97. public function sendFile()
  98. {
  99. if (!is_file($this->source) or !is_readable($this->source))
  100. $this->sendError(404, 'could not find this attachment.');
  101. // ???????? ??????? ???? ?? ??????. ????????? ?????? ???? ???? ???????? ?????????.
  102. $img = Molinos_Image_Scaler::getInstance();
  103. $rc = $img->open($this->source, $this->node->filetype);
  104. // ???? ?? ??????? ???????, ?????? ???? ?? ???????? ?????????. ?????? ??? ? ?????? ??????????.
  105. if ($rc === false)
  106. return $this->sendFileDownload($img);
  107. if (!is_file($this->output) or filemtime($this->source) > filemtime($this->output)) {
  108. // ???? ???? ?????????? -- ??????????? ??? ???????, ????? ????
  109. // ???? ???????? ????????, ??????????? ???????????? ??????? (??
  110. // ??????? ?????? ????????? ??????????, ??? ?? ?????? -- ?? ?????,
  111. // ?????? ??????).
  112. // ???????????? ????????, ???? ??? ?????.
  113. if ($this->options !== null)
  114. $this->processImage($img);
  115. if (is_link($this->output) and !unlink($this->output))
  116. $this->sendError(500, 'could not remove the file from cache. Overwriting that file would cause the original data to be lost.');
  117. }
  118. // ?????? ????????, ????? ???????? ?? ????? ???????? ? ???????,
  119. // ????? ?? ?????????? ??????? ??????? ???????? ?????????, ? ?? ? ?????????.
  120. if (false == $this->options['noshow']) {
  121. // ????????? ???? ?? ??????.
  122. $f = fopen($this->output, 'r')
  123. or $this->sendError(500, "could not read from cache.");
  124. // ?????????? ???? ???????.
  125. header('Content-Type: '.$img->getType());
  126. header('Content-Length: '.filesize($this->output));
  127. fpassthru($f);
  128. } else {
  129. exit();
  130. }
  131. }
  132. private function processImage($img)
  133. {
  134. try {
  135. $origSize = $img->getImageSize();
  136. // ???????????????
  137. $nw = intval($origSize[0] * $this->options['scale'] / 100);
  138. $nh = intval($origSize[1] * $this->options['scale'] / 100);
  139. if (!$img->scale($nw, $nh))
  140. $this->sendError(500, "could not resize the image");
  141. // ?????????????? ?? ?????????
  142. if (true == $this->options['mirrorV'])
  143. $img->mirror('v');
  144. // ?????????????? ?? ???????????
  145. if (true == $this->options['mirrorH'])
  146. $img->mirror('h');
  147. // ??????? ?? ???????? ????
  148. $angle = $this->options['angle'];
  149. if (is_numeric($angle) && ($angle != 360 or $angle != 0))
  150. $img->rotate(-($angle));
  151. // ???????? ???????
  152. $offsetX = $this->options['offsetX'];
  153. $offsetY = $this->options['offsetY'];
  154. if (is_numeric($offsetX) && is_numeric($offsetY)) {
  155. $img->moveTo($offsetX, $offsetY);
  156. }
  157. // ???????????? ?? ???????? ?????????
  158. $size = $img->getImageSize();
  159. $dX = $this->options['cropLeft'];
  160. $dY = $this->options['cropTop'];
  161. $dW = $this->options['cropRight'];
  162. $dH = $this->options['cropBottom'];
  163. $nW = $size[0] - $dW - $dX;
  164. $nH = $size[1] - $dH - $dY;
  165. if (!$img->crop($dX, $dY, $nW, $nH))
  166. $this->sendError(500, "could not crop the image");
  167. if (null != $this->mergeNode) {
  168. if (!$img->watermark($this->mergeNode->uri))
  169. $this->sendError(500, "could not merge the image");
  170. }
  171. if (!is_dir($this->folder) and !mkdir($this->folder))
  172. $this->sendError(500, "could not create the cache directory: ".$this->folder);
  173. if (!is_writable($this->folder))
  174. $this->sendError(500, "could not cache the image.");
  175. if (!$img->save($this->output))
  176. $this->sendError(500, "could not write the resized image");
  177. } catch (Exception $e) {
  178. $this->sendError(500, $e->getMessage());
  179. }
  180. }
  181. private function sendFileDownload($img)
  182. {
  183. ini_set('zlib.output_compression', 0);
  184. $headers = array();
  185. $headers[] = "Content-Type: ". $this->node->filetype;
  186. $headers[] = "Content-Length: ". $this->node->filesize;
  187. $download = (strstr($this->node->filetype, 'shockwave') === false);
  188. if ($download)
  189. $headers[] = "Content-Disposition: attachment; filename=\"{$this->node->filename}\"";
  190. foreach ($headers as $item)
  191. header($item);
  192. $f = fopen($this->source, 'rb')
  193. or $this->sendError(403, "could not read the file");
  194. fpassthru($f);
  195. }
  196. }