3 * @file src/Object/Photo.php
4 * @brief This file contains the Photo class for image processing
6 namespace Friendica\Object;
9 use Friendica\Core\Cache;
10 use Friendica\Core\Config;
11 use Friendica\Core\System;
12 use Friendica\Database\DBM;
15 require_once "include/photos.php";
18 * Class to handle Photos
25 * Put back gd stuff, not everybody have Imagick
35 * @brief supported mimetypes and corresponding file extensions
37 public static function supportedTypes()
39 if (class_exists('Imagick')) {
40 // Imagick::queryFormats won't help us a lot there...
41 // At least, not yet, other parts of friendica uses this array
43 'image/jpeg' => 'jpg',
49 $t['image/jpeg'] ='jpg';
50 if (imagetypes() & IMG_PNG) {
51 $t['image/png'] = 'png';
60 * @param object $data data
61 * @param boolean $type optional, default null
64 public function __construct($data, $type = null)
66 $this->imagick = class_exists('Imagick');
67 $this->types = static::supportedTypes();
68 if (!array_key_exists($type, $this->types)) {
73 if ($this->isImagick() && $this->loadData($data)) {
76 // Failed to load with Imagick, fallback
77 $this->imagick = false;
79 return $this->loadData($data);
86 public function __destruct()
89 if ($this->isImagick()) {
90 $this->image->clear();
91 $this->image->destroy();
94 if (is_resource($this->image)) {
95 imagedestroy($this->image);
103 public function isImagick()
105 return $this->imagick;
109 * @brief Maps Mime types to Imagick formats
110 * @return arr With with image formats (mime type as key)
112 public function getFormatsMap()
115 'image/jpeg' => 'JPG',
116 'image/png' => 'PNG',
123 * @param object $data data
126 private function loadData($data)
128 if ($this->isImagick()) {
129 $this->image = new Imagick();
131 $this->image->readImageBlob($data);
132 } catch (Exception $e) {
133 // Imagick couldn't use the data
138 * Setup the image to the format it will be saved to
140 $map = $this->getFormatsMap();
141 $format = $map[$type];
142 $this->image->setFormat($format);
144 // Always coalesce, if it is not a multi-frame image it won't hurt anyway
145 $this->image = $this->image->coalesceImages();
148 * setup the compression here, so we'll do it only once
150 switch ($this->getType()) {
152 $quality = Config::get('system', 'png_quality');
153 if ((! $quality) || ($quality > 9)) {
154 $quality = PNG_QUALITY;
157 * From http://www.imagemagick.org/script/command-line-options.php#quality:
159 * 'For the MNG and PNG image formats, the quality value sets
160 * the zlib compression level (quality / 10) and filter-type (quality % 10).
161 * The default PNG "quality" is 75, which means compression level 7 with adaptive PNG filtering,
162 * unless the image has a color map, in which case it means compression level 7 with no PNG filtering'
164 $quality = $quality * 10;
165 $this->image->setCompressionQuality($quality);
168 $quality = Config::get('system', 'jpeg_quality');
169 if ((! $quality) || ($quality > 100)) {
170 $quality = JPEG_QUALITY;
172 $this->image->setCompressionQuality($quality);
175 // The 'width' and 'height' properties are only used by non-Imagick routines.
176 $this->width = $this->image->getImageWidth();
177 $this->height = $this->image->getImageHeight();
183 $this->valid = false;
184 $this->image = @imagecreatefromstring($data);
185 if ($this->image !== false) {
186 $this->width = imagesx($this->image);
187 $this->height = imagesy($this->image);
189 imagealphablending($this->image, false);
190 imagesavealpha($this->image, true);
201 public function isValid()
203 if ($this->isImagick()) {
204 return ($this->image !== false);
212 public function getWidth()
214 if (!$this->isValid()) {
218 if ($this->isImagick()) {
219 return $this->image->getImageWidth();
227 public function getHeight()
229 if (!$this->isValid()) {
233 if ($this->isImagick()) {
234 return $this->image->getImageHeight();
236 return $this->height;
242 public function getImage()
244 if (!$this->isValid()) {
248 if ($this->isImagick()) {
250 $this->image = $this->image->deconstructImages();
259 public function getType()
261 if (!$this->isValid()) {
271 public function getExt()
273 if (!$this->isValid()) {
277 return $this->types[$this->getType()];
281 * @param integer $max max dimension
284 public function scaleImage($max)
286 if (!$this->isValid()) {
290 $width = $this->getWidth();
291 $height = $this->getHeight();
293 $dest_width = $dest_height = 0;
295 if ((! $width)|| (! $height)) {
299 if ($width > $max && $height > $max) {
300 // very tall image (greater than 16:9)
301 // constrain the width - let the height float.
303 if ((($height * 9) / 16) > $width) {
305 $dest_height = intval(($height * $max) / $width);
306 } elseif ($width > $height) {
307 // else constrain both dimensions
309 $dest_height = intval(($height * $max) / $width);
311 $dest_width = intval(($width * $max) / $height);
317 $dest_height = intval(($height * $max) / $width);
319 if ($height > $max) {
320 // very tall image (greater than 16:9)
321 // but width is OK - don't do anything
323 if ((($height * 9) / 16) > $width) {
324 $dest_width = $width;
325 $dest_height = $height;
327 $dest_width = intval(($width * $max) / $height);
331 $dest_width = $width;
332 $dest_height = $height;
338 if ($this->isImagick()) {
340 * If it is not animated, there will be only one iteration here,
341 * so don't bother checking
343 // Don't forget to go back to the first frame
344 $this->image->setFirstIterator();
346 // FIXME - implement horizantal bias for scaling as in followin GD functions
347 // to allow very tall images to be constrained only horizontally.
349 $this->image->scaleImage($dest_width, $dest_height);
350 } while ($this->image->nextImage());
352 // These may not be necessary any more
353 $this->width = $this->image->getImageWidth();
354 $this->height = $this->image->getImageHeight();
360 $dest = imagecreatetruecolor($dest_width, $dest_height);
361 imagealphablending($dest, false);
362 imagesavealpha($dest, true);
363 if ($this->type=='image/png') {
364 imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
366 imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
368 imagedestroy($this->image);
370 $this->image = $dest;
371 $this->width = imagesx($this->image);
372 $this->height = imagesy($this->image);
376 * @param integer $degrees degrees to rotate image
379 public function rotate($degrees)
381 if (!$this->isValid()) {
385 if ($this->isImagick()) {
386 $this->image->setFirstIterator();
388 $this->image->rotateImage(new ImagickPixel(), -$degrees); // ImageMagick rotates in the opposite direction of imagerotate()
389 } while ($this->image->nextImage());
393 // if script dies at this point check memory_limit setting in php.ini
394 $this->image = imagerotate($this->image, $degrees, 0);
395 $this->width = imagesx($this->image);
396 $this->height = imagesy($this->image);
400 * @param boolean $horiz optional, default true
401 * @param boolean $vert optional, default false
404 public function flip($horiz = true, $vert = false)
406 if (!$this->isValid()) {
410 if ($this->isImagick()) {
411 $this->image->setFirstIterator();
414 $this->image->flipImage();
417 $this->image->flopImage();
419 } while ($this->image->nextImage());
423 $w = imagesx($this->image);
424 $h = imagesy($this->image);
425 $flipped = imagecreate($w, $h);
427 for ($x = 0; $x < $w; $x++) {
428 imagecopy($flipped, $this->image, $x, 0, $w - $x - 1, 0, 1, $h);
432 for ($y = 0; $y < $h; $y++) {
433 imagecopy($flipped, $this->image, 0, $y, 0, $h - $y - 1, $w, 1);
436 $this->image = $flipped;
440 * @param string $filename filename
443 public function orient($filename)
445 if ($this->isImagick()) {
446 // based off comment on http://php.net/manual/en/imagick.getimageorientation.php
447 $orientation = $this->image->getImageOrientation();
448 switch ($orientation) {
449 case imagick::ORIENTATION_BOTTOMRIGHT:
450 $this->image->rotateimage("#000", 180);
452 case imagick::ORIENTATION_RIGHTTOP:
453 $this->image->rotateimage("#000", 90);
455 case imagick::ORIENTATION_LEFTBOTTOM:
456 $this->image->rotateimage("#000", -90);
460 $this->image->setImageOrientation(imagick::ORIENTATION_TOPLEFT);
463 // based off comment on http://php.net/manual/en/function.imagerotate.php
465 if (!$this->isValid()) {
469 if ((!function_exists('exif_read_data')) || ($this->getType() !== 'image/jpeg')) {
473 $exif = @exif_read_data($filename, null, true);
478 $ort = $exif['IFD0']['Orientation'];
484 case 2: // horizontal flip
488 case 3: // 180 rotate left
492 case 4: // vertical flip
493 $this->flip(false, true);
496 case 5: // vertical flip + 90 rotate right
497 $this->flip(false, true);
501 case 6: // 90 rotate right
505 case 7: // horizontal flip + 90 rotate right
510 case 8: // 90 rotate left
515 // logger('exif: ' . print_r($exif,true));
520 * @param integer $min minimum dimension
523 public function scaleImageUp($min)
525 if (!$this->isValid()) {
529 $width = $this->getWidth();
530 $height = $this->getHeight();
532 $dest_width = $dest_height = 0;
534 if ((!$width)|| (!$height)) {
538 if ($width < $min && $height < $min) {
539 if ($width > $height) {
541 $dest_height = intval(($height * $min) / $width);
543 $dest_width = intval(($width * $min) / $height);
549 $dest_height = intval(($height * $min) / $width);
551 if ($height < $min) {
552 $dest_width = intval(($width * $min) / $height);
555 $dest_width = $width;
556 $dest_height = $height;
561 if ($this->isImagick()) {
562 return $this->scaleImage($dest_width, $dest_height);
565 $dest = imagecreatetruecolor($dest_width, $dest_height);
566 imagealphablending($dest, false);
567 imagesavealpha($dest, true);
568 if ($this->type=='image/png') {
569 imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
571 imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
573 imagedestroy($this->image);
575 $this->image = $dest;
576 $this->width = imagesx($this->image);
577 $this->height = imagesy($this->image);
581 * @param integer $dim dimension
584 public function scaleImageSquare($dim)
586 if (!$this->isValid()) {
590 if ($this->isImagick()) {
591 $this->image->setFirstIterator();
593 $this->image->scaleImage($dim, $dim);
594 } while ($this->image->nextImage());
598 $dest = imagecreatetruecolor($dim, $dim);
599 imagealphablending($dest, false);
600 imagesavealpha($dest, true);
601 if ($this->type=='image/png') {
602 imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
604 imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dim, $dim, $this->width, $this->height);
606 imagedestroy($this->image);
608 $this->image = $dest;
609 $this->width = imagesx($this->image);
610 $this->height = imagesy($this->image);
614 * @param integer $max maximum
615 * @param integer $x x coordinate
616 * @param integer $y y coordinate
617 * @param integer $w width
618 * @param integer $h height
621 public function cropImage($max, $x, $y, $w, $h)
623 if (!$this->isValid()) {
627 if ($this->isImagick()) {
628 $this->image->setFirstIterator();
630 $this->image->cropImage($w, $h, $x, $y);
632 * We need to remove the canva,
633 * or the image is not resized to the crop:
634 * http://php.net/manual/en/imagick.cropimage.php#97232
636 $this->image->setImagePage(0, 0, 0, 0);
637 } while ($this->image->nextImage());
638 return $this->scaleImage($max);
641 $dest = imagecreatetruecolor($max, $max);
642 imagealphablending($dest, false);
643 imagesavealpha($dest, true);
644 if ($this->type=='image/png') {
645 imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
647 imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $max, $max, $w, $h);
649 imagedestroy($this->image);
651 $this->image = $dest;
652 $this->width = imagesx($this->image);
653 $this->height = imagesy($this->image);
657 * @param string $path file path
660 public function saveImage($path)
662 if (!$this->isValid()) {
666 $string = $this->imageString();
670 $stamp1 = microtime(true);
671 file_put_contents($path, $string);
672 $a->save_timestamp($stamp1, "file");
678 public function imageString()
680 if (!$this->isValid()) {
684 if ($this->isImagick()) {
686 $this->image = $this->image->deconstructImages();
687 $string = $this->image->getImagesBlob();
695 // Enable interlacing
696 imageinterlace($this->image, true);
698 switch ($this->getType()) {
700 $quality = Config::get('system', 'png_quality');
701 if ((!$quality) || ($quality > 9)) {
702 $quality = PNG_QUALITY;
704 imagepng($this->image, null, $quality);
707 $quality = Config::get('system', 'jpeg_quality');
708 if ((!$quality) || ($quality > 100)) {
709 $quality = JPEG_QUALITY;
711 imagejpeg($this->image, null, $quality);
713 $string = ob_get_contents();
720 * @param integer $uid uid
721 * @param integer $cid cid
722 * @param integer $rid rid
723 * @param string $filename filename
724 * @param string $album album name
725 * @param integer $scale scale
726 * @param integer $profile optional, default = 0
727 * @param string $allow_cid optional, default = ''
728 * @param string $allow_gid optional, default = ''
729 * @param string $deny_cid optional, default = ''
730 * @param string $deny_gid optional, default = ''
731 * @param string $desc optional, default = ''
734 public function store($uid, $cid, $rid, $filename, $album, $scale, $profile = 0, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '', $desc = '')
736 $r = dba::select('photo', array('guid'), array("`resource-id` = ? AND `guid` != ?", $rid, ''), array('limit' => 1));
737 if (DBM::is_result($r)) {
743 $x = dba::select('photo', array('id'), array('resource-id' => $rid, 'uid' => $uid, 'contact-id' => $cid, 'scale' => $scale), array('limit' => 1));
745 $fields = array('uid' => $uid, 'contact-id' => $cid, 'guid' => $guid, 'resource-id' => $rid, 'created' => datetime_convert(), 'edited' => datetime_convert(),
746 'filename' => basename($filename), 'type' => $this->getType(), 'album' => $album, 'height' => $this->getHeight(), 'width' => $this->getWidth(),
747 'datasize' => strlen($this->imageString()), 'data' => $this->imageString(), 'scale' => $scale, 'profile' => $profile,
748 'allow_cid' => $allow_cid, 'allow_gid' => $allow_gid, 'deny_cid' => $deny_cid, 'deny_gid' => $deny_gid, 'desc' => $desc);
750 if (DBM::is_result($x)) {
751 $r = dba::update('photo', $fields, array('id' => $x['id']));
753 $r = dba::insert('photo', $fields);
760 * Guess image mimetype from filename or from Content-Type header
762 * @param string $filename Image filename
763 * @param boolean $fromcurl Check Content-Type header from curl request
767 public function guessImageType($filename, $fromcurl = false)
769 logger('Photo: guessImageType: '.$filename . ($fromcurl?' from curl headers':''), LOGGER_DEBUG);
774 $h = explode("\n", $a->get_curl_headers());
776 list($k,$v) = array_map("trim", explode(":", trim($l), 2));
779 if (array_key_exists('Content-Type', $headers))
780 $type = $headers['Content-Type'];
782 if (is_null($type)) {
783 // Guessing from extension? Isn't that... dangerous?
784 if (class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
786 * Well, this not much better,
787 * but at least it comes from the data inside the image,
788 * we won't be tricked by a manipulated extension
790 $image = new Imagick($filename);
791 $type = $image->getImageMimeType();
792 $image->setInterlaceScheme(Imagick::INTERLACE_PLANE);
794 $ext = pathinfo($filename, PATHINFO_EXTENSION);
795 $types = $this->supportedTypes();
796 $type = "image/jpeg";
797 foreach ($types as $m => $e) {
804 logger('Photo: guessImageType: type='.$type, LOGGER_DEBUG);
809 * @brief Updates the avatar links in a contact only if needed
811 * @param string $avatar Link to avatar picture
812 * @param int $uid User id of contact owner
813 * @param int $cid Contact id
814 * @param bool $force force picture update
816 * @return array Returns array of the different avatar sizes
818 public function updateContactAvatar($avatar, $uid, $cid, $force = false)
820 // Limit = 1 returns the row so no need for dba:inArray()
821 $r = dba::select('contact', array('avatar', 'photo', 'thumb', 'micro', 'nurl'), array('id' => $cid), array('limit' => 1));
822 if (!DBM::is_result($r)) {
825 $data = array($r["photo"], $r["thumb"], $r["micro"]);
828 if (($r["avatar"] != $avatar) || $force) {
829 $photos = $this->importProfilePhoto($avatar, $uid, $cid, true);
834 array('avatar' => $avatar, 'photo' => $photos[0], 'thumb' => $photos[1], 'micro' => $photos[2], 'avatar-date' => datetime_convert()),
838 // Update the public contact (contact id = 0)
840 $pcontact = dba::select('contact', array('id'), array('nurl' => $r[0]['nurl']), array('limit' => 1));
841 if (DBM::is_result($pcontact)) {
842 $this->updateContactAvatar($avatar, 0, $pcontact['id'], $force);
854 * @param string $photo photo
855 * @param integer $uid user id
856 * @param integer $cid contact id
857 * @param boolean $quit_on_error optional, default false
860 private function importProfilePhoto($photo, $uid, $cid, $quit_on_error = false)
864 array('resource-id'),
865 array('uid' => $uid, 'contact-id' => $cid, 'scale' => 4, 'album' => 'Contact Photos'),
869 if (DBM::is_result($r) && strlen($r['resource-id'])) {
870 $hash = $r['resource-id'];
872 $hash = photo_new_resource();
875 $photo_failure = false;
877 $filename = basename($photo);
878 $img_str = fetch_url($photo, true);
880 if ($quit_on_error && ($img_str == "")) {
884 $type = $this->guessImageType($photo, true);
885 $img = new Photo($img_str, $type);
886 if ($img->isValid()) {
887 $img->scaleImageSquare(175);
889 $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 4);
892 $photo_failure = true;
895 $img->scaleImage(80);
897 $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 5);
900 $photo_failure = true;
903 $img->scaleImage(48);
905 $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 6);
908 $photo_failure = true;
911 $suffix = '?ts='.time();
913 $photo = System::baseUrl() . '/photo/' . $hash . '-4.' . $img->getExt() . $suffix;
914 $thumb = System::baseUrl() . '/photo/' . $hash . '-5.' . $img->getExt() . $suffix;
915 $micro = System::baseUrl() . '/photo/' . $hash . '-6.' . $img->getExt() . $suffix;
917 // Remove the cached photo
919 $basepath = $a->get_basepath();
921 if (is_dir($basepath."/photo")) {
922 $filename = $basepath.'/photo/'.$hash.'-4.'.$img->getExt();
923 if (file_exists($filename)) {
926 $filename = $basepath.'/photo/'.$hash.'-5.'.$img->getExt();
927 if (file_exists($filename)) {
930 $filename = $basepath.'/photo/'.$hash.'-6.'.$img->getExt();
931 if (file_exists($filename)) {
936 $photo_failure = true;
939 if ($photo_failure && $quit_on_error) {
943 if ($photo_failure) {
944 $photo = System::baseUrl() . '/images/person-175.jpg';
945 $thumb = System::baseUrl() . '/images/person-80.jpg';
946 $micro = System::baseUrl() . '/images/person-48.jpg';
949 return(array($photo, $thumb, $micro));
953 * @param string $url url
956 public function getPhotoInfo($url)
960 $data = Cache::get($url);
962 if (is_null($data) || !$data || !is_array($data)) {
963 $img_str = fetch_url($url, true, $redirects, 4);
964 $filesize = strlen($img_str);
966 if (function_exists("getimagesizefromstring")) {
967 $data = getimagesizefromstring($img_str);
969 $tempfile = tempnam(get_temppath(), "cache");
972 $stamp1 = microtime(true);
973 file_put_contents($tempfile, $img_str);
974 $a->save_timestamp($stamp1, "file");
976 $data = getimagesize($tempfile);
981 $data["size"] = $filesize;
984 Cache::set($url, $data);
991 * @param integer $width width
992 * @param integer $height height
993 * @param integer $max max
996 public function scaleImageTo($width, $height, $max)
998 $dest_width = $dest_height = 0;
1000 if ((!$width) || (!$height)) {
1004 if ($width > $max && $height > $max) {
1005 // very tall image (greater than 16:9)
1006 // constrain the width - let the height float.
1008 if ((($height * 9) / 16) > $width) {
1010 $dest_height = intval(($height * $max) / $width);
1011 } elseif ($width > $height) {
1012 // else constrain both dimensions
1014 $dest_height = intval(($height * $max) / $width);
1016 $dest_width = intval(($width * $max) / $height);
1017 $dest_height = $max;
1020 if ($width > $max) {
1022 $dest_height = intval(($height * $max) / $width);
1024 if ($height > $max) {
1025 // very tall image (greater than 16:9)
1026 // but width is OK - don't do anything
1028 if ((($height * 9) / 16) > $width) {
1029 $dest_width = $width;
1030 $dest_height = $height;
1032 $dest_width = intval(($width * $max) / $height);
1033 $dest_height = $max;
1036 $dest_width = $width;
1037 $dest_height = $height;
1041 return array("width" => $dest_width, "height" => $dest_height);
1045 * @brief This function doesn't seem to be used
1046 * @param object $a App
1047 * @param integer $uid user id
1048 * @param string $imagedata optional, default empty
1049 * @param string $url optional, default empty
1052 private function storePhoto(App $a, $uid, $imagedata = "", $url = "")
1055 "SELECT `user`.`nickname`, `user`.`page-flags`, `contact`.`id` FROM `user` INNER JOIN `contact` on `user`.`uid` = `contact`.`uid`
1056 WHERE `user`.`uid` = %d AND `user`.`blocked` = 0 AND `contact`.`self` = 1 LIMIT 1",
1060 if (!DBM::is_result($r)) {
1061 logger("Can't detect user data for uid ".$uid, LOGGER_DEBUG);
1065 $page_owner_nick = $r[0]['nickname'];
1068 /// $default_cid = $r[0]['id'];
1069 /// $community_page = (($r[0]['page-flags'] == PAGE_COMMUNITY) ? true : false);
1071 if ((strlen($imagedata) == 0) && ($url == "")) {
1072 logger("No image data and no url provided", LOGGER_DEBUG);
1074 } elseif (strlen($imagedata) == 0) {
1075 logger("Uploading picture from ".$url, LOGGER_DEBUG);
1077 $stamp1 = microtime(true);
1078 $imagedata = @file_get_contents($url);
1079 $a->save_timestamp($stamp1, "file");
1082 $maximagesize = Config::get('system', 'maximagesize');
1084 if (($maximagesize) && (strlen($imagedata) > $maximagesize)) {
1085 logger("Image exceeds size limit of ".$maximagesize, LOGGER_DEBUG);
1089 $tempfile = tempnam(get_temppath(), "cache");
1091 $stamp1 = microtime(true);
1092 file_put_contents($tempfile, $imagedata);
1093 $a->save_timestamp($stamp1, "file");
1095 $data = getimagesize($tempfile);
1097 if (!isset($data["mime"])) {
1099 logger("File is no picture", LOGGER_DEBUG);
1103 $ph = new Photo($imagedata, $data["mime"]);
1105 if (!$ph->isValid()) {
1107 logger("Picture is no valid picture", LOGGER_DEBUG);
1111 $ph->orient($tempfile);
1114 $max_length = Config::get('system', 'max_image_length');
1115 if (! $max_length) {
1116 $max_length = MAX_IMAGE_LENGTH;
1118 if ($max_length > 0) {
1119 $ph->scaleImage($max_length);
1122 $width = $ph->getWidth();
1123 $height = $ph->getHeight();
1125 $hash = photo_new_resource();
1129 // Pictures are always public by now
1130 //$defperm = '<'.$default_cid.'>';
1134 $r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 0, 0, $defperm);
1137 logger("Picture couldn't be stored", LOGGER_DEBUG);
1141 $image = array("page" => System::baseUrl().'/photos/'.$page_owner_nick.'/image/'.$hash,
1142 "full" => System::baseUrl()."/photo/{$hash}-0.".$ph->getExt());
1144 if ($width > 800 || $height > 800) {
1145 $image["large"] = System::baseUrl()."/photo/{$hash}-0.".$ph->getExt();
1148 if ($width > 640 || $height > 640) {
1149 $ph->scaleImage(640);
1150 $r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 1, 0, $defperm);
1152 $image["medium"] = System::baseUrl()."/photo/{$hash}-1.".$ph->getExt();
1156 if ($width > 320 || $height > 320) {
1157 $ph->scaleImage(320);
1158 $r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 2, 0, $defperm);
1160 $image["small"] = System::baseUrl()."/photo/{$hash}-2.".$ph->getExt();
1164 if ($width > 160 && $height > 160) {
1168 $min = $ph->getWidth();
1170 $x = ($min - 160) / 2;
1173 if ($ph->getHeight() < $min) {
1174 $min = $ph->getHeight();
1176 $y = ($min - 160) / 2;
1181 $ph->cropImage(160, $x, $y, $min, $min);
1183 $r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 3, 0, $defperm);
1185 $image["thumb"] = System::baseUrl()."/photo/{$hash}-3.".$ph->getExt();
1189 // Set the full image as preview image. This will be overwritten, if the picture is larger than 640.
1190 $image["preview"] = $image["full"];
1192 // Deactivated, since that would result in a cropped preview, if the picture wasn't larger than 320
1193 //if (isset($image["thumb"]))
1194 // $image["preview"] = $image["thumb"];
1196 // Unsure, if this should be activated or deactivated
1197 //if (isset($image["small"]))
1198 // $image["preview"] = $image["small"];
1200 if (isset($image["medium"])) {
1201 $image["preview"] = $image["medium"];