resize.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. <?php
  2. /**
  3. * Elgg tidypics library of resizing functions
  4. *
  5. * @package TidypicsImageResize
  6. */
  7. include dirname(__FILE__) . "/watermark.php";
  8. /**
  9. * Create thumbnails using PHP GD Library
  10. *
  11. * @param ElggFile holds the image that was uploaded
  12. * @param string folder to store thumbnail in
  13. * @param string name of the thumbnail
  14. * @return bool TRUE on success
  15. */
  16. function tp_create_gd_thumbnails($file, $prefix, $filestorename) {
  17. global $CONFIG;
  18. $image_sizes = elgg_get_plugin_setting('image_sizes', 'tidypics');
  19. if (!$image_sizes) {
  20. // move this out of library
  21. register_error(elgg_echo('tidypics:nosettings'));
  22. forward(REFERER);
  23. return FALSE;
  24. }
  25. $image_sizes = unserialize($image_sizes);
  26. $thumb = new ElggFile();
  27. $thumb->owner_guid = $file->owner_guid;
  28. $thumb->container_guid = $file->container_guid;
  29. // tiny thumbail
  30. $thumb->setFilename($prefix."thumb".$filestorename);
  31. $thumbname = $thumb->getFilenameOnFilestore();
  32. if (empty($image_sizes['tiny_image_width'])) {
  33. // sites upgraded from 1.6 may not have this set
  34. $image_sizes['tiny_image_width'] = $image_sizes['tiny_image_height'] = 60;
  35. }
  36. $rtn_code = tp_gd_resize( $file->getFilenameOnFilestore(),
  37. $thumbname,
  38. FALSE,
  39. $image_sizes['tiny_image_width'],
  40. $image_sizes['tiny_image_height'],
  41. TRUE);
  42. if (!$rtn_code) {
  43. return FALSE;
  44. }
  45. $file->thumbnail = $prefix."thumb".$filestorename;
  46. // album thumbnail
  47. global $CONFIG;
  48. $CONFIG->debug = 'WARNING';
  49. $thumb->setFilename($prefix."smallthumb".$filestorename);
  50. $thumbname = $thumb->getFilenameOnFilestore();
  51. $rtn_code = tp_gd_resize( $file->getFilenameOnFilestore(),
  52. $thumbname,
  53. FALSE,
  54. $image_sizes['small_image_width'],
  55. $image_sizes['small_image_height'],
  56. TRUE);
  57. if (!$rtn_code) {
  58. return FALSE;
  59. }
  60. $file->smallthumb = $prefix."smallthumb".$filestorename;
  61. unset($CONFIG->debug);
  62. // main image
  63. $thumb->setFilename($prefix."largethumb".$filestorename);
  64. $thumbname = $thumb->getFilenameOnFilestore();
  65. $rtn_code = tp_gd_resize( $file->getFilenameOnFilestore(),
  66. $thumbname,
  67. TRUE,
  68. $image_sizes['large_image_width'],
  69. $image_sizes['large_image_height'],
  70. FALSE);
  71. if (!$rtn_code) {
  72. return FALSE;
  73. }
  74. $file->largethumb = $prefix."largethumb".$filestorename;
  75. unset($thumb);
  76. return TRUE;
  77. }
  78. /**
  79. * Writes resized version of an already uploaded image - original from Elgg filestore.php
  80. * Saves it in the same format as uploaded
  81. *
  82. * @param string $input_name The name of the file on the disk
  83. * @param string $output_name The name of the file to be written
  84. * @param bool - watermark this image?
  85. * @param int $maxwidth The maximum width of the resized image
  86. * @param int $maxheight The maximum height of the resized image
  87. * @param TRUE|FALSE $square If set to TRUE, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped.
  88. * @return bool TRUE on success or FALSE on failure
  89. */
  90. function tp_gd_resize($input_name, $output_name, $watermark, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) {
  91. // Get the size information from the image
  92. $imgsizearray = getimagesize($input_name);
  93. if (!$imgsizearray) {
  94. return FALSE;
  95. }
  96. // Get width and height of image
  97. $width = $imgsizearray[0];
  98. $height = $imgsizearray[1];
  99. $params = tp_im_calc_resize_params($width, $height, $maxwidth, $maxheight, $square, $x1, $y1, $x2, $y2);
  100. if (!$params) {
  101. return FALSE;
  102. }
  103. $new_width = $params['new_width'];
  104. $new_height = $params['new_height'];
  105. $region_width = $params['region_width'];
  106. $region_height = $params['region_height'];
  107. $widthoffset = $params['width_offset'];
  108. $heightoffset = $params['height_offset'];
  109. $accepted_formats = array(
  110. 'image/jpeg' => 'jpeg',
  111. 'image/pjpeg' => 'jpeg',
  112. 'image/png' => 'png',
  113. 'image/x-png' => 'png',
  114. 'image/gif' => 'gif'
  115. );
  116. // make sure the function is available
  117. $function = "imagecreatefrom" . $accepted_formats[$imgsizearray['mime']];
  118. if (!is_callable($function)) {
  119. return FALSE;
  120. }
  121. // load old image
  122. $oldimage = $function($input_name);
  123. if (!$oldimage) {
  124. return FALSE;
  125. }
  126. // allocate the new image
  127. $newimage = imagecreatetruecolor($new_width, $new_height);
  128. if (!$newimage) {
  129. return FALSE;
  130. }
  131. // color transparencies white (default is black)
  132. imagefilledrectangle(
  133. $newimage, 0, 0, $new_width, $new_height, imagecolorallocate($newimage, 255, 255, 255)
  134. );
  135. $rtn_code = imagecopyresampled( $newimage,
  136. $oldimage,
  137. 0,
  138. 0,
  139. $widthoffset,
  140. $heightoffset,
  141. $new_width,
  142. $new_height,
  143. $region_width,
  144. $region_height);
  145. if (!$rtn_code) {
  146. return $rtn_code;
  147. }
  148. if ($watermark) {
  149. tp_gd_watermark($newimage);
  150. }
  151. switch ($imgsizearray['mime']) {
  152. case 'image/jpeg':
  153. case 'image/pjpeg':
  154. $rtn_code = imagejpeg($newimage, $output_name, 85);
  155. break;
  156. case 'image/png':
  157. case 'image/x-png':
  158. $rtn_code = imagepng($newimage, $output_name);
  159. break;
  160. case 'image/gif':
  161. $rtn_code = imagegif($newimage, $output_name);
  162. break;
  163. }
  164. imagedestroy($newimage);
  165. imagedestroy($oldimage);
  166. return $rtn_code;
  167. }
  168. /**
  169. * Create thumbnails using PHP imagick extension
  170. *
  171. * @param ElggFile holds the image that was uploaded
  172. * @param string folder to store thumbnail in
  173. * @param string name of the thumbnail
  174. * @return bool TRUE on success
  175. */
  176. function tp_create_imagick_thumbnails($file, $prefix, $filestorename) {
  177. $image_sizes = elgg_get_plugin_setting('image_sizes', 'tidypics');
  178. if (!$image_sizes) {
  179. register_error(elgg_echo('tidypics:nosettings'));
  180. return FALSE;
  181. }
  182. $image_sizes = unserialize($image_sizes);
  183. $thumb = new ElggFile();
  184. $thumb->owner_guid = $file->owner_guid;
  185. $thumb->container_guid = $file->container_guid;
  186. // tiny thumbnail
  187. $thumb->setFilename($prefix."thumb".$filestorename);
  188. $thumbname = $thumb->getFilenameOnFilestore();
  189. if (empty($image_sizes['tiny_image_width'])) {
  190. // sites upgraded from 1.6 may not have this set
  191. $image_sizes['tiny_image_width'] = $image_sizes['tiny_image_height'] = 60;
  192. }
  193. $rtn_code = tp_imagick_resize( $file->getFilenameOnFilestore(),
  194. $thumbname,
  195. $image_sizes['tiny_image_width'],
  196. $image_sizes['tiny_image_height'],
  197. TRUE);
  198. if (!$rtn_code) {
  199. return FALSE;
  200. }
  201. $file->thumbnail = $prefix."thumb".$filestorename;
  202. // album thumbnail
  203. $thumb->setFilename($prefix."smallthumb".$filestorename);
  204. $thumbname = $thumb->getFilenameOnFilestore();
  205. $rtn_code = tp_imagick_resize( $file->getFilenameOnFilestore(),
  206. $thumbname,
  207. $image_sizes['small_image_width'],
  208. $image_sizes['small_image_height'],
  209. TRUE);
  210. if (!$rtn_code) {
  211. return FALSE;
  212. }
  213. $file->smallthumb = $prefix."smallthumb".$filestorename;
  214. // main image
  215. $thumb->setFilename($prefix."largethumb".$filestorename);
  216. $thumbname = $thumb->getFilenameOnFilestore();
  217. $rtn_code = tp_imagick_resize( $file->getFilenameOnFilestore(),
  218. $thumbname,
  219. $image_sizes['large_image_width'],
  220. $image_sizes['large_image_height'],
  221. FALSE);
  222. if (!$rtn_code) {
  223. return FALSE;
  224. }
  225. $file->largethumb = $prefix."largethumb".$filestorename;
  226. tp_imagick_watermark($thumbname);
  227. unset($thumb);
  228. return TRUE;
  229. }
  230. /**
  231. * Resize using PHP imagick extension
  232. *
  233. * Writes resized version of an already uploaded image
  234. *
  235. *
  236. * @param string $input_name The name of the file input field on the submission form
  237. * @param string $output_name The name of the file to be written
  238. * @param int $maxwidth The maximum width of the resized image
  239. * @param int $maxheight The maximum height of the resized image
  240. * @param TRUE|FALSE $square If set to TRUE, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped.
  241. * @return bool TRUE on success
  242. */
  243. function tp_imagick_resize($input_name, $output_name, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) {
  244. // Get the size information from the image
  245. $imgsizearray = getimagesize($input_name);
  246. if (!$imgsizearray) {
  247. return FALSE;
  248. }
  249. // Get width and height
  250. $width = $imgsizearray[0];
  251. $height = $imgsizearray[1];
  252. $params = tp_im_calc_resize_params($width, $height, $maxwidth, $maxheight, $square, $x1, $y1, $x2, $y2);
  253. if (!$params) {
  254. return FALSE;
  255. }
  256. $new_width = $params['new_width'];
  257. $new_height = $params['new_height'];
  258. $region_width = $params['region_width'];
  259. $region_height = $params['region_height'];
  260. $widthoffset = $params['width_offset'];
  261. $heightoffset = $params['height_offset'];
  262. try {
  263. $img = new Imagick($input_name);
  264. } catch (ImagickException $e) {
  265. return FALSE;
  266. }
  267. $img->cropImage($region_width, $region_height, $widthoffset, $heightoffset);
  268. // use the default IM filter (windowing filter), I think 1 means default blurring or number of lobes
  269. $img->resizeImage($new_width, $new_height, imagick::FILTER_LANCZOS, 1);
  270. $img->setImagePage($new_width, $new_height, 0, 0);
  271. if ($img->writeImage($output_name) != TRUE) {
  272. $img->destroy();
  273. return FALSE;
  274. }
  275. $img->destroy();
  276. return TRUE;
  277. }
  278. /**
  279. * Create thumbnails using ImageMagick executables
  280. *
  281. * @param ElggFile holds the image that was uploaded
  282. * @param string folder to store thumbnail in
  283. * @param string name of the thumbnail
  284. * @return bool TRUE on success
  285. */
  286. function tp_create_im_cmdline_thumbnails($file, $prefix, $filestorename) {
  287. $image_sizes = elgg_get_plugin_setting('image_sizes', 'tidypics');
  288. if (!$image_sizes) {
  289. register_error(elgg_echo('tidypics:nosettings'));
  290. return FALSE;
  291. }
  292. $image_sizes = unserialize($image_sizes);
  293. $thumb = new ElggFile();
  294. $thumb->owner_guid = $file->owner_guid;
  295. $thumb->container_guid = $file->container_guid;
  296. // tiny thumbnail
  297. $thumb->setFilename($prefix."thumb".$filestorename);
  298. $thumbname = $thumb->getFilenameOnFilestore();
  299. if (empty($image_sizes['tiny_image_width'])) {
  300. // sites upgraded from 1.6 may not have this set
  301. $image_sizes['tiny_image_width'] = $image_sizes['tiny_image_height'] = 60;
  302. }
  303. $rtn_code = tp_im_cmdline_resize( $file->getFilenameOnFilestore(),
  304. $thumbname,
  305. $image_sizes['tiny_image_width'],
  306. $image_sizes['tiny_image_height'],
  307. TRUE);
  308. if (!$rtn_code) {
  309. return FALSE;
  310. }
  311. $file->thumbnail = $prefix."thumb".$filestorename;
  312. // album thumbnail
  313. $thumb->setFilename($prefix."smallthumb".$filestorename);
  314. $thumbname = $thumb->getFilenameOnFilestore();
  315. $rtn_code = tp_im_cmdline_resize( $file->getFilenameOnFilestore(),
  316. $thumbname,
  317. $image_sizes['small_image_width'],
  318. $image_sizes['small_image_height'],
  319. TRUE);
  320. if (!$rtn_code) {
  321. return FALSE;
  322. }
  323. $file->smallthumb = $prefix."smallthumb".$filestorename;
  324. // main image
  325. $thumb->setFilename($prefix."largethumb".$filestorename);
  326. $thumbname = $thumb->getFilenameOnFilestore();
  327. $rtn_code = tp_im_cmdline_resize( $file->getFilenameOnFilestore(),
  328. $thumbname,
  329. $image_sizes['large_image_width'],
  330. $image_sizes['large_image_height'],
  331. FALSE);
  332. if (!$rtn_code) {
  333. return FALSE;
  334. }
  335. $file->largethumb = $prefix."largethumb".$filestorename;
  336. tp_im_cmdline_watermark($thumbname);
  337. unset($thumb);
  338. return TRUE;
  339. }
  340. /**
  341. * Gets the jpeg contents of the resized version of an already uploaded image
  342. * (Returns FALSE if the uploaded file was not an image)
  343. *
  344. * @param string $input_name The name of the file input field on the submission form
  345. * @param string $output_name The name of the file to be written
  346. * @param int $maxwidth The maximum width of the resized image
  347. * @param int $maxheight The maximum height of the resized image
  348. * @param TRUE|FALSE $square If set to TRUE, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped.
  349. * @return bool
  350. */
  351. function tp_im_cmdline_resize($input_name, $output_name, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) {
  352. // Get the size information from the image
  353. $imgsizearray = getimagesize($input_name);
  354. if (!$imgsizearray) {
  355. return FALSE;
  356. }
  357. // Get width and height
  358. $orig_width = $imgsizearray[0];
  359. $orig_height = $imgsizearray[1];
  360. $params = tp_im_calc_resize_params($orig_width, $orig_height, $maxwidth, $maxheight, $square, $x1, $y1, $x2, $y2);
  361. if (!$params) {
  362. return FALSE;
  363. }
  364. $newwidth = $params['new_width'];
  365. $newheight = $params['new_height'];
  366. $accepted_formats = array(
  367. 'image/jpeg' => 'jpeg',
  368. 'image/pjpeg' => 'jpeg',
  369. 'image/png' => 'png',
  370. 'image/x-png' => 'png',
  371. 'image/gif' => 'gif'
  372. );
  373. // If it's a file we can manipulate ...
  374. if (!array_key_exists($imgsizearray['mime'],$accepted_formats)) {
  375. return FALSE;
  376. }
  377. $im_path = elgg_get_plugin_setting('im_path', 'tidypics');
  378. if (!$im_path) {
  379. $im_path = "/usr/bin/";
  380. }
  381. if (substr($im_path, strlen($im_path)-1, 1) != "/") {
  382. $im_path .= "/";
  383. }
  384. // see imagemagick web site for explanation of these parameters
  385. // the ^ in the resize means those are minimum width and height values
  386. $command = $im_path . "convert \"$input_name\" -resize ".$newwidth."x".$newheight."^ -gravity center -extent ".$newwidth."x".$newheight." \"$output_name\"";
  387. $output = array();
  388. $ret = 0;
  389. exec($command, $output, $ret);
  390. if ($ret == 127) {
  391. trigger_error('Tidypics warning: Image Magick convert is not found', E_USER_WARNING);
  392. return FALSE;
  393. } else if ($ret > 0) {
  394. trigger_error('Tidypics warning: Image Magick convert failed', E_USER_WARNING);
  395. return FALSE;
  396. }
  397. return TRUE;
  398. }
  399. /**
  400. * Calculate the resizing/cropping parameters
  401. *
  402. * @param int $orig_width
  403. * @param int $orig_height
  404. * @param int $new_width
  405. * @param int $new_height
  406. * @param bool $square
  407. * @param int $x1
  408. * @param int $y1
  409. * @param int $x2
  410. * @param int $y2
  411. * @return array|FALSE
  412. */
  413. function tp_im_calc_resize_params($orig_width, $orig_height, $new_width, $new_height, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) {
  414. // crop image first?
  415. $crop = TRUE;
  416. if ($x1 == 0 && $y1 == 0 && $x2 == 0 && $y2 == 0) {
  417. $crop = FALSE;
  418. }
  419. // how large a section of the image has been selected
  420. if ($crop) {
  421. $region_width = $x2 - $x1;
  422. $region_height = $y2 - $y1;
  423. } else {
  424. // everything selected if no crop parameters
  425. $region_width = $orig_width;
  426. $region_height = $orig_height;
  427. }
  428. // determine cropping offsets
  429. if ($square) {
  430. // asking for a square image back
  431. // detect case where someone is passing crop parameters that are not for a square
  432. if ($crop == TRUE && $region_width != $region_height) {
  433. return FALSE;
  434. }
  435. // size of the new square image
  436. $new_width = $new_height = min($new_width, $new_height);
  437. // find largest square that fits within the selected region
  438. $region_width = $region_height = min($region_width, $region_height);
  439. // set offsets for crop
  440. if ($crop) {
  441. $widthoffset = $x1;
  442. $heightoffset = $y1;
  443. $orig_width = $x2 - $x1;
  444. $orig_height = $orig_width;
  445. } else {
  446. // place square region in the center
  447. $widthoffset = floor(($orig_width - $region_width) / 2);
  448. $heightoffset = floor(($orig_height - $region_height) / 2);
  449. }
  450. } else {
  451. // non-square new image
  452. // maintain aspect ratio of original image/crop
  453. if (($region_height / (float)$new_height) > ($region_width / (float)$new_width)) {
  454. $new_width = floor($new_height * $region_width / (float)$region_height);
  455. } else {
  456. $new_height = floor($new_width * $region_height / (float)$region_width);
  457. }
  458. // by default, use entire image
  459. $widthoffset = 0;
  460. $heightoffset = 0;
  461. if ($crop) {
  462. $widthoffset = $x1;
  463. $heightoffset = $y1;
  464. }
  465. }
  466. $resize_params = array();
  467. $resize_params['new_width'] = $new_width;
  468. $resize_params['new_height'] = $new_height;
  469. $resize_params['region_width'] = $region_width;
  470. $resize_params['region_height'] = $region_height;
  471. $resize_params['width_offset'] = $widthoffset;
  472. $resize_params['height_offset'] = $heightoffset;
  473. return $resize_params;
  474. }