diff options
author | Mario <mario@mariovavti.com> | 2019-02-18 10:02:46 +0100 |
---|---|---|
committer | Mario <mario@mariovavti.com> | 2019-02-18 10:02:46 +0100 |
commit | b5109d2a1ae6056ec845c66ad89ccb02b4de0a05 (patch) | |
tree | cc5fc990c3178af5c537a47891148a36baa77020 /include/photo | |
parent | f11c17063cfb2133bd3e90b4417e8ffddbe3c29b (diff) | |
parent | b9df4c99cf9fcd1b16757309b4206ad084376aa2 (diff) | |
download | volse-hubzilla-b5109d2a1ae6056ec845c66ad89ccb02b4de0a05.tar.gz volse-hubzilla-b5109d2a1ae6056ec845c66ad89ccb02b4de0a05.tar.bz2 volse-hubzilla-b5109d2a1ae6056ec845c66ad89ccb02b4de0a05.zip |
Merge branch 'photo_driver_refactor' into 'dev'
Photo driver refactor
See merge request hubzilla/core!1515
Diffstat (limited to 'include/photo')
-rw-r--r-- | include/photo/photo_driver.php | 857 | ||||
-rw-r--r-- | include/photo/photo_gd.php | 162 | ||||
-rw-r--r-- | include/photo/photo_imagick.php | 213 |
3 files changed, 220 insertions, 1012 deletions
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index 5c8ed9bdc..c11580bdc 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -1,18 +1,34 @@ -<?php /** @file */ +<?php +use Zotlabs\Photo\PhotoDriver; +use Zotlabs\Photo\PhotoGd; +use Zotlabs\Photo\PhotoImagick; + +/** + * @brief Return a PhotoDriver object. + * + * Use this factory when manipulating images. + * + * Return a photo driver object implementing ImageMagick or GD. + * + * @param string $data Image data + * @param string $type Mimetype + * @return null|PhotoDriver + * NULL if unsupported image type or failure, otherwise photo driver object + */ function photo_factory($data, $type = null) { $ph = null; + $m = null; - - $unsupported_types = array( + $unsupported_types = [ 'image/bmp', 'image/vnd.microsoft.icon', 'image/tiff', - 'image/svg+xml' - ); + 'image/svg+xml', + ]; - if($type && in_array(strtolower($type),$unsupported_types)) { - logger('photo_factory: unsupported image type'); + if($type && in_array(strtolower($type), $unsupported_types)) { + logger('Unsupported image type ' . $type); return null; } @@ -21,475 +37,47 @@ function photo_factory($data, $type = null) { if(class_exists('Imagick') && !$ignore_imagick) { $v = Imagick::getVersion(); preg_match('/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $m); - if(version_compare($m[1],'6.6.7') >= 0) { - require_once('include/photo/photo_imagick.php'); - $ph = new photo_imagick($data,$type); - } - else { + if(version_compare($m[1], '6.6.7') >= 0) { + $ph = new PhotoImagick($data, $type); + } else { // earlier imagick versions have issues with scaling png's // don't log this because it will just fill the logfile. - // leave this note here so those who are looking for why + // leave this note here so those who are looking for why // we aren't using imagick can find it } } if(! $ph) { - require_once('include/photo/photo_gd.php'); - $ph = new photo_gd($data,$type); + $ph = new PhotoGd($data, $type); } return $ph; } - - -abstract class photo_driver { - - protected $image; - protected $width; - protected $height; - protected $valid; - protected $type; - protected $types; - - abstract function supportedTypes(); - - abstract function load($data,$type); - - abstract function destroy(); - - abstract function setDimensions(); - - abstract function getImage(); - - abstract function doScaleImage($new_width,$new_height); - - abstract function rotate($degrees); - - abstract function flip($horiz = true, $vert = false); - - abstract function cropImage($max,$x,$y,$w,$h); - - abstract function cropImageRect($maxx,$maxy,$x,$y,$w,$h); - - abstract function imageString(); - - abstract function clearexif(); - - public function __construct($data, $type='') { - $this->types = $this->supportedTypes(); - if (! array_key_exists($type,$this->types)){ - $type='image/jpeg'; - } - $this->type = $type; - $this->valid = false; - $this->load($data,$type); - } - - public function __destruct() { - if($this->is_valid()) - $this->destroy(); - } - - public function is_valid() { - return $this->valid; - } - - public function getWidth() { - if(!$this->is_valid()) - return FALSE; - return $this->width; - } - - public function getHeight() { - if(!$this->is_valid()) - return FALSE; - return $this->height; - } - - - public function saveImage($path) { - if(!$this->is_valid()) - return FALSE; - return (file_put_contents($path, $this->imageString()) ? true : false); - } - - - public function getType() { - if(!$this->is_valid()) - return FALSE; - - return $this->type; - } - - public function getExt() { - if(!$this->is_valid()) - return FALSE; - - return $this->types[$this->getType()]; - } - - /** - * @brief scale image - * int $max maximum pixel size in either dimension - * boolean $float_height - if true allow height to float to any length on tall images, - * constraining only the width - */ - - public function scaleImage($max, $float_height = true) { - if(!$this->is_valid()) - return FALSE; - - $width = $this->width; - $height = $this->height; - - $dest_width = $dest_height = 0; - - if((! $width)|| (! $height)) - return FALSE; - - if($width > $max && $height > $max) { - - // very tall image (greater than 16:9) - // constrain the width - let the height float. - - if(((($height * 9) / 16) > $width) && ($float_height)) { - $dest_width = $max; - $dest_height = intval(( $height * $max ) / $width); - } - - // else constrain both dimensions - - elseif($width > $height) { - $dest_width = $max; - $dest_height = intval(( $height * $max ) / $width); - } - else { - $dest_width = intval(( $width * $max ) / $height); - $dest_height = $max; - } - } - else { - if( $width > $max ) { - $dest_width = $max; - $dest_height = intval(( $height * $max ) / $width); - } - else { - if( $height > $max ) { - - // very tall image (greater than 16:9) - // but width is OK - don't do anything - - if(((($height * 9) / 16) > $width) && ($float_height)) { - $dest_width = $width; - $dest_height = $height; - } - else { - $dest_width = intval(( $width * $max ) / $height); - $dest_height = $max; - } - } - else { - $dest_width = $width; - $dest_height = $height; - } - } - } - $this->doScaleImage($dest_width,$dest_height); - } - - public function scaleImageUp($min) { - if(!$this->is_valid()) - return FALSE; - - - $width = $this->width; - $height = $this->height; - - $dest_width = $dest_height = 0; - - if((! $width)|| (! $height)) - return FALSE; - - if($width < $min && $height < $min) { - if($width > $height) { - $dest_width = $min; - $dest_height = intval(( $height * $min ) / $width); - } - else { - $dest_width = intval(( $width * $min ) / $height); - $dest_height = $min; - } - } - else { - if( $width < $min ) { - $dest_width = $min; - $dest_height = intval(( $height * $min ) / $width); - } - else { - if( $height < $min ) { - $dest_width = intval(( $width * $min ) / $height); - $dest_height = $min; - } - else { - $dest_width = $width; - $dest_height = $height; - } - } - } - $this->doScaleImage($dest_width,$dest_height); - } - - - public function scaleImageSquare($dim) { - if(!$this->is_valid()) - return FALSE; - $this->doScaleImage($dim,$dim); - } - - - /** - * @brief reads exif data from filename - */ - - public function exif($filename) { - - - if((! function_exists('exif_read_data')) - || (! in_array($this->getType(), [ 'image/jpeg' , 'image/tiff'] ))) { - return false; - } - - /* - * PHP 7.2 allows you to use a stream resource, which should reduce/avoid - * memory exhaustion on large images. - */ - - if(version_compare(PHP_VERSION,'7.2.0') >= 0) { - $f = @fopen($filename,'rb'); - } - else { - $f = $filename; - } - - if($f) { - return @exif_read_data($f,null,true); - } - - return false; - } - - /** - * @brief orients current image based on exif orientation information - */ - - public function orient($exif) { - - if(! ($this->is_valid() && $exif)) { - return false; - } - - $ort = ((array_key_exists('IFD0',$exif)) ? $exif['IFD0']['Orientation'] : $exif['Orientation']); - - if(! $ort) { - return false; - } - - switch($ort) { - case 1: // nothing - break; - case 2: // horizontal flip - $this->flip(); - break; - case 3: // 180 rotate left - $this->rotate(180); - break; - case 4: // vertical flip - $this->flip(false, true); - break; - case 5: // vertical flip + 90 rotate right - $this->flip(false, true); - $this->rotate(-90); - break; - case 6: // 90 rotate right - $this->rotate(-90); - break; - case 7: // horizontal flip + 90 rotate right - $this->flip(); - $this->rotate(-90); - break; - case 8: // 90 rotate left - $this->rotate(90); - break; - default: - break; - } - - return true; - } - - - public function save($arr, $skipcheck = false) { - - if(! ($skipcheck || $this->is_valid())) { - logger('attempt to store invalid photo.'); - return false; - } - - $p = array(); - - $p['aid'] = ((intval($arr['aid'])) ? intval($arr['aid']) : 0); - $p['uid'] = ((intval($arr['uid'])) ? intval($arr['uid']) : 0); - $p['xchan'] = (($arr['xchan']) ? $arr['xchan'] : ''); - $p['resource_id'] = (($arr['resource_id']) ? $arr['resource_id'] : ''); - $p['filename'] = (($arr['filename']) ? $arr['filename'] : ''); - $p['mimetype'] = (($arr['mimetype']) ? $arr['mimetype'] : $this->getType()); - $p['album'] = (($arr['album']) ? $arr['album'] : ''); - $p['imgscale'] = ((intval($arr['imgscale'])) ? intval($arr['imgscale']) : 0); - $p['allow_cid'] = (($arr['allow_cid']) ? $arr['allow_cid'] : ''); - $p['allow_gid'] = (($arr['allow_gid']) ? $arr['allow_gid'] : ''); - $p['deny_cid'] = (($arr['deny_cid']) ? $arr['deny_cid'] : ''); - $p['deny_gid'] = (($arr['deny_gid']) ? $arr['deny_gid'] : ''); - $p['edited'] = (($arr['edited']) ? $arr['edited'] : datetime_convert()); - $p['title'] = (($arr['title']) ? $arr['title'] : ''); - $p['description'] = (($arr['description']) ? $arr['description'] : ''); - $p['photo_usage'] = intval($arr['photo_usage']); - $p['os_storage'] = intval($arr['os_storage']); - $p['os_path'] = $arr['os_path']; - $p['os_syspath'] = ((array_key_exists('os_syspath',$arr)) ? $arr['os_syspath'] : ''); - $p['display_path'] = (($arr['display_path']) ? $arr['display_path'] : ''); - $p['width'] = (($arr['width']) ? $arr['width'] : $this->getWidth()); - $p['height'] = (($arr['height']) ? $arr['height'] : $this->getHeight()); - $p['expires'] = (($arr['expires']) ? $arr['expires'] : gmdate('Y-m-d H:i:s', time() + get_config('system','photo_cache_time', 86400))); - - if(! intval($p['imgscale'])) - logger('save: ' . print_r($arr,true), LOGGER_DATA); - - $x = q("select id, created from photo where resource_id = '%s' and uid = %d and xchan = '%s' and imgscale = %d limit 1", - dbesc($p['resource_id']), - intval($p['uid']), - dbesc($p['xchan']), - intval($p['imgscale']) - ); - - if($x) { - $p['created'] = (($x['created']) ? $x['created'] : $p['edited']); - $r = q("UPDATE photo set - aid = %d, - uid = %d, - xchan = '%s', - resource_id = '%s', - created = '%s', - edited = '%s', - filename = '%s', - mimetype = '%s', - album = '%s', - height = %d, - width = %d, - content = '%s', - os_storage = %d, - filesize = %d, - imgscale = %d, - photo_usage = %d, - title = '%s', - description = '%s', - os_path = '%s', - display_path = '%s', - allow_cid = '%s', - allow_gid = '%s', - deny_cid = '%s', - deny_gid = '%s', - expires = '%s' - where id = %d", - - intval($p['aid']), - intval($p['uid']), - dbesc($p['xchan']), - dbesc($p['resource_id']), - dbescdate($p['created']), - dbescdate($p['edited']), - dbesc(basename($p['filename'])), - dbesc($p['mimetype']), - dbesc($p['album']), - intval($p['height']), - intval($p['width']), - (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), - intval($p['os_storage']), - (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), - intval($p['imgscale']), - intval($p['photo_usage']), - dbesc($p['title']), - dbesc($p['description']), - dbesc($p['os_path']), - dbesc($p['display_path']), - dbesc($p['allow_cid']), - dbesc($p['allow_gid']), - dbesc($p['deny_cid']), - dbesc($p['deny_gid']), - dbescdate($p['expires']), - intval($x[0]['id']) - ); - } - else { - $p['created'] = (($arr['created']) ? $arr['created'] : $p['edited']); - $r = q("INSERT INTO photo - ( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid, expires ) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", - intval($p['aid']), - intval($p['uid']), - dbesc($p['xchan']), - dbesc($p['resource_id']), - dbescdate($p['created']), - dbescdate($p['edited']), - dbesc(basename($p['filename'])), - dbesc($p['mimetype']), - dbesc($p['album']), - intval($p['height']), - intval($p['width']), - (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), - intval($p['os_storage']), - (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), - intval($p['imgscale']), - intval($p['photo_usage']), - dbesc($p['title']), - dbesc($p['description']), - dbesc($p['os_path']), - dbesc($p['display_path']), - dbesc($p['allow_cid']), - dbesc($p['allow_gid']), - dbesc($p['deny_cid']), - dbesc($p['deny_gid']), - dbescdate($p['expires']) - ); - } - logger('photo save ' . $p['imgscale'] . ' returned ' . intval($r)); - return $r; - } - -} - - - /** - * Guess image mimetype from filename or from Content-Type header + * @brief Guess image mimetype from filename or from Content-Type header. * - * @arg $filename string Image filename - * @arg $headers string Headers to check for Content-Type (from curl request) + * @param string $filename + * Image filename + * @param string $headers (optional) + * Headers to check for Content-Type (from curl request) + * @return null|string Guessed mimetype */ - function guess_image_type($filename, $headers = '') { // logger('Photo: guess_image_type: '.$filename . ($headers?' from curl headers':''), LOGGER_DEBUG); $type = null; - if ($headers) { - $hdrs=array(); - $h = explode("\n",$headers); + $m = null; + + if($headers) { + $hdrs = []; + $h = explode("\n", $headers); foreach ($h as $l) { - list($k,$v) = array_map("trim", explode(":", trim($l), 2)); + list($k, $v) = array_map('trim', explode(':', trim($l), 2)); $hdrs[strtolower($k)] = $v; } - logger('Curl headers: '.var_export($hdrs, true), LOGGER_DEBUG); - if (array_key_exists('content-type', $hdrs)) { + logger('Curl headers: ' .var_export($hdrs, true), LOGGER_DEBUG); + if(array_key_exists('content-type', $hdrs)) { $ph = photo_factory(''); $types = $ph->supportedTypes(); @@ -498,13 +86,13 @@ function guess_image_type($filename, $headers = '') { } } - if (is_null($type)){ + if(is_null($type)){ $ignore_imagick = get_config('system', 'ignore_imagick'); // Guessing from extension? Isn't that... dangerous? if(class_exists('Imagick') && file_exists($filename) && is_readable($filename) && !$ignore_imagick) { $v = Imagick::getVersion(); preg_match('/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $m); - if(version_compare($m[1],'6.6.7') >= 0) { + if(version_compare($m[1], '6.6.7') >= 0) { /** * Well, this not much better, * but at least it comes from the data inside the image, @@ -516,7 +104,7 @@ function guess_image_type($filename, $headers = '') { else { // earlier imagick versions have issues with scaling png's // don't log this because it will just fill the logfile. - // leave this note here so those who are looking for why + // leave this note here so those who are looking for why // we aren't using imagick can find it } } @@ -532,7 +120,7 @@ function guess_image_type($filename, $headers = '') { } } - if(is_null($type) && (strpos($filename,'http') === false)) { + if(is_null($type) && (strpos($filename, 'http') === false)) { $size = getimagesize($filename); $ph = photo_factory(''); $types = $ph->supportedTypes(); @@ -551,33 +139,36 @@ function guess_image_type($filename, $headers = '') { } logger('Photo: guess_image_type: filename = ' . $filename . ' type = ' . $type, LOGGER_DEBUG); - return $type; + return $type; } - -function delete_thing_photo($url,$ob_hash) { +/** + * @brief Delete thing photo from database. + * + * @param string $url + * @param string $ob_hash + * @return void + */ +function delete_thing_photo($url, $ob_hash) { $hash = basename($url); - $hash = substr($hash,0,strpos($hash,'-')); + $hash = substr($hash, 0, strpos($hash, '-')); - // hashes should be 32 bytes. + // hashes should be 32 bytes. if((! $ob_hash) || (strlen($hash) < 16)) - return; + return; - $r = q("delete from photo where xchan = '%s' and photo_usage = %d and resource_id = '%s'", + q("delete from photo where xchan = '%s' and photo_usage = %d and resource_id = '%s'", dbesc($ob_hash), intval(PHOTO_THING), dbesc($hash) ); - } - - /** - * @brief fetches an photo from external site and prepares its miniatures. + * @brief Fetches a photo from external site and prepares its miniatures. * * @param string $photo * external URL to fetch base image @@ -596,223 +187,215 @@ function delete_thing_photo($url,$ob_hash) { * * \e boolean \b 4 => TRUE if fetch failure * * \e string \b 5 => modification date */ +function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { + $modified = ''; + $o = null; + + $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); + $album = (($thing) ? 'Things' : 'Contact Photos'); + + logger('Updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); + + if($thing) { + $hash = photo_new_resource(); + } else { + $r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", dbesc($xchan), intval(PHOTO_XCHAN)); + if($r) { + $hash = $r[0]['resource_id']; + $modified = $r[0]['edited']; + $type = $r[0]['mimetype']; + } else { + $hash = photo_new_resource(); + } + } -function import_xchan_photo($photo,$xchan,$thing = false,$force = false) { - - $modified = ''; - - $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); - $album = (($thing) ? 'Things' : 'Contact Photos'); - - logger('import_xchan_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); - - if($thing) { - $hash = photo_new_resource(); - } - else { - $r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", - dbesc($xchan), - intval(PHOTO_XCHAN) - ); - if($r) { - $hash = $r[0]['resource_id']; - $modified = $r[0]['edited']; - $type = $r[0]['mimetype']; - } - else { - $hash = photo_new_resource(); - } - } - - $photo_failure = false; - $img_str = ''; - - if($photo) { - $filename = basename($photo); - - if($force || $modified == '') { - $result = z_fetch_url($photo,true); - } - else { - $h = array('headers' => array("If-Modified-Since: " . gmdate("D, d M Y H:i:s", strtotime($modified . "Z")) . " GMT")); - $result = z_fetch_url($photo,true,0,$h); - } - - if($result['success']) { - $img_str = $result['body']; - $type = guess_image_type($photo, $result['header']); - $modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time())); - if(is_null($type)) - $photo_failure = true; - } - elseif($result['return_code'] == 304) { - $photo = z_root() . '/photo/' . $hash . '-4'; - $thumb = z_root() . '/photo/' . $hash . '-5'; - $micro = z_root() . '/photo/' . $hash . '-6'; - } - else { - $photo_failure = true; - } - - } - else - $photo_failure = true; - - if(! $photo_failure && $result['return_code'] != 304) { - $img = photo_factory($img_str, $type); - if($img->is_valid()) { - $width = $img->getWidth(); - $height = $img->getHeight(); - - if($width && $height) { - if(($width / $height) > 1.2) { - // crop out the sides - $margin = $width - $height; - $img->cropImage(300,($margin / 2),0,$height,$height); - } - elseif(($height / $width) > 1.2) { - // crop out the bottom - $margin = $height - $width; - $img->cropImage(300,0,0,$width,$width); - - } - else { - $img->scaleImageSquare(300); - } - - } - else - $photo_failure = true; - - $p = array( - 'xchan' => $xchan, - 'resource_id' => $hash, - 'filename' => basename($photo), - 'album' => $album, - 'photo_usage' => $flags, - 'imgscale' => 4, - 'edited' => $modified - ); - - $r = $img->save($p); - - if($r === false) - $photo_failure = true; - - $img->scaleImage(80); - $p['imgscale'] = 5; - - $r = $img->save($p); - - if($r === false) - $photo_failure = true; - - $img->scaleImage(48); - $p['imgscale'] = 6; - - $r = $img->save($p); - - if($r === false) - $photo_failure = true; - - $photo = z_root() . '/photo/' . $hash . '-4'; - $thumb = z_root() . '/photo/' . $hash . '-5'; - $micro = z_root() . '/photo/' . $hash . '-6'; - } - else { - logger('import_xchan_photo: invalid image from ' . $photo); - $photo_failure = true; - } - } - if($photo_failure) { - $default = get_default_profile_photo(); - $photo = z_root() . '/' . $default; - $thumb = z_root() . '/' . get_default_profile_photo(80); - $micro = z_root() . '/' . get_default_profile_photo(48); - $type = 'image/png'; - $modified = gmdate('Y-m-d H:i:s', filemtime($default)); - } - - logger('HTTP code: ' . $result['return_code'] . '; modified: ' . $modified . '; failure: ' . ($photo_failure ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG); - return(array($photo,$thumb,$micro,$type,$photo_failure,$modified)); - -} - -function import_channel_photo_from_url($photo,$aid,$uid) { + $photo_failure = false; + $img_str = ''; if($photo) { - $filename = basename($photo); - $result = z_fetch_url($photo,true); + if($force || $modified == '') { + $result = z_fetch_url($photo, true); + } else { + $h = [ + 'headers' => [ + 'If-Modified-Since: ' . gmdate('D, d M Y H:i:s', strtotime($modified . 'Z')) . ' GMT' + ] + ]; + $result = z_fetch_url($photo, true, 0, $h); + } if($result['success']) { $img_str = $result['body']; $type = guess_image_type($photo, $result['header']); + $modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time())); + if(is_null($type)) + $photo_failure = true; + } elseif($result['return_code'] == 304) { + $photo = z_root() . '/photo/' . $hash . '-4'; + $thumb = z_root() . '/photo/' . $hash . '-5'; + $micro = z_root() . '/photo/' . $hash . '-6'; + } else { + $photo_failure = true; + } + } else { + $photo_failure = true; + } + + if(!$photo_failure && $result['return_code'] != 304) { + $img = photo_factory($img_str, $type); + if($img->is_valid()) { + $width = $img->getWidth(); + $height = $img->getHeight(); + + if($width && $height) { + if(($width / $height) > 1.2) { + // crop out the sides + $margin = $width - $height; + $img->cropImage(300, ($margin / 2), 0, $height, $height); + } elseif(($height / $width) > 1.2) { + // crop out the bottom + $margin = $height - $width; + $img->cropImage(300, 0, 0, $width, $width); + } else { + $img->scaleImageSquare(300); + } + } else { + $photo_failure = true; + } - if(is_null($type)) - $photo_failure = true; + $p = [ + 'xchan' => $xchan, + 'resource_id' => $hash, + 'filename' => basename($photo), + 'album' => $album, + 'photo_usage' => $flags, + 'imgscale' => 4, + 'edited' => $modified, + ]; + + $r = $img->save($p); + if($r === false) + $photo_failure = true; + + $img->scaleImage(80); + $p['imgscale'] = 5; + $r = $img->save($p); + if($r === false) + $photo_failure = true; + + $img->scaleImage(48); + $p['imgscale'] = 6; + $r = $img->save($p); + if($r === false) + $photo_failure = true; + + $photo = z_root() . '/photo/' . $hash . '-4'; + $thumb = z_root() . '/photo/' . $hash . '-5'; + $micro = z_root() . '/photo/' . $hash . '-6'; + } else { + logger('Invalid image from ' . $photo); + $photo_failure = true; } } - else { - $photo_failure = true; + if($photo_failure) { + $default = get_default_profile_photo(); + $photo = z_root() . '/' . $default; + $thumb = z_root() . '/' . get_default_profile_photo(80); + $micro = z_root() . '/' . get_default_profile_photo(48); + $type = 'image/png'; + $modified = gmdate('Y-m-d H:i:s', filemtime($default)); } - import_channel_photo($img_str,$type,$aid,$uid); + logger('HTTP code: ' . $result['return_code'] . '; modified: ' . $modified + . '; failure: ' . ($photo_failure ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG); - return $type; + return([$photo, $thumb, $micro, $type, $photo_failure, $modified]); } +/** + * @brief Import channel photo from a URL. + * + * @param string $photo URL to a photo + * @param int $aid + * @param int $uid channel_id + * @return null|string Guessed image mimetype or null. + */ +function import_channel_photo_from_url($photo, $aid, $uid) { + $type = null; -function import_channel_photo($photo,$type,$aid,$uid) { + if($photo) { + $result = z_fetch_url($photo, true); - logger('import_channel_photo: importing channel photo for ' . $uid, LOGGER_DEBUG); + if($result['success']) { + $img_str = $result['body']; + $type = guess_image_type($photo, $result['header']); - $hash = photo_new_resource(); + import_channel_photo($img_str, $type, $aid, $uid); + } + } - $photo_failure = false; + return $type; +} +/** + * @brief Import a channel photo and prepare its miniatures. + * + * @param string $photo Image data + * @param string $type + * @param int $aid + * @param int $uid channel_id + * @return boolean|string false on failure, otherwise resource_id of photo + */ +function import_channel_photo($photo, $type, $aid, $uid) { + logger('Importing channel photo for ' . $uid, LOGGER_DEBUG); + + $photo_failure = false; + $hash = photo_new_resource(); $filename = $hash; $img = photo_factory($photo, $type); if($img->is_valid()) { + // config array for image save method + $p = [ + 'aid' => $aid, + 'uid' => $uid, + 'resource_id' => $hash, + 'filename' => $filename, + 'album' => t('Profile Photos'), + 'photo_usage' => PHOTO_PROFILE, + 'imgscale' => 4, + ]; + + // photo size $img->scaleImageSquare(300); - - $p = array('aid' => $aid, 'uid' => $uid, 'resource_id' => $hash, 'filename' => $filename, 'album' => t('Profile Photos'), 'photo_usage' => PHOTO_PROFILE, 'imgscale' => 4); - $r = $img->save($p); - if($r === false) $photo_failure = true; + // thumb size $img->scaleImage(80); $p['imgscale'] = 5; - $r = $img->save($p); - if($r === false) $photo_failure = true; + // micro size $img->scaleImage(48); $p['imgscale'] = 6; - $r = $img->save($p); - if($r === false) $photo_failure = true; - } - else { - logger('import_channel_photo: invalid image.'); + } else { + logger('Invalid image.'); $photo_failure = true; } - //return(($photo_failure)? false : true); - if($photo_failure) return false; else return $hash; - } diff --git a/include/photo/photo_gd.php b/include/photo/photo_gd.php deleted file mode 100644 index e98ac2827..000000000 --- a/include/photo/photo_gd.php +++ /dev/null @@ -1,162 +0,0 @@ -<?php /** @file */ - - -require_once('include/photo/photo_driver.php'); - - -class photo_gd extends photo_driver { - - function supportedTypes() { - $t = array(); - $t['image/jpeg'] ='jpg'; - if (imagetypes() & IMG_PNG) $t['image/png'] = 'png'; - if (imagetypes() & IMG_GIF) $t['image/gif'] = 'gif'; - return $t; - - } - - function load($data, $type) { - $this->valid = false; - if(! $data) - return; - - $this->image = @imagecreatefromstring($data); - if($this->image !== FALSE) { - $this->valid = true; - $this->setDimensions(); - imagealphablending($this->image, false); - imagesavealpha($this->image, true); - } - } - - function setDimensions() { - $this->width = imagesx($this->image); - $this->height = imagesy($this->image); - } - - - public function clearexif() { - return; - } - - - public function destroy() { - if($this->is_valid()) { - imagedestroy($this->image); - } - } - - public function getImage() { - if(!$this->is_valid()) - return FALSE; - - return $this->image; - } - - public function doScaleImage($dest_width,$dest_height) { - - $dest = imagecreatetruecolor( $dest_width, $dest_height ); - $width = imagesx($this->image); - $height = imagesy($this->image); - - imagealphablending($dest, false); - imagesavealpha($dest, true); - if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha - imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height); - if($this->image) - imagedestroy($this->image); - $this->image = $dest; - $this->setDimensions(); - } - - public function rotate($degrees) { - if(!$this->is_valid()) - return FALSE; - - $this->image = imagerotate($this->image,$degrees,0); - $this->setDimensions(); - } - - public function flip($horiz = true, $vert = false) { - if(!$this->is_valid()) - return FALSE; - - $w = imagesx($this->image); - $h = imagesy($this->image); - $flipped = imagecreate($w, $h); - if($horiz) { - for ($x = 0; $x < $w; $x++) { - imagecopy($flipped, $this->image, $x, 0, $w - $x - 1, 0, 1, $h); - } - } - if($vert) { - for ($y = 0; $y < $h; $y++) { - imagecopy($flipped, $this->image, 0, $y, 0, $h - $y - 1, $w, 1); - } - } - $this->image = $flipped; - $this->setDimensions(); // Shouldn't really be necessary - } - - public function cropImage($max,$x,$y,$w,$h) { - if(!$this->is_valid()) - return FALSE; - - $dest = imagecreatetruecolor( $max, $max ); - imagealphablending($dest, false); - imagesavealpha($dest, true); - if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha - imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $max, $max, $w, $h); - if($this->image) - imagedestroy($this->image); - $this->image = $dest; - $this->setDimensions(); - } - - public function cropImageRect($maxx,$maxy,$x,$y,$w,$h) { - if(!$this->is_valid()) - return FALSE; - - $dest = imagecreatetruecolor( $maxx, $maxy ); - imagealphablending($dest, false); - imagesavealpha($dest, true); - if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha - imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $maxx, $maxy, $w, $h); - if($this->image) - imagedestroy($this->image); - $this->image = $dest; - $this->setDimensions(); - } - - - - public function imageString() { - if(!$this->is_valid()) - return FALSE; - - $quality = FALSE; - - ob_start(); - - switch($this->getType()){ - case "image/png": - $quality = get_config('system','png_quality'); - if((! $quality) || ($quality > 9)) - $quality = PNG_QUALITY; - imagepng($this->image,NULL, $quality); - break; - case "image/jpeg": - default: - $quality = get_config('system','jpeg_quality'); - if((! $quality) || ($quality > 100)) - $quality = JPEG_QUALITY; - imagejpeg($this->image,NULL,$quality); - break; - } - $string = ob_get_contents(); - ob_end_clean(); - - return $string; - } - -} diff --git a/include/photo/photo_imagick.php b/include/photo/photo_imagick.php deleted file mode 100644 index cb3ad27fb..000000000 --- a/include/photo/photo_imagick.php +++ /dev/null @@ -1,213 +0,0 @@ -<?php /** @file */ - - -require_once('include/photo/photo_driver.php'); - - -class photo_imagick extends photo_driver { - - - function supportedTypes() { - return array( - 'image/jpeg' => 'jpg', - 'image/png' => 'png', - 'image/gif' => 'gif' - ); - } - - public function get_FormatsMap() { - return array( - 'image/jpeg' => 'JPG', - 'image/png' => 'PNG', - 'image/gif' => 'GIF' - ); - } - - - function load($data, $type) { - $this->valid = false; - $this->image = new Imagick(); - - if(! $data) - return; - - try { - $this->image->readImageBlob($data); - } - catch (Exception $e) { - logger('imagick readImageBlob() exception:' . print_r($e,true)); - return; - } - - /** - * Setup the image to the format it will be saved to - */ - - $map = $this->get_FormatsMap(); - $format = $map[$type]; - - if($this->image) { - $this->image->setFormat($format); - - // Always coalesce, if it is not a multi-frame image it won't hurt anyway - $this->image = $this->image->coalesceImages(); - - - $this->valid = true; - $this->setDimensions(); - - /** - * setup the compression here, so we'll do it only once - */ - switch($this->getType()) { - case "image/png": - $quality = get_config('system','png_quality'); - if((! $quality) || ($quality > 9)) - $quality = PNG_QUALITY; - /** - * From http://www.imagemagick.org/script/command-line-options.php#quality: - * - * 'For the MNG and PNG image formats, the quality value sets - * the zlib compression level (quality / 10) and filter-type (quality % 10). - * The default PNG "quality" is 75, which means compression level 7 with adaptive PNG filtering, - * unless the image has a color map, in which case it means compression level 7 with no PNG filtering' - */ - $quality = $quality * 10; - $this->image->setCompressionQuality($quality); - break; - case "image/jpeg": - $quality = get_config('system','jpeg_quality'); - if((! $quality) || ($quality > 100)) - $quality = JPEG_QUALITY; - $this->image->setCompressionQuality($quality); - default: - break; - - } - } - } - - public function destroy() { - if($this->is_valid()) { - $this->image->clear(); - $this->image->destroy(); - } - } - - - public function setDimensions() { - $this->width = $this->image->getImageWidth(); - $this->height = $this->image->getImageHeight(); - } - - - public function clearexif() { - - $profiles = $this->image->getImageProfiles("icc", true); - - $this->image->stripImage(); - - if(!empty($profiles)) { - $this->image->profileImage("icc", $profiles['icc']); - } - } - - - - public function getImage() { - if(!$this->is_valid()) - return FALSE; - - $this->image = $this->image->deconstructImages(); - return $this->image; - } - - public function doScaleImage($dest_width,$dest_height) { - - /** - * If it is not animated, there will be only one iteration here, - * so don't bother checking - */ - // Don't forget to go back to the first frame - $this->image->setFirstIterator(); - do { - $this->image->scaleImage($dest_width, $dest_height); - } while ($this->image->nextImage()); - - $this->setDimensions(); - } - - public function rotate($degrees) { - if(!$this->is_valid()) - return FALSE; - - $this->image->setFirstIterator(); - do { - // ImageMagick rotates in the opposite direction of imagerotate() - $this->image->rotateImage(new ImagickPixel(), -$degrees); - } while ($this->image->nextImage()); - - $this->setDimensions(); - } - - public function flip($horiz = true, $vert = false) { - if(!$this->is_valid()) - return FALSE; - - $this->image->setFirstIterator(); - do { - if($horiz) $this->image->flipImage(); - if($vert) $this->image->flopImage(); - } while ($this->image->nextImage()); - - $this->setDimensions(); // Shouldn't really be necessary - } - - public function cropImage($max,$x,$y,$w,$h) { - if(!$this->is_valid()) - return FALSE; - - $this->image->setFirstIterator(); - do { - $this->image->cropImage($w, $h, $x, $y); - /** - * We need to remove the canvas, - * or the image is not resized to the crop: - * http://php.net/manual/en/imagick.cropimage.php#97232 - */ - $this->image->setImagePage(0, 0, 0, 0); - } while ($this->image->nextImage()); - - $this->doScaleImage($max,$max); - } - - public function cropImageRect($maxx,$maxy,$x,$y,$w,$h) { - if(!$this->is_valid()) - return FALSE; - - $this->image->setFirstIterator(); - do { - $this->image->cropImage($w, $h, $x, $y); - /** - * We need to remove the canvas, - * or the image is not resized to the crop: - * http://php.net/manual/en/imagick.cropimage.php#97232 - */ - $this->image->setImagePage(0, 0, 0, 0); - } while ($this->image->nextImage()); - - $this->doScaleImage($maxx,$maxy); - } - - public function imageString() { - if(!$this->is_valid()) - return FALSE; - - /* Clean it */ - $this->image = $this->image->deconstructImages(); - return $this->image->getImagesBlob(); - } - - - -} |