PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/app/lib/core/Parsers/TilepicParser.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 1782 lines | 1610 code | 75 blank | 97 comment | 117 complexity | 0dd9ba517fa9420dab22e6846daf72e3 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0

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

  1. <?php
  2. /** ---------------------------------------------------------------------
  3. * app/lib/core/Parsers/TilepicParser.php :
  4. * ----------------------------------------------------------------------
  5. * CollectiveAccess
  6. * Open-source collections management software
  7. * ----------------------------------------------------------------------
  8. *
  9. * Software by Whirl-i-Gig (http://www.whirl-i-gig.com)
  10. * Copyright 2004-2011 Whirl-i-Gig
  11. *
  12. * For more information visit http://www.CollectiveAccess.org
  13. *
  14. * This program is free software; you may redistribute it and/or modify it under
  15. * the terms of the provided license as published by Whirl-i-Gig
  16. *
  17. * CollectiveAccess is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTIES whatsoever, including any implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  20. *
  21. * This source code is free and modifiable under the terms of
  22. * GNU General Public License. (http://www.gnu.org/copyleft/gpl.html). See
  23. * the "license.txt" file for details, or visit the CollectiveAccess web site at
  24. * http://www.CollectiveAccess.org
  25. *
  26. * @package CollectiveAccess
  27. * @subpackage Parsers
  28. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License version 3
  29. *
  30. * ----------------------------------------------------------------------
  31. */
  32. /**
  33. *
  34. */
  35. require_once(__CA_LIB_DIR__."/core/Utils/Timer.php");
  36. include_once(__CA_LIB_DIR__."/core/Configuration.php");
  37. include_once(__CA_APP_DIR__."/helpers/mediaPluginHelpers.php");
  38. define("LIBRARY_GD", 0);
  39. define("LIBRARY_IMAGEMAGICK",2);
  40. define("LIBRARY_IMAGICK",3);
  41. define("LIBRARY_COREIMAGE",4);
  42. class TilepicParser {
  43. var $error = "";
  44. var $properties = array();
  45. var $fh = "";
  46. #
  47. # Supported tile types
  48. #
  49. var $mimetype2magick = array(
  50. "image/gif" => "GIF",
  51. "image/jpeg" => "JPEG",
  52. "image/png" => "PNG",
  53. "image/tiff" => "TIFF"
  54. );
  55. var $mimetype2ext = array(
  56. "image/gif" => "gif",
  57. "image/jpeg" => "jpg",
  58. "image/png" => "png",
  59. "image/tiff" => "tiff"
  60. );
  61. var $magick_names = array(
  62. "image/jpeg" => "JPEG",
  63. "image/gif" => "GIF",
  64. "image/tiff" => "TIFF",
  65. "image/png" => "PNG",
  66. "image/x-bmp" => "BMP",
  67. "image/x-psd" => "PDF",
  68. "image/tilepic" => "TPC",
  69. "image/x-dcraw" => "cRAW"
  70. );
  71. var $apple_type_names = array(
  72. "image/jpeg" => "jpeg",
  73. "image/gif" => "gif",
  74. "image/tiff" => "tiff",
  75. "image/png" => "png",
  76. "image/x-bmp" => "bmp",
  77. "image/x-psd" => "psd",
  78. "image/tilepic" => "tpc",
  79. "image/jp2" => "jp2"
  80. );
  81. var $apple_UTIs = array(
  82. "image/jpeg" => "public.jpeg",
  83. "image/gif" => "com.compuserve.gif",
  84. "image/tiff" => "public.tiff",
  85. "image/png" => "public.png",
  86. "image/x-bmp" => "com.microsoft.bmp",
  87. "image/x-psd" => "com.adobe.photoshop.image",
  88. "image/tilepic" => "public.tpc",
  89. "image/jp2" => "public.jpeg-2000"
  90. );
  91. var $debug = false;
  92. var $backend;
  93. var $opo_config;
  94. var $opo_external_app_config;
  95. var $ops_imagemagick_path;
  96. var $ops_CoreImage_path;
  97. var $opa_CoreImage_pipeline;
  98. # ------------------------------------------------------------------------------------
  99. function TilepicParser($filename="") {
  100. $this->opo_config = Configuration::load();
  101. $vs_external_app_config_path = $this->opo_config->get('external_applications');
  102. $this->opo_external_app_config = Configuration::load($vs_external_app_config_path);
  103. $this->ops_imagemagick_path = $this->opo_external_app_config->get('imagemagick_path');
  104. $this->ops_CoreImage_path = $this->opo_external_app_config->get('coreimagetool_app');
  105. $this->opa_CoreImage_pipeline = array();
  106. if (caMediaPluginCoreImageInstalled($this->ops_CoreImage_path)) {
  107. $this->backend = LIBRARY_COREIMAGE;
  108. } else {
  109. if (caMediaPluginImagickInstalled()) {
  110. $this->backend = LIBRARY_IMAGICK;
  111. } else {
  112. if (caMediaPluginImageMagickInstalled($this->ops_imagemagick_path)) {
  113. $this->backend = LIBRARY_IMAGEMAGICK;
  114. } else {
  115. if (caMediaPluginGDInstalled()) {
  116. $this->backend = LIBRARY_GD;
  117. } else {
  118. return null;
  119. }
  120. }
  121. }
  122. }
  123. if ($filename) { $this->load($filename); }
  124. }
  125. # ------------------------------------------------------------------------------------
  126. function init () {
  127. $this->error = "";
  128. $this->properties = array();
  129. if ($this->fh) { fclose($this->fh); }
  130. $this->fh = "";
  131. return 1;
  132. }
  133. # ------------------------------------------------------------------------------------
  134. function useLibrary($vn_backend) {
  135. switch($vn_backend) {
  136. case LIBRARY_GD:
  137. $this->backend = LIBRARY_GD;
  138. break;
  139. case LIBRARY_IMAGICK:
  140. $this->backend = LIBRARY_IMAGICK;
  141. break;
  142. case LIBRARY_COREIMAGE:
  143. $this->backend = LIBRARY_COREIMAGE;
  144. break;
  145. default:
  146. $this->backend = LIBRARY_IMAGEMAGICK;
  147. break;
  148. }
  149. }
  150. # ------------------------------------------------------------------------------------
  151. #
  152. # Format check
  153. #
  154. # ------------------------------------------------------------------------------------
  155. function isTilepic($ps_filepath) {
  156. if ($fh = @fopen($ps_filepath,'r')) {
  157. // --------
  158. // -- Read header
  159. // --------
  160. $header = fread ($fh, 4);
  161. fclose($fh);
  162. if (preg_match("/TPC\n/", $header)) {
  163. # the first four characters of a Tilepic file are TPN\n
  164. return "image/tilepic";
  165. } else {
  166. return "";
  167. }
  168. } else {
  169. # file format is not supported by this plug-in
  170. return "";
  171. }
  172. }
  173. # ------------------------------------------------------------------------------------
  174. #
  175. # Tilepic loader (must call this before accessing file)
  176. #
  177. # ------------------------------------------------------------------------------------
  178. function load ($ps_filepath) {
  179. $this->init();
  180. if (is_array($ps_filepath)) {
  181. $this->properties = $ps_filepath;
  182. return 1;
  183. }
  184. //$t= new Timer();
  185. if ($this->fh = $fh = @fopen($ps_filepath,'r')) {
  186. # look for signature
  187. $sig = fread ($fh, 4);
  188. if (preg_match("/TPC\n/", $sig)) {
  189. $buf = fread($fh, 4);
  190. $x = unpack("Nheader_size", $buf);
  191. if ($x['header_size'] <= 8) {
  192. $this->error = "Tilepic header length is invalid";
  193. return false;
  194. }
  195. $this->properties['filepath'] = $ps_filepath;
  196. $this->properties['header_size'] = $x['header_size'];
  197. $header = fread($fh, $x['header_size'] - 8);
  198. $header_values = unpack("Nwidth/Nheight/Ntile_width/Ntile_height/Ntiles/nlayers/nratio/Nattributes_size/Nattributes", $header);
  199. # --- Check header values
  200. if (($header_values["width"] < 1) || ($header_values["height"] < 1) || ($header_values["tile_width"] < 1) || ($header_values["tile_height"] < 1) ||
  201. ($header_values["tiles"] < 1) || ($header_values["layers"] < 1)) {
  202. $this->error = "Tilepic header is invalid";
  203. return false;
  204. }
  205. foreach (array_keys($header_values) as $k) {
  206. $this->properties[$k] = $header_values[$k];
  207. }
  208. # --- get tile offsets (start of each tile)
  209. $tile_offsets = array();
  210. for ($i=0; $i < $header_values['tiles']; $i++) {
  211. $x = unpack("Noffset", fread($fh, 4));
  212. $tile_offsets[] = $x['offset'];
  213. }
  214. $this->properties['tile_offsets'] = $tile_offsets;
  215. # --- get attribute data
  216. $buf = fread($fh, 4);
  217. $x = unpack("Nattribute_offset", $buf);
  218. $this->properties['attribute_offset'] = $attribute_offset = $x['attribute_offset'];
  219. if (fseek($fh, $attribute_offset, 0) == -1) {
  220. $this->error = "Seek error while fetch attributes";
  221. return false;
  222. }
  223. $attribute_data = fread($fh, filesize($ps_filepath) - $attribute_offset);
  224. $attribute_list = explode("\0", $attribute_data);
  225. $attributes = array();
  226. foreach ($attribute_list as $attr) {
  227. if ($attr = trim($attr)) {
  228. $x = explode("=", $attr);
  229. $attributes[$x[0]] = $x[1];
  230. if (preg_match("/^mimetype\$/i", $x[0])) {
  231. $this->properties["tile_mimetype"] = $x[1];
  232. }
  233. }
  234. }
  235. $this->properties["attributes"] = $attributes;
  236. //error_log("Tilepic load took " . $t->getTime()." seconds");
  237. return 1;
  238. } else {
  239. $this->error = "File is not Tilepic format";
  240. return false;
  241. }
  242. } else {
  243. $this->error = "Couldn't open file $ps_filepath";
  244. return false;
  245. }
  246. }
  247. # ------------------------------------------------------------------------------------
  248. function getProperties() {
  249. return $this->properties;
  250. }
  251. # ------------------------------------------------------------------------------------
  252. #
  253. # Tilepic creation methods
  254. #
  255. # ------------------------------------------------------------------------------------
  256. function encode ($ps_filepath, $ps_output_path, $pa_options) {
  257. #
  258. # Default values for options
  259. #
  260. if (($pa_options["layer_ratio"] = (isset($pa_options["layer_ratio"])) ? $pa_options["layer_ratio"] : 2) <= 0) { $pa_options["layer_ratio"] = 2; }
  261. if (($pa_options["scale_factor"] = (isset($pa_options["scale_factor"])) ? $pa_options["scale_factor"] : 1) <= 0) { $pa_options["scale_factor"] = 1; }
  262. if (($pa_options["quality"] = (isset($pa_options["quality"])) ? $pa_options["quality"] : 75) < 1) { $pa_options["quality"] = 75; }
  263. if (isset($pa_options["layers"])) {
  264. if (($pa_options["layers"] < 1) || ($pa_options["layers"] > 100)) {
  265. $pa_options["layers"] = 6;
  266. }
  267. }
  268. if (($pa_options["antialiasing"] = (isset($pa_options["antialiasing"])) ? $pa_options["antialiasing"] : 1) < 0) { $pa_options["antialiasing"] = 1; }
  269. if (isset($pa_options["tile_size"])) {
  270. $pa_options["tile_width"] = $pa_options["tile_height"] = $pa_options["tile_size"];
  271. }
  272. if (($pa_options["tile_width"] < 10) || ($pa_options["tile_height"] < 10)) {
  273. $pa_options["tile_width"] = $pa_options["tile_height"] = 256;
  274. }
  275. if (($pa_options["layers"] < 1) || ($pa_options["layers"] > 25)) {
  276. $pa_options["layers"] = 0;
  277. }
  278. if (!$pa_options["output_mimetype"]) {
  279. $pa_options["output_mimetype"] = "image/jpeg";
  280. }
  281. switch($this->backend) {
  282. case LIBRARY_GD:
  283. return $this->encode_gd($ps_filepath, $ps_output_path, $pa_options);
  284. break;
  285. case LIBRARY_IMAGICK:
  286. return $this->encode_imagick($ps_filepath, $ps_output_path, $pa_options);
  287. break;
  288. case LIBRARY_COREIMAGE:
  289. return $this->encode_coreimage($ps_filepath, $ps_output_path, $pa_options);
  290. break;
  291. default:
  292. return $this->encode_imagemagick($ps_filepath, $ps_output_path, $pa_options);
  293. break;
  294. }
  295. }
  296. # ------------------------------------------------
  297. private function _imageMagickRead($ps_filepath) {
  298. if (caMediaPluginImageMagickInstalled($this->ops_imagemagick_path)) {
  299. exec($this->ops_imagemagick_path.'/identify -format "%m;%w;%h\n" "'.$ps_filepath."\" 2> /dev/null", $va_output, $vn_return);
  300. $va_tmp = explode(';', $va_output[0]);
  301. if (sizeof($va_tmp) != 3) {
  302. return null;
  303. }
  304. return array(
  305. 'mimetype' => $this->magickToMimeType($va_tmp[0]),
  306. 'magick' => $va_tmp[0],
  307. 'width' => $va_tmp[1],
  308. 'height' => $va_tmp[2],
  309. 'ops' => array(),
  310. 'filepath' => $ps_filepath
  311. );
  312. }
  313. return null;
  314. }
  315. # ------------------------------------------------
  316. private function _imageMagickProcess($ps_source_filepath, $ps_dest_filepath, $pa_ops, $pn_quality=null) {
  317. $va_ops = array('-colorspace RGB');
  318. if (!is_null($pn_quality)) {
  319. $va_ops[] = '-quality '.intval($pn_quality);
  320. }
  321. foreach($pa_ops as $va_op) {
  322. switch($va_op['op']) {
  323. case 'size':
  324. if ($va_op['width'] < 1) { break; }
  325. if ($va_op['height'] < 1) { break; }
  326. $va_ops[] = '-resize '.$va_op['width'].'x'.$va_op['height'].' -filter Cubic';
  327. break;
  328. case 'crop':
  329. if ($va_op['width'] < 1) { break; }
  330. if ($va_op['height'] < 1) { break; }
  331. if ($va_op['x'] < 0) { break; }
  332. if ($va_op['y'] < 0) { break; }
  333. $va_ops[] = '-crop '.$va_op['width'].'x'.$va_op['height'].'+'.$va_op['x'].'+'.$va_op['y'];
  334. break;
  335. case 'rotate':
  336. if (!is_numeric($va_op['angle'])) { break; }
  337. $va_ops[] = '-rotate '.$va_op['angle'];
  338. break;
  339. case 'filter_despeckle':
  340. $va_ops[] = '-despeckle';
  341. break;
  342. case 'filter_sharpen':
  343. if ($va_op['radius'] < 0) { break; }
  344. $vs_tmp = '-sharpen '.$va_op['radius'];
  345. if (isset($va_op['sigma'])) { $vs_tmp .= 'x'.$va_op['sigma'];}
  346. $va_ops[] = $vs_tmp;
  347. break;
  348. case 'filter_median':
  349. if ($va_op['radius'] < 0) { break; }
  350. $va_ops[] = '-median '.$va_op['radius'];
  351. break;
  352. case 'filter_unsharp_mask':
  353. if ($va_op['radius'] < 0) { break; }
  354. $vs_tmp = '-unsharp '.$va_op['radius'];
  355. if (isset($va_op['sigma'])) { $vs_tmp .= 'x'.$va_op['sigma'];}
  356. if (isset($va_op['amount'])) { $vs_tmp .= '+'.$va_op['amount'];}
  357. if (isset($va_op['threshold'])) { $vs_tmp .= '+'.$va_op['threshold'];}
  358. $va_ops[] = $vs_tmp;
  359. break;
  360. case 'strip':
  361. $va_ops[] = '-strip';
  362. break;
  363. }
  364. }
  365. exec($this->ops_imagemagick_path.'/convert "'.$ps_source_filepath.'[0]" '.join(' ', $va_ops).' "'.$ps_dest_filepath.'"');
  366. return true;
  367. }
  368. # ------------------------------------------------
  369. private function _imageMagickImageFromTiles($ps_dest_filepath, $pa_tiles, $pn_tile_width, $pn_tile_height) {
  370. exec($this->ops_imagemagick_path.'/montage '.join(' ', $pa_tiles).' -mode Concatenate -tile '.$pn_tile_width.'x'.$pn_tile_height.' "'.$ps_dest_filepath.'"');
  371. return true;
  372. }
  373. # ------------------------------------------------
  374. public function magickToMimeType($ps_magick) {
  375. foreach($this->magick_names as $vs_mimetype => $vs_magick) {
  376. if ($ps_magick == $vs_magick) {
  377. return $vs_mimetype;
  378. }
  379. }
  380. return null;
  381. }
  382. # ------------------------------------------------
  383. public function appleTypeToMimeType($ps_apple_type) {
  384. foreach($this->apple_type_names as $vs_mimetype => $vs_apple_type) {
  385. if ($ps_apple_type == $vs_apple_type) {
  386. return $vs_mimetype;
  387. }
  388. }
  389. return null;
  390. }
  391. # ------------------------------------------------
  392. private function _CoreImageRead($ps_filepath) {
  393. if (caMediaPluginCoreImageInstalled($this->ops_CoreImage_path)) {
  394. $vs_output = shell_exec('sips --getProperty format --getProperty space --getProperty bitsPerSample --getProperty pixelWidth --getProperty pixelHeight --getProperty dpiWidth --getProperty dpiHeight "'.$ps_filepath."\" 2> /dev/null");
  395. $va_tmp = explode("\n", $vs_output);
  396. array_shift($va_tmp);
  397. $va_properties = array();
  398. foreach($va_tmp as $vs_line) {
  399. $va_line_tmp = explode(':', $vs_line);
  400. $va_properties[trim($va_line_tmp[0])] = trim($va_line_tmp[1]);
  401. }
  402. return array(
  403. 'mimetype' => $this->appleTypeToMimeType($va_properties['format']),
  404. 'magick' => $va_properties['format'],
  405. 'width' => $va_properties['pixelWidth'],
  406. 'height' => $va_properties['pixelHeight'],
  407. 'ops' => array(),
  408. 'filepath' => $ps_filepath
  409. );
  410. }
  411. return null;
  412. }
  413. # ------------------------------------------------
  414. private function _CoreImageProcess($ps_source_filepath, $ps_dest_filepath, $pa_ops, $pn_quality=null, $pb_pipeline=false) {
  415. foreach($pa_ops as $va_op) {
  416. switch($va_op['op']) {
  417. case 'size':
  418. if ($va_op['width'] < 1) { break; }
  419. if ($va_op['height'] < 1) { break; }
  420. $vn_scale = $va_op['width']/$va_op['orig_width'];
  421. $va_ops[] = "filter image CILanczosScaleTransform scale={$vn_scale}:aspectRatio=1";
  422. break;
  423. case 'crop':
  424. if ($va_op['width'] < 1) { break; }
  425. if ($va_op['height'] < 1) { break; }
  426. if ($va_op['x'] < 0) { break; }
  427. if ($va_op['y'] < 0) { break; }
  428. // CoreImage y-origin is at the bottom, not the top, of the image
  429. $vn_y = $va_op['orig_height'] - $va_op['y'] - $va_op['height'];
  430. if ($vn_y < 0) { $va_op['height'] += $vn_y; $vn_y = 0; }
  431. if ($va_op['height'] <= 0) { break; }
  432. $va_ops[] = "filter image CICrop rectangle=".join(",", array($va_op['x'], $vn_y, $va_op['width'], $va_op['height']));
  433. break;
  434. case 'filter_despeckle':
  435. // TODO: see if this works nicely... just using default values
  436. $va_ops[] = "filter image CINoiseReduction inputNoiseLevel=0.2:inputSharpness=0.4";
  437. break;
  438. case 'filter_median':
  439. if ($va_op['radius'] < 0) { break; }
  440. // NOTE: CoreImage Median doesn't take a radius, unlike ImageMagick's
  441. $va_ops[] = "filter image CIMedianFilter ";
  442. break;
  443. case 'filter_unsharp_mask':
  444. case 'filter_sharpen':
  445. if ($va_op['radius'] < 0) { break; }
  446. $vn_radius = $va_op['radius'];
  447. if(!($vn_intensity = $va_op['amount'])) {
  448. $vn_intensity = 1;
  449. }
  450. $va_ops[] = "filter image CIUnsharpMask radius={$vn_radius}:intensity={$vn_intensity}";
  451. break;
  452. }
  453. }
  454. if (is_array($va_ops) && sizeof($va_ops)) {
  455. $ps_mimetype = 'image/jpeg';
  456. array_unshift($va_ops, "load image \"{$ps_source_filepath}\"");
  457. array_push($va_ops, "store image \"{$ps_dest_filepath}\" ".$this->apple_UTIs[$ps_mimetype]);
  458. if ($pb_pipeline) {
  459. $this->opa_CoreImage_pipeline[] = join(" ", $va_ops);
  460. } else {
  461. exec($this->ops_CoreImage_path." ".join(" ", $va_ops), $va_output, $vn_ret);
  462. }
  463. }
  464. return true;
  465. }
  466. # ------------------------------------------------
  467. private function _CoreImageFlushPipeline() {
  468. if (sizeof($this->opa_CoreImage_pipeline)) {
  469. exec($this->ops_CoreImage_path." ".join(" ", $this->opa_CoreImage_pipeline), $va_output, $vn_ret);
  470. }
  471. $this->opa_CoreImage_pipeline = array();
  472. }
  473. # ------------------------------------------------
  474. private function _CoreImageImageFromTiles($ps_dest_filepath, $pa_tiles, $pn_tile_width, $pn_tile_height) {
  475. // TODO: implement this for _CoreImageImageFromTiles
  476. //exec($this->ops_imagemagick_path.'/montage '.join(' ', $pa_tiles).' -mode Concatenate -tile '.$pn_tile_width.'x'.$pn_tile_height.' "'.$ps_dest_filepath.'"');
  477. return true;
  478. }
  479. # ------------------------------------------------------------------------------------
  480. function encode_imagemagick ($ps_filepath, $ps_output_path, $pa_options) {
  481. if (!($vs_tilepic_tmpdir = $this->opo_config->get('tilepic_tmpdir'))) {
  482. $vs_tilepic_tmpdir = '/tmp';
  483. }
  484. if (!($magick = $this->mimetype2magick[$pa_options["output_mimetype"]])) {
  485. $this->error = "Invalid output format";
  486. return false;
  487. }
  488. #
  489. # Open image
  490. #
  491. $h = $this->_imageMagickRead($ps_filepath);
  492. if (!$h) {
  493. $this->error = "Couldn't open image $ps_filepath";
  494. return false;
  495. }
  496. $vs_filepath = $ps_filepath;
  497. $image_width = $h['width'];
  498. $image_height = $h['height'];
  499. if (($image_width < 10) || ($image_height < 10)) {
  500. $this->error = "Image is too small to be output as Tilepic; minimum dimensions are 10x10 pixels";
  501. return false;
  502. }
  503. if ($pa_options["scale_factor"] != 1) {
  504. $image_width *= $pa_options["scale_factor"];
  505. $image_height *= $pa_options["scale_factor"];
  506. $vs_tmp_basename = tempnam($vs_tilepic_tmpdir, 'tpc_');
  507. $vs_tmp_fname = $vs_tmp_basename.'.jpg';
  508. if (!($this->_imageMagickProcess($vs_filepath, $vs_tmp_fname, array(
  509. array(
  510. 'op' => 'size',
  511. 'width' => $image_width,
  512. 'height' => $image_height,
  513. )
  514. )
  515. ))) {
  516. $this->error = "Couldn't scale image";
  517. @unlink($vs_tmp_fname);
  518. return false;
  519. }
  520. $vs_filepath = $vs_tmp_fname;
  521. }
  522. #
  523. # How many layers to make?
  524. #
  525. if (!$pa_options["layers"]) {
  526. $sw = $image_width * $pa_options["layer_ratio"];
  527. $sh = $image_height * $pa_options["layer_ratio"];
  528. $pa_options["layers"] = 1;
  529. while (($sw >= $pa_options["tile_width"]) || ($sh >= $pa_options["tile_height"])) {
  530. $sw = ceil($sw / $pa_options["layer_ratio"]);
  531. $sh = ceil($sh / $pa_options["layer_ratio"]);
  532. $pa_options["layers"] ++;
  533. }
  534. }
  535. #
  536. # Cut image into tiles
  537. #
  538. $tiles = 0;
  539. $layer_list = array();
  540. $base_width = $image_width;
  541. $base_height = $image_height;
  542. if ($this->debug) { print "BASE $base_width x $base_height \n";}
  543. for($l=$pa_options["layers"]; $l >= 1; $l--) {
  544. $x = $y = 0;
  545. $wx = $pa_options["tile_width"];
  546. $wy = $pa_options["tile_height"];
  547. if ($this->debug) { print "LAYER=$l\n"; };
  548. if ($l < $pa_options["layers"]) {
  549. $image_width = ceil($image_width/$pa_options["layer_ratio"]);
  550. $image_height = ceil($image_height/$pa_options["layer_ratio"]);
  551. if ($this->debug) { print "RESIZE layer $l TO $image_width x $image_height \n";}
  552. $vs_tmp_basename = tempnam($vs_tilepic_tmpdir, 'tpc_');
  553. $vs_tmp_fname = $vs_tmp_basename.'.jpg';
  554. if (!($this->_imageMagickProcess($vs_filepath, $vs_tmp_fname, array(
  555. array(
  556. 'op' => 'size',
  557. 'width' => $image_width,
  558. 'height' => $image_height,
  559. )
  560. )
  561. ))) {
  562. $this->error = "Couldn't scale image";
  563. @unlink($vs_tmp_fname);
  564. return false;
  565. }
  566. if ($vs_filepath != $ps_filepath) { @unlink($vs_filepath); }
  567. $vs_filepath = $vs_tmp_fname;
  568. }
  569. $i = 0;
  570. $layer_list[] = array();
  571. while($y < $image_height) {
  572. $vs_tmp_basename = tempnam($vs_tilepic_tmpdir, 'tpc_');
  573. $vs_tmp_fname = $vs_tmp_basename.'.jpg';
  574. if (!($this->_imageMagickProcess($vs_filepath, $vs_tmp_fname, array(
  575. array(
  576. 'op' => 'crop',
  577. 'width' => $wx,
  578. 'height' => $wy,
  579. 'x' => $x,
  580. 'y' => $y
  581. ),
  582. array(
  583. 'op' => 'strip'
  584. )
  585. ),
  586. $pa_options["quality"]
  587. ))) {
  588. $this->error = "Couldn't scale image";
  589. return false;
  590. }
  591. $vs_tile = file_get_contents($vs_tmp_fname);
  592. @unlink($vs_tmp_fname);
  593. $layer_list[sizeof($layer_list)-1][] = $vs_tile;
  594. $x += $pa_options["tile_width"];
  595. if ($x >= $image_width) {
  596. $y += $pa_options["tile_height"];
  597. $x = 0;
  598. }
  599. $i++;
  600. $tiles++;
  601. }
  602. if ($this->debug) { print "OUTPUT $tiles TILES FOR LAYER $l : $image_width x $image_height\n";}
  603. }
  604. if ($vs_filepath != $ps_filepath) { @unlink($vs_filepath); }
  605. #
  606. # Write Tilepic format file
  607. #
  608. if ($this->debug) { print "WRITING FILE..."; }
  609. if ($fh = fopen($ps_output_path.".tpc", "w")) {
  610. # --- attribute list
  611. $attribute_list = "";
  612. $attributes = 0;
  613. if ((isset($pa_options["attributes"])) && (is_array($pa_options["attributes"]))) {
  614. $pa_options["attributes"]["mimeType"] = $pa_options["output_mimetype"];
  615. } else {
  616. $pa_options["attributes"] = array("mimeType" => $pa_options["output_mimetype"]);
  617. }
  618. foreach ($pa_options["attributes"] as $k => $v) {
  619. $attribute_list .= "$k=$v\0";
  620. $attributes++;
  621. }
  622. if ($this->debug) { print "header OK;"; }
  623. # --- header
  624. if (!fwrite($fh, "TPC\n")) {
  625. $this->error = "Could not write Tilepic signature";
  626. return false;
  627. }
  628. if (!fwrite($fh, pack("NNNNNNnnNN",40, $base_width, $base_height, $pa_options["tile_width"], $pa_options["tile_height"], $tiles, $pa_options["layers"], $pa_options["layer_ratio"], strlen($attribute_list),$attributes))) {
  629. $this->error = "Could not write Tilepic header";
  630. return false;
  631. }
  632. # --- offset table
  633. $offset = 44 + ($tiles * 4);
  634. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  635. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  636. if (!fwrite($fh, pack("N",$offset))) {
  637. $this->error = "Could not write Tilepic offset table";
  638. return false;
  639. }
  640. $offset += strlen($layer_list[$i][$j]);
  641. }
  642. }
  643. if ($this->debug) { print "offset table OK;"; }
  644. if (!fwrite($fh, pack("N", $offset))) {
  645. $this->error = "Could not finish writing Tilepic offset table";
  646. return false;
  647. }
  648. # --- tiles
  649. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  650. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  651. if (!fwrite($fh, $layer_list[$i][$j])) {
  652. $this->error = "Could not write Tilepic tile data";
  653. return false;
  654. }
  655. }
  656. }
  657. if ($this->debug) { print "tiles OK;"; }
  658. unset($layer_list);
  659. # --- attributes
  660. if (!fwrite($fh, $attribute_list)) {
  661. $this->error = "Could not write Tilepic attributes";
  662. return false;
  663. }
  664. if ($this->debug) { print "attributes OK\n"; }
  665. fclose($fh);
  666. return $pa_options;
  667. } else {
  668. $this->error = "Couldn't open output file $ps_output_path\n";
  669. return false;
  670. }
  671. }
  672. # ------------------------------------------------------------------------------------
  673. function encode_coreimage ($ps_filepath, $ps_output_path, $pa_options) {
  674. if (!($vs_tilepic_tmpdir = $this->opo_config->get('tilepic_tmpdir'))) {
  675. $vs_tilepic_tmpdir = '/tmp';
  676. }
  677. if (!($magick = $this->mimetype2magick[$pa_options["output_mimetype"]])) {
  678. $this->error = "Invalid output format";
  679. return false;
  680. }
  681. #
  682. # Open image
  683. #
  684. $h = $this->_CoreImageRead($ps_filepath);
  685. if (!$h) {
  686. $this->error = "Couldn't open image $ps_filepath";
  687. return false;
  688. }
  689. $vs_filepath = $ps_filepath;
  690. $orig_image_width = $image_width = $h['width'];
  691. $orig_image_height = $image_height = $h['height'];
  692. if (($image_width < 10) || ($image_height < 10)) {
  693. $this->error = "Image is too small to be output as Tilepic; minimum dimensions are 10x10 pixels";
  694. return false;
  695. }
  696. if ($pa_options["scale_factor"] != 1) {
  697. $image_width *= $pa_options["scale_factor"];
  698. $image_height *= $pa_options["scale_factor"];
  699. $vs_tmp_fname = tempnam($vs_tilepic_tmpdir, 'tpc_');
  700. if (!($this->_CoreImageProcess($vs_filepath, $vs_tmp_fname, array(
  701. array(
  702. 'op' => 'size',
  703. 'width' => $image_width,
  704. 'height' => $image_height,
  705. 'orig_width' => $orig_image_width,
  706. 'orig_height' => $orig_image_height
  707. )
  708. )
  709. ))) {
  710. $this->error = "Couldn't scale image";
  711. @unlink($vs_tmp_fname);
  712. return false;
  713. }
  714. $vs_filepath = $vs_tmp_fname;
  715. }
  716. #
  717. # How many layers to make?
  718. #
  719. if (!$pa_options["layers"]) {
  720. $sw = $image_width * $pa_options["layer_ratio"];
  721. $sh = $image_height * $pa_options["layer_ratio"];
  722. $pa_options["layers"] = 1;
  723. while (($sw >= $pa_options["tile_width"]) || ($sh >= $pa_options["tile_height"])) {
  724. $sw = ceil($sw / $pa_options["layer_ratio"]);
  725. $sh = ceil($sh / $pa_options["layer_ratio"]);
  726. $pa_options["layers"] ++;
  727. }
  728. }
  729. #
  730. # Cut image into tiles
  731. #
  732. $tiles = 0;
  733. $layer_list = array();
  734. $base_width = $image_width;
  735. $base_height = $image_height;
  736. if ($this->debug) { print "BASE $base_width x $base_height \n";}
  737. for($l=$pa_options["layers"]; $l >= 1; $l--) {
  738. $x = $y = 0;
  739. $wx = $pa_options["tile_width"];
  740. $wy = $pa_options["tile_height"];
  741. if ($this->debug) { print "LAYER=$l\n"; };
  742. if ($l < $pa_options["layers"]) {
  743. $orig_image_width = $image_width;
  744. $orig_image_height = $image_height;
  745. $image_width = ceil($image_width/$pa_options["layer_ratio"]);
  746. $image_height = ceil($image_height/$pa_options["layer_ratio"]);
  747. if ($this->debug) { print "RESIZE layer $l TO $image_width x $image_height \n";}
  748. $vs_tmp_fname = tempnam($vs_tilepic_tmpdir, 'tpc_layer_');
  749. if (!($this->_CoreImageProcess($vs_filepath, $vs_tmp_fname, array(
  750. array(
  751. 'op' => 'size',
  752. 'width' => $image_width,
  753. 'height' => $image_height,
  754. 'orig_width' => $orig_image_width,
  755. 'orig_height' => $orig_image_height
  756. )
  757. )
  758. ))) {
  759. $this->error = "Couldn't scale image";
  760. @unlink($vs_tmp_fname);
  761. return false;
  762. }
  763. if ($vs_filepath != $ps_filepath) { @unlink($vs_filepath); }
  764. $vs_filepath = $vs_tmp_fname;
  765. }
  766. $i = 0;
  767. // generate first row strip of image
  768. $vs_strip_name = tempnam($vs_tilepic_tmpdir, 'tpc_strip_');
  769. if (!($this->_CoreImageProcess($vs_filepath, $vs_strip_name, array(
  770. array(
  771. 'op' => 'crop',
  772. 'width' => $image_width,
  773. 'height' => $wy,
  774. 'x' => 0,
  775. 'y' => 0,
  776. 'orig_width' => $image_width,
  777. 'orig_height' => $image_height
  778. ),
  779. array(
  780. 'op' => 'strip'
  781. )
  782. ),
  783. $pa_options["quality"]
  784. ))) {
  785. $this->error = "Couldn't generate image strip";
  786. return false;
  787. }
  788. $layer_list[] = array();
  789. $tile_name_list = array();
  790. while($y < $image_height) {
  791. $vs_tmp_fname = tempnam($vs_tilepic_tmpdir, 'tpc_tile_');
  792. if (!($this->_CoreImageProcess($vs_strip_name, $vs_tmp_fname, array(
  793. array(
  794. 'op' => 'crop',
  795. 'width' => $wx,
  796. 'height' => $wy,
  797. 'x' => $x,
  798. 'y' => 0,
  799. 'orig_width' => $image_width,
  800. 'orig_height' => $wy
  801. ),
  802. array(
  803. 'op' => 'strip'
  804. )
  805. ),
  806. $pa_options["quality"], true
  807. ))) {
  808. $this->error = "Couldn't scale image";
  809. return false;
  810. }
  811. $tile_name_list[] = $vs_tmp_fname;
  812. $x += $pa_options["tile_width"];
  813. if ($x >= $image_width) {
  814. $y += $pa_options["tile_height"];
  815. $x = 0;
  816. $this->_CoreImageFlushPipeline();
  817. foreach($tile_name_list as $vs_tmp_fname) {
  818. $vs_tile = file_get_contents($vs_tmp_fname);
  819. unlink($vs_tmp_fname);
  820. $layer_list[sizeof($layer_list)-1][] = $vs_tile;
  821. $tile_name_list = array();
  822. }
  823. @unlink($vs_strip_name);
  824. // get next strip
  825. $vs_strip_name = tempnam($vs_tilepic_tmpdir, 'tpc_strip_');
  826. if (!($this->_CoreImageProcess($vs_filepath, $vs_strip_name, array(
  827. array(
  828. 'op' => 'crop',
  829. 'width' => $image_width,
  830. 'height' => $wy,
  831. 'x' => 0,
  832. 'y' => $y,
  833. 'orig_width' => $image_width,
  834. 'orig_height' => $image_height
  835. ),
  836. array(
  837. 'op' => 'strip'
  838. )
  839. ),
  840. $pa_options["quality"]
  841. ))) {
  842. $this->error = "Couldn't generate image strip";
  843. return false;
  844. }
  845. }
  846. $i++;
  847. $tiles++;
  848. }
  849. @unlink($vs_strip_name);
  850. if ($this->debug) { print "OUTPUT $tiles TILES FOR LAYER $l : $image_width x $image_height\n";}
  851. }
  852. @unlink($vs_strip_name);
  853. if ($vs_filepath != $ps_filepath) { @unlink($vs_filepath); }
  854. #
  855. # Write Tilepic format file
  856. #
  857. if ($this->debug) { print "WRITING FILE..."; }
  858. if ($fh = fopen($ps_output_path.".tpc", "w")) {
  859. # --- attribute list
  860. $attribute_list = "";
  861. $attributes = 0;
  862. if ((isset($pa_options["attributes"])) && (is_array($pa_options["attributes"]))) {
  863. $pa_options["attributes"]["mimeType"] = $pa_options["output_mimetype"];
  864. } else {
  865. $pa_options["attributes"] = array("mimeType" => $pa_options["output_mimetype"]);
  866. }
  867. foreach ($pa_options["attributes"] as $k => $v) {
  868. $attribute_list .= "$k=$v\0";
  869. $attributes++;
  870. }
  871. if ($this->debug) { print "header OK;"; }
  872. # --- header
  873. if (!fwrite($fh, "TPC\n")) {
  874. $this->error = "Could not write Tilepic signature";
  875. return false;
  876. }
  877. if (!fwrite($fh, pack("NNNNNNnnNN",40, $base_width, $base_height, $pa_options["tile_width"], $pa_options["tile_height"], $tiles, $pa_options["layers"], $pa_options["layer_ratio"], strlen($attribute_list),$attributes))) {
  878. $this->error = "Could not write Tilepic header";
  879. return false;
  880. }
  881. # --- offset table
  882. $offset = 44 + ($tiles * 4);
  883. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  884. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  885. if (!fwrite($fh, pack("N",$offset))) {
  886. $this->error = "Could not write Tilepic offset table";
  887. return false;
  888. }
  889. $offset += strlen($layer_list[$i][$j]);
  890. }
  891. }
  892. if ($this->debug) { print "offset table OK;"; }
  893. if (!fwrite($fh, pack("N", $offset))) {
  894. $this->error = "Could not finish writing Tilepic offset table";
  895. return false;
  896. }
  897. # --- tiles
  898. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  899. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  900. if (!fwrite($fh, $layer_list[$i][$j])) {
  901. $this->error = "Could not write Tilepic tile data";
  902. return false;
  903. }
  904. }
  905. }
  906. if ($this->debug) { print "tiles OK;"; }
  907. unset($layer_list);
  908. # --- attributes
  909. if (!fwrite($fh, $attribute_list)) {
  910. $this->error = "Could not write Tilepic attributes";
  911. return false;
  912. }
  913. if ($this->debug) { print "attributes OK\n"; }
  914. fclose($fh);
  915. return $pa_options;
  916. } else {
  917. $this->error = "Couldn't open output file $ps_output_path\n";
  918. return false;
  919. }
  920. }
  921. # ------------------------------------------------------------------------------------
  922. function encode_imagick ($ps_filepath, $ps_output_path, $pa_options) {
  923. if (!($magick = $this->mimetype2magick[$pa_options["output_mimetype"]])) {
  924. $this->error = "Invalid output format";
  925. return false;
  926. }
  927. #
  928. # Open image
  929. #
  930. $h = new Imagick();
  931. if (!$h->readImage($ps_filepath)) {
  932. $this->error = "Couldn't open image $ps_filepath";
  933. return false;
  934. }
  935. $h->setImageType(imagick::IMGTYPE_TRUECOLOR);
  936. if (!$h->setImageColorspace(imagick::COLORSPACE_RGB)) {
  937. $this->error = "Error during RGB colorspace transformation operation";
  938. return false;
  939. }
  940. $va_tmp = $h->getImageGeometry();
  941. $image_width = $va_tmp['width'];
  942. $image_height = $va_tmp['height'];
  943. if (($image_width < 10) || ($image_height < 10)) {
  944. $this->error = "Image is too small to be output as Tilepic; minimum dimensions are 10x10 pixels";
  945. return false;
  946. }
  947. if ($pa_options["scale_factor"] != 1) {
  948. $image_width *= $pa_options["scale_factor"];
  949. $image_height *= $pa_options["scale_factor"];
  950. if (!$h->resizeImage($image_width, $image_height, imagick::FILTER_CUBIC, $pa_options["antialiasing"])) {
  951. $this->error = "Couldn't scale image";
  952. return false;
  953. }
  954. }
  955. #
  956. # How many layers to make?
  957. #
  958. if (!$pa_options["layers"]) {
  959. $sw = $image_width * $pa_options["layer_ratio"];
  960. $sh = $image_height * $pa_options["layer_ratio"];
  961. $pa_options["layers"] = 1;
  962. while (($sw >= $pa_options["tile_width"]) || ($sh >= $pa_options["tile_height"])) {
  963. $sw = ceil($sw / $pa_options["layer_ratio"]);
  964. $sh = ceil($sh / $pa_options["layer_ratio"]);
  965. $pa_options["layers"] ++;
  966. }
  967. }
  968. #
  969. # Cut image into tiles
  970. #
  971. $tiles = 0;
  972. $layer_list = array();
  973. $base_width = $image_width;
  974. $base_height = $image_height;
  975. if ($this->debug) { print "BASE $base_width x $base_height \n";}
  976. for($l=$pa_options["layers"]; $l >= 1; $l--) {
  977. $x = $y = 0;
  978. $wx = $pa_options["tile_width"];
  979. $wy = $pa_options["tile_height"];
  980. if ($this->debug) { print "LAYER=$l\n"; };
  981. if ($l < $pa_options["layers"]) {
  982. $image_width = ceil($image_width/$pa_options["layer_ratio"]);
  983. $image_height = ceil($image_height/$pa_options["layer_ratio"]);
  984. if ($this->debug) { print "RESIZE layer $l TO $image_width x $image_height \n";}
  985. if (!$h->resizeImage( $image_width, $image_height, imagick::FILTER_CUBIC, $pa_options["antialiasing"])) {
  986. $this->error = "Couldn't scale image";
  987. return false;
  988. }
  989. }
  990. $i = 0;
  991. $layer_list[] = array();
  992. while($y < $image_height) {
  993. if (!($slice = $h->getImageRegion($wx, $wy, $x, $y))) {
  994. $this->error = "Couldn't create tile";
  995. return false;
  996. }
  997. $slice->setCompressionQuality($pa_options["quality"]);
  998. if (!$slice->setImageFormat($magick)) {
  999. $reason = WandGetExceptionType( $slice ) ;
  1000. $description = WandGetExceptionDescription( $slice ) ;
  1001. $this->error = "Tile conversion failed: $reason; $description";
  1002. return false;
  1003. }
  1004. # --- remove color profile (saves lots of space)
  1005. //$slice->removeImageProfile($slice);
  1006. $layer_list[sizeof($layer_list)-1][] = $slice->getImageBlob();
  1007. $slice->destroy();
  1008. $x += $pa_options["tile_width"];
  1009. if ($x >= $image_width) {
  1010. $y += $pa_options["tile_height"];
  1011. $x = 0;
  1012. }
  1013. $i++;
  1014. $tiles++;
  1015. }
  1016. if ($this->debug) { print "OUTPUT $tiles TILES FOR LAYER $l : $image_width x $image_height\n";}
  1017. }
  1018. $h->destroy();
  1019. #
  1020. # Write Tilepic format file
  1021. #
  1022. if ($this->debug) { print "WRITING FILE..."; }
  1023. if ($fh = fopen($ps_output_path.".tpc", "w")) {
  1024. # --- attribute list
  1025. $attribute_list = "";
  1026. $attributes = 0;
  1027. if ((isset($pa_options["attributes"])) && (is_array($pa_options["attributes"]))) {
  1028. $pa_options["attributes"]["mimeType"] = $pa_options["output_mimetype"];
  1029. } else {
  1030. $pa_options["attributes"] = array("mimeType" => $pa_options["output_mimetype"]);
  1031. }
  1032. foreach ($pa_options["attributes"] as $k => $v) {
  1033. $attribute_list .= "$k=$v\0";
  1034. $attributes++;
  1035. }
  1036. if ($this->debug) { print "header OK;"; }
  1037. # --- header
  1038. if (!fwrite($fh, "TPC\n")) {
  1039. $this->error = "Could not write Tilepic signature";
  1040. return false;
  1041. }
  1042. if (!fwrite($fh, pack("NNNNNNnnNN",40, $base_width, $base_height, $pa_options["tile_width"], $pa_options["tile_height"], $tiles, $pa_options["layers"], $pa_options["layer_ratio"], strlen($attribute_list),$attributes))) {
  1043. $this->error = "Could not write Tilepic header";
  1044. return false;
  1045. }
  1046. # --- offset table
  1047. $offset = 44 + ($tiles * 4);
  1048. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  1049. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  1050. if (!fwrite($fh, pack("N",$offset))) {
  1051. $this->error = "Could not write Tilepic offset table";
  1052. return false;
  1053. }
  1054. $offset += strlen($layer_list[$i][$j]);
  1055. }
  1056. }
  1057. if ($this->debug) { print "offset table OK;"; }
  1058. if (!fwrite($fh, pack("N", $offset))) {
  1059. $this->error = "Could not finish writing Tilepic offset table";
  1060. return false;
  1061. }
  1062. # --- tiles
  1063. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  1064. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  1065. if (!fwrite($fh, $layer_list[$i][$j])) {
  1066. $this->error = "Could not write Tilepic tile data";
  1067. return false;
  1068. }
  1069. }
  1070. }
  1071. if ($this->debug) { print "tiles OK;"; }
  1072. unset($layer_list);
  1073. # --- attributes
  1074. if (!fwrite($fh, $attribute_list)) {
  1075. $this->error = "Could not write Tilepic attributes";
  1076. return false;
  1077. }
  1078. if ($this->debug) { print "attributes OK\n"; }
  1079. fclose($fh);
  1080. return $pa_options;
  1081. } else {
  1082. $this->error = "Couldn't open output file $ps_output_path\n";
  1083. return false;
  1084. }
  1085. }
  1086. # ------------------------------------------------------------------------------------
  1087. function encode_gd ($ps_filepath, $ps_output_path, $pa_options) {
  1088. if (!($magick = $this->mimetype2magick[$pa_options["output_mimetype"]])) {
  1089. $this->error = "Invalid output format";
  1090. return false;
  1091. }
  1092. #
  1093. # Open image
  1094. #
  1095. if($va_info = getimagesize($ps_filepath)) {
  1096. switch($va_info[2]) {
  1097. case IMAGETYPE_GIF:
  1098. $r_image = imagecreatefromgif($ps_filepath);
  1099. $vs_mimetype = "image/gif";
  1100. $vs_typename = "GIF";
  1101. break;
  1102. case IMAGETYPE_JPEG:
  1103. $r_image = imagecreatefromjpeg($ps_filepath);
  1104. $vs_mimetype = "image/jpeg";
  1105. $vs_typename = "JPEG";
  1106. break;
  1107. case IMAGETYPE_PNG:
  1108. $r_image = imagecreatefrompng($ps_filepath);
  1109. $vs_mimetype = "image/png";
  1110. $vs_typename = "PNG";
  1111. break;
  1112. }
  1113. if (!$r_image) {
  1114. $this->error = "Couldn't open image $ps_filepath: open for $vs_typename failed";
  1115. return false;
  1116. }
  1117. } else {
  1118. $this->error = "Couldn't open image $ps_filepath: unsupported file type";
  1119. return false;
  1120. }
  1121. $image_width = $va_info[0];
  1122. $image_height = $va_info[1];
  1123. if (($image_width < 10) || ($image_height < 10)) {
  1124. $this->error = "Image is too small to be output as Tilepic; minimum dimensions are 10x10 pixels";
  1125. return false;
  1126. }
  1127. if ($pa_options["scale_factor"] != 1) {
  1128. $image_width *= $pa_options["scale_factor"];
  1129. $image_height *= $pa_options["scale_factor"];
  1130. $r_new_image = imagecreatetruecolor($image_width, $image_height);
  1131. $r_color = ImageColorAllocate( $r_new_image, 255, 255, 255 );
  1132. imagefilledrectangle($r_new_image, 0,0,$image_width-1, $image_height-1, $r_color);
  1133. if (imagecopyresampled($r_new_image, $r_image, 0, 0, 0, 0, $image_width, $image_height, $va_info[0], $va_info[1])) {
  1134. $this->error = "Couldn't scale image for new layer";
  1135. return false;
  1136. }
  1137. imagedestroy($r_image);
  1138. $r_image = $r_new_image;
  1139. }
  1140. #
  1141. # How many layers to make?
  1142. #
  1143. if (!$pa_options["layers"]) {
  1144. $sw = $image_width * $pa_options["layer_ratio"];
  1145. $sh = $image_height * $pa_options["layer_ratio"];
  1146. $pa_options["layers"] = 1;
  1147. while (($sw >= $pa_options["tile_width"]) || ($sh >= $pa_options["tile_height"])) {
  1148. $sw = ceil($sw / $pa_options["layer_ratio"]);
  1149. $sh = ceil($sh / $pa_options["layer_ratio"]);
  1150. $pa_options["layers"] ++;
  1151. }
  1152. }
  1153. #
  1154. # Cut image into tiles
  1155. #
  1156. $tiles = 0;
  1157. $layer_list = array();
  1158. $base_width = $image_width;
  1159. $base_height = $image_height;
  1160. for($l=$pa_options["layers"]; $l >= 1; $l--) {
  1161. $x = $y = 0;
  1162. if ($l < $pa_options["layers"]) {
  1163. $old_image_width = $image_width;
  1164. $old_image_height = $image_height;
  1165. $image_width = ceil($image_width/$pa_options["layer_ratio"]);
  1166. $image_height = ceil($image_height/$pa_options["layer_ratio"]);
  1167. $r_new_image = imagecreatetruecolor($image_width, $image_height);
  1168. $r_color = ImageColorAllocate( $r_new_image, 255, 255, 255 );
  1169. imagefilledrectangle($r_new_image, 0,0,$image_width-1, $image_height-1, $r_color);
  1170. if (!imagecopyresampled($r_new_image, $r_image, 0, 0, 0, 0, $image_width, $image_height, $old_image_width, $old_image_height)) {
  1171. $this->error = "Couldn't scale image for layer $l";
  1172. return false;
  1173. }
  1174. imagedestroy($r_image);
  1175. $r_image = $r_new_image;
  1176. }
  1177. $i = 0;
  1178. //$slices = array();
  1179. $layer_list[] = array();
  1180. while($y < $image_height) {
  1181. $wx = $pa_options["tile_width"];
  1182. $wy = $pa_options["tile_height"];
  1183. if (($image_width - $x) < $wx) { $wx = ($image_width - $x); }
  1184. if (($image_height - $y) < $wy) { $wy = ($image_height - $y); }
  1185. $r_slice = imagecreatetruecolor($wx, $wy);
  1186. $r_color = ImageColorAllocate( $r_slice, 255, 255, 255 );
  1187. imagefilledrectangle($r_slice, 0,0,$wx-1, $wy-1, $r_color);
  1188. if(!imagecopy($r_slice, $r_image,0,0,$x,$y,$wx, $wy)) {
  1189. $this->error = "Couldn't create tile in level $l";
  1190. return false;
  1191. }
  1192. ob_start();
  1193. switch($pa_options["output_mimetype"]) {
  1194. case 'image/gif':
  1195. imagegif($r_slice);
  1196. break;
  1197. case 'image/jpeg':
  1198. if ($pa_options["quality"] > 0) {
  1199. imagejpeg($r_slice, '', $pa_options["quality"]);
  1200. } else {
  1201. imagejpeg($r_slice);
  1202. }
  1203. break;
  1204. case 'image/png':
  1205. imagepng($r_slice);
  1206. break;
  1207. default:
  1208. die("Invalid output format ".$pa_options["output_mimetype"]);
  1209. }
  1210. $vs_image = ob_get_clean();
  1211. $layer_list[sizeof($layer_list)-1][] = $vs_image;
  1212. imagedestroy($r_slice);
  1213. $x += $pa_options["tile_width"];
  1214. if ($x >= $image_width) {
  1215. $y += $pa_options["tile_height"];
  1216. $x = 0;
  1217. }
  1218. $i++;
  1219. $tiles++;
  1220. }
  1221. }
  1222. imagedestroy($r_image);
  1223. #
  1224. # Write Tilepic format file
  1225. #
  1226. if ($fh = fopen($ps_output_path.".tpc", "w")) {
  1227. # --- attribute list
  1228. $attribute_list = "";
  1229. $attributes = 0;
  1230. if ((isset($pa_options["attributes"])) && (is_array($pa_options["attributes"]))) {
  1231. $pa_options["attributes"]["mimeType"] = $pa_options["output_mimetype"];
  1232. } else {
  1233. $pa_options["attributes"] = array("mimeType" => $pa_options["output_mimetype"]);
  1234. }
  1235. foreach ($pa_options["attributes"] as $k => $v) {
  1236. $attribute_list .= "$k=$v\0";
  1237. $attributes++;
  1238. }
  1239. # --- header
  1240. if (!fwrite($fh, "TPC\n")) {
  1241. $this->error = "Could not write Tilepic signature";
  1242. return false;
  1243. }
  1244. if (!fwrite($fh, pack("NNNNNNnnNN",40, $base_width, $base_height, $pa_options["tile_width"], $pa_options["tile_height"], $tiles, $pa_options["layers"], $pa_options["layer_ratio"], strlen($attribute_list),$attributes))) {
  1245. $this->error = "Could not write Tilepic header";
  1246. return false;
  1247. }
  1248. # --- offset table
  1249. $offset = 44 + ($tiles * 4);
  1250. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  1251. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  1252. if (!fwrite($fh, pack("N",$offset))) {
  1253. $this->error = "Could not write Tilepic offset table";
  1254. return false;
  1255. }
  1256. $offset += strlen($layer_list[$i][$j]);
  1257. }
  1258. }
  1259. if (!fwrite($fh, pack("N", $offset))) {
  1260. $this->error = "Could not finish writing Tilepic offset table";
  1261. return false;
  1262. }
  1263. # --- tiles
  1264. for($i=sizeof($layer_list)-1; $i >= 0; $i--) {
  1265. for($j=0; $j<sizeof($layer_list[$i]);$j++) {
  1266. if (!fwrite($fh, $layer_list[$i][$j])) {
  1267. $this->error = "Could not write Tilepic tile data";
  1268. return false;
  1269. }
  1270. }
  1271. }
  1272. unset($layer_list);
  1273. # --- attributes
  1274. if (!fwrite($fh, $attribute_list)) {
  1275. $this->error = "Could not write Tilepic attributes";
  1276. return false;
  1277. }
  1278. fclose($fh);
  1279. return $pa_options;
  1280. } else {
  1281. $this->error = "Couldn't open output file $ps_output_path\n";
  1282. return false;
  1283. }
  1284. }
  1285. # ------------------------------------------------------------------------------------
  1286. #
  1287. # Tilepic file access methods
  1288. #
  1289. # ------------------------------------------------------------------------------------
  1290. function getTile($tile_number) {
  1291. # --- Tile numbers start at 1, *NOT* 0 in parameter!
  1292. $tile_number--; # internally, tiles are numbered from zero, so adjust here
  1293. if (!$this->properties["filepath"]) {
  1294. $this->error = "No file loaded";
  1295. return false;
  1296. }
  1297. if (($this->fh) || ($this->fh = fopen($this->properties["filepath"], "r"))) {
  1298. if ($offset = $this->properties["tile_offsets"][$tile_number]) {
  1299. if (!($next_offset = $this->properties["tile_offsets"][$tile_number + 1])) {
  1300. if (!($next_offset = $this->properties["attribute_offset"])) {
  1301. $this->error = "Couldn't find end of tile [".$this->properties["attribute_offset"]."]";
  1302. return false;
  1303. }
  1304. }
  1305. if (fseek($this->fh, $offset, 0) == -1) {
  1306. $this->error = "Could not seek to requested tile";
  1307. return false;
  1308. }
  1309. return fread($this->fh, $next_offset - $offset);
  1310. } else {
  1311. $this->error = "Invalid tile number '$tile_number'";
  1312. return false;
  1313. }
  1314. } else {
  1315. $this->error = "Couldn't open file ".$this->properties["filepath"];
  1316. return false;
  1317. }
  1318. }
  1319. # ------------------------------------------------------------------------------------
  1320. function writeTiles($ps_dirpath, $ps_filestem="") {
  1321. # --- get tile offsets (start of each tile)
  1322. if (($this->fh) || ($this->fh = fopen($this->properties["filepath"], "r"))) {
  1323. $vs_ext = $this->mimetype2ext[$this->properties["tile_mimetype"]];
  1324. foreach($this->properties["tile_offsets"] as $vn_tile_num => $vn_offset) {
  1325. if (fseek($this->fh, $vn_offset, 0) == -1) {
  1326. $this->error = "Could not seek to requested tile";
  1327. return false;
  1328. }
  1329. if (!($vn_next_offset = $this->properties["tile_offsets"][$vn_tile_num + 1])) {
  1330. if (!($vn_next_offset = $this->properties["attribute_offset"])) {
  1331. $this->error = "Couldn't find end of tile [".$this->properties["attribute_offset"]."]";
  1332. return false;
  1333. }
  1334. }
  1335. if ($r_fh = fopen($ps_dirpath."/".$ps_filestem.($vn_tile_num+1).".".$vs_ext,"w+")) {
  1336. fwrite($r_fh, fread($this->fh, $vn_next_offset - $vn_offset));
  1337. fclose($r_fh);
  1338. } else {
  1339. $this->error = "Couldn't write tile to ".$ps_dirpath;
  1340. return false;
  1341. }
  1342. }
  1343. } else {
  1344. $this->error = "Couldn't open file ".$this->properties["filepath"];
  1345. return false;
  1346. }
  1347. }
  1348. # ------------------------------------------------------------------------------------
  1349. function getLayer($layer_number, $output_mimetype = "image/jpeg") {
  1350. if (!($magick = $this->mimetype2magick[$output_mimetype])) {
  1351. $this->error = "Invalid output format";
  1352. return false;
  1353. }
  1354. if (($layer_number > 0) && ($layer_number <= $this->properties['layers'])) {
  1355. #
  1356. # --- assemble tiles
  1357. #
  1358. switch($this->backend) {
  1359. case LIBRARY_GD:
  1360. $h = $this->getLayer_gd($layer_number, $output_mimetype);
  1361. break;
  1362. case LIBRARY_IMAGICK:
  1363. $h = $this->getLayer_imagick($layer_number, $magick);
  1364. break;
  1365. default:
  1366. $h = $this->getLayer_imagemagick($layer_number, $output_mimetype);
  1367. break;
  1368. }
  1369. return $h;
  1370. } else {
  1371. # --- layer does not exist
  1372. $this->error = "Layer $layer_number does not exist";
  1373. return false;
  1374. }
  1375. }
  1376. # ------------------------------------------------------------------------------------
  1377. function getLayer_imagemagick($layer_number, $output_mimetype) {
  1378. $layer_tiles = $this->getFileGeometry();
  1379. if (!($tile_count = $layer_tiles[$layer_number]['tiles'])) {
  1380. $this->error = "Invalid file";
  1381. return false;
  1382. }
  1383. $tile_start = 1;
  1384. for ($l=1; $l<$layer_number; $l++) {
  1385. $tile_start += $layer_tiles[$l]['tiles'];
  1386. }
  1387. $tile_number = $tile_start;
  1388. $tile_width = $this->properties['tile_width'];
  1389. $tile_height = $this->properties['tile_height'];
  1390. $va_tile_files = array();
  1391. for($y=0; $y<$layer_tiles[$layer_number]['vertical_tiles']; $y++) {
  1392. $cy = ($y*$tile_height);
  1393. for($x=0; $x<$layer_tiles[$layer_number]['horizontal_tiles']; $x++) {
  1394. $cx = ($x*$tile_width);
  1395. $tile = $this->getTile($tile_number);
  1396. if ($tile) {
  1397. $vs_tile_file = tempnam($vs_tilepic_tmpdir, "tpcl_");
  1398. file_put_contents($vs_tile_file, $tile);
  1399. $va_tile_files[] = $vs_tile_file;
  1400. }
  1401. $tile_number++;
  1402. }
  1403. }
  1404. if ($vs_ext = $this->mimetype2ext[$output_mimetype]) { $vs_ext = '.'.$vs_ext; }
  1405. $vs_tmp_base_path = tempnam($vs_tilepic_tmpdir, 'tcpt_');
  1406. $vs_tmp_path = $vs_tmp_base_path.$vs_ext;
  1407. if (!$this->_imageMagickImageFromTiles($vs_tmp_path, $va_tile_files, $tile_width, $tile_height)) {
  1408. $this->error = "Compositing of tiles failed";
  1409. foreach($va_tile_files as $vs_tile) {
  1410. @unlink($vs_tile);
  1411. }
  1412. return false;
  1413. }
  1414. foreach($va_tile_files as $vs_tile) {
  1415. @unlink($vs_tile);
  1416. }
  1417. $h = file_get_contents($vs_tmp_path);
  1418. @unlink($vs_tmp_path);
  1419. return $h;
  1420. }
  1421. # ----------------------------------------------------------------------------------

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