diff --git a/boot.php b/boot.php
index 7961efc4a8..0e8f017f46 100644
--- a/boot.php
+++ b/boot.php
@@ -11,7 +11,7 @@ require_once('include/cache.php');
define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_VERSION', '3.0.1366' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
-define ( 'DB_UPDATE_VERSION', 1148 );
+define ( 'DB_UPDATE_VERSION', 1149 );
define ( 'EOL', "
\r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
@@ -28,6 +28,11 @@ define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
*/
define ( 'JPEG_QUALITY', 100 );
+/**
+ * $a->config['system']['png_quality'] from 0 (uncompressed) to 9
+ */
+define ( 'PNG_QUALITY', 8 );
+
/**
* Not yet used
diff --git a/include/Photo.php b/include/Photo.php
index fce5599996..ffefc37eca 100644
--- a/include/Photo.php
+++ b/include/Photo.php
@@ -7,14 +7,34 @@ class Photo {
private $width;
private $height;
private $valid;
+ private $type;
+ private $types;
- public function __construct($data) {
+ /**
+ * supported mimetypes and corresponding file extensions
+ */
+ static function supportedTypes() {
+ $t = array();
+ $t['image/jpeg'] ='jpg';
+ if (imagetypes() & IMG_PNG) $t['image/png'] = 'png';
+ return $t;
+ }
+
+ public function __construct($data, $type="image/jpeg") {
+
+ $this->types = $this->supportedTypes();
+ if (!array_key_exists($type,$this->types)){
+ $type='image/jpeg';
+ }
$this->valid = false;
+ $this->type = $type;
$this->image = @imagecreatefromstring($data);
if($this->image !== FALSE) {
$this->width = imagesx($this->image);
$this->height = imagesy($this->image);
$this->valid = true;
+ imagealphablending($this->image, false);
+ imagesavealpha($this->image, true);
}
}
@@ -38,6 +58,13 @@ class Photo {
public function getImage() {
return $this->image;
}
+
+ public function getType() {
+ return $this->type;
+ }
+ public function getExt() {
+ return $this->types[$this->type];
+ }
public function scaleImage($max) {
@@ -78,6 +105,9 @@ class Photo {
$dest = imagecreatetruecolor( $dest_width, $dest_height );
+ imagealphablending($dest->image, 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);
@@ -134,6 +164,9 @@ class Photo {
$dest = imagecreatetruecolor( $dest_width, $dest_height );
+ imagealphablending($dest->image, 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);
@@ -148,6 +181,9 @@ class Photo {
public function scaleImageSquare($dim) {
$dest = imagecreatetruecolor( $dim, $dim );
+ imagealphablending($dest->image, 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, $dim, $dim, $this->width, $this->height);
if($this->image)
imagedestroy($this->image);
@@ -159,6 +195,9 @@ class Photo {
public function cropImage($max,$x,$y,$w,$h) {
$dest = imagecreatetruecolor( $max, $max );
+ imagealphablending($dest->image, 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);
@@ -168,20 +207,38 @@ class Photo {
}
public function saveImage($path) {
- $quality = get_config('system','jpeg_quality');
- if((! $quality) || ($quality > 100))
- $quality = JPEG_QUALITY;
- imagejpeg($this->image,$path,$quality);
+ switch($this->type){
+ case "image/png":
+ $quality = get_config('system','png_quality');
+ if((! $quality) || ($quality > 9))
+ $quality = PNG_QUALITY;
+ imagepng($this->image, $path, $quality);
+ break;
+ default:
+ $quality = get_config('system','jpeg_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = JPEG_QUALITY;
+ imagejpeg($this->image,$path,$quality);
+ }
+
}
public function imageString() {
ob_start();
+ switch($this->type){
+ case "image/png":
+ $quality = get_config('system','png_quality');
+ if((! $quality) || ($quality > 9))
+ $quality = PNG_QUALITY;
+ imagepng($this->image,NULL, $quality);
+ break;
+ default:
+ $quality = get_config('system','jpeg_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = JPEG_QUALITY;
- $quality = get_config('system','jpeg_quality');
- if((! $quality) || ($quality > 100))
- $quality = JPEG_QUALITY;
-
- imagejpeg($this->image,NULL,$quality);
+ imagejpeg($this->image,NULL,$quality);
+ }
$s = ob_get_contents();
ob_end_clean();
return $s;
@@ -200,8 +257,8 @@ class Photo {
$guid = get_guid();
$r = q("INSERT INTO `photo`
- ( `uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, `album`, `height`, `width`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, '%s', '%s', '%s', '%s' )",
+ ( `uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
+ VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, '%s', '%s', '%s', '%s' )",
intval($uid),
intval($cid),
dbesc($guid),
@@ -209,6 +266,7 @@ class Photo {
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(basename($filename)),
+ dbesc($this->type),
dbesc($album),
intval($this->height),
intval($this->width),
@@ -230,6 +288,38 @@ class Photo {
}}
+/**
+ * Guess image mimetype from filename or from Content-Type header
+ *
+ * @arg $filename string Image filename
+ * @arg $fromcurl boolean Check Content-Type header from curl request
+ */
+function guess_image_type($filename, $fromcurl=false) {
+ $type = null;
+ if ($fromcurl) {
+ $a = get_app();
+ $headers=array();
+ $h = explode("\n",$a->get_curl_headers());
+ foreach ($h as $l) {
+ list($k,$v) = array_map("trim", explode(":", trim($l), 2));
+ $headers[$k] = $v;
+ }
+ if (array_key_exists('Content-Type', $headers))
+ $type = $headers['Content-Type'];
+ }
+ if (is_null($type)){
+ $ext = pathinfo($filename, PATHINFO_EXTENSION);
+ $types = Photo::supportedTypes();
+ foreach ($types as $m=>$e){
+ if ($ext==$e) return $m;
+ }
+ $type = "image/jpeg";
+ }
+
+ return $type;
+
+}
+
function import_profile_photo($photo,$uid,$cid) {
$a = get_app();
@@ -238,7 +328,12 @@ function import_profile_photo($photo,$uid,$cid) {
$filename = basename($photo);
$img_str = fetch_url($photo,true);
- $img = new Photo($img_str);
+
+ // guess mimetype from headers or filename
+ $type = guess_image_type($photo,true);
+
+
+ $img = new Photo($img_str, $type);
if($img->is_valid()) {
$img->scaleImageSquare(175);
@@ -266,9 +361,9 @@ function import_profile_photo($photo,$uid,$cid) {
- $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
- $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
- $micro = $a->get_baseurl() . '/photo/' . $hash . '-6.jpg';
+ $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt();
+ $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt();
+ $micro = $a->get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt();
}
else
$photo_failure = true;
diff --git a/include/items.php b/include/items.php
index 66e219ddf2..15c043e922 100755
--- a/include/items.php
+++ b/include/items.php
@@ -1346,7 +1346,11 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
}
$img_str = fetch_url($photo_url,true);
- $img = new Photo($img_str);
+ // guess mimetype from headers or filename
+ $type = guess_image_type($photo_url,true);
+
+
+ $img = new Photo($img_str, $type);
if($img->is_valid()) {
if($have_photo) {
q("DELETE FROM `photo` WHERE `resource-id` = '%s' AND `contact-id` = %d AND `uid` = %d",
@@ -1372,9 +1376,9 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s'
WHERE `uid` = %d AND `id` = %d LIMIT 1",
dbesc(datetime_convert()),
- dbesc($a->get_baseurl() . '/photo/' . $hash . '-4.jpg'),
- dbesc($a->get_baseurl() . '/photo/' . $hash . '-5.jpg'),
- dbesc($a->get_baseurl() . '/photo/' . $hash . '-6.jpg'),
+ dbesc($a->get_baseurl() . '/photo/' . $hash . '-4.'.$img->getExt()),
+ dbesc($a->get_baseurl() . '/photo/' . $hash . '-5.'.$img->getExt()),
+ dbesc($a->get_baseurl() . '/photo/' . $hash . '-6.'.$img->getExt()),
intval($contact['uid']),
intval($contact['id'])
);
diff --git a/include/network.php b/include/network.php
index eeb2460d14..446413cd83 100644
--- a/include/network.php
+++ b/include/network.php
@@ -807,8 +807,11 @@ function scale_external_images($s,$include_link = true) {
if(stristr($mtch[1],$hostname))
continue;
$i = fetch_url($mtch[1]);
+ // guess mimetype from headers or filename
+ $type = guess_image_type($mtch[1],true);
+
if($i) {
- $ph = new Photo($i);
+ $ph = new Photo($i, $type);
if($ph->is_valid()) {
$orig_width = $ph->getWidth();
$orig_height = $ph->getHeight();
diff --git a/include/user.php b/include/user.php
index af43a2b52c..2477438bf4 100644
--- a/include/user.php
+++ b/include/user.php
@@ -284,7 +284,11 @@ function create_user($arr) {
$filename = basename($photo);
$img_str = fetch_url($photo,true);
- $img = new Photo($img_str);
+ // guess mimetype from headers or filename
+ $type = guess_image_type($photo,true);
+
+
+ $img = new Photo($img_str, $type);
if($img->is_valid()) {
$img->scaleImageSquare(175);
@@ -324,4 +328,4 @@ function create_user($arr) {
$result['user'] = $u;
return $result;
-}
\ No newline at end of file
+}
diff --git a/mod/parse_url.php b/mod/parse_url.php
index 27dac4d5d3..cdf2223a86 100644
--- a/mod/parse_url.php
+++ b/mod/parse_url.php
@@ -215,8 +215,11 @@ function parse_url_content(&$a) {
$i = fetch_url($image);
if($i) {
+ // guess mimetype from headers or filename
+ $type = guess_image_type($image,true);
+
require_once('include/Photo.php');
- $ph = new Photo($i);
+ $ph = new Photo($i, $type);
if($ph->is_valid()) {
if($ph->getWidth() > 300 || $ph->getHeight() > 300) {
$ph->scaleImage(300);
diff --git a/mod/photo.php b/mod/photo.php
index 3cd8250a9e..e8e74cfde1 100644
--- a/mod/photo.php
+++ b/mod/photo.php
@@ -1,6 +1,7 @@
$e){
+ $photo = str_replace(".$e",'',$photo);
+ }
if(substr($photo,-2,1) == '-') {
$resolution = intval(substr($photo,-1,1));
@@ -119,6 +124,7 @@ function photo_init(&$a) {
if(count($r)) {
$data = $r[0]['data'];
+ $mimetype = $r[0]['type'];
}
else {
@@ -136,6 +142,7 @@ function photo_init(&$a) {
);
if(count($r)) {
$data = file_get_contents('images/nosign.jpg');
+ $mimetype = 'image/jpeg';
$prvcachecontrol = true;
}
}
@@ -148,12 +155,15 @@ function photo_init(&$a) {
case 4:
$data = file_get_contents('images/person-175.jpg');
+ $mimetype = 'image/jpeg';
break;
case 5:
$data = file_get_contents('images/person-80.jpg');
+ $mimetype = 'image/jpeg';
break;
case 6:
$data = file_get_contents('images/person-48.jpg');
+ $mimetype = 'image/jpeg';
break;
default:
killme();
@@ -164,11 +174,11 @@ function photo_init(&$a) {
}
if(isset($customres) && $customres > 0 && $customres < 500) {
- require_once('include/Photo.php');
- $ph = new Photo($data);
+ $ph = new Photo($data, $mimetype);
if($ph->is_valid()) {
$ph->scaleImageSquare($customres);
$data = $ph->imageString();
+ $mimetype = $ph->getType();
}
}
@@ -181,7 +191,7 @@ function photo_init(&$a) {
header_remove('pragma');
}
- header("Content-type: image/jpeg");
+ header("Content-type: ".$mimetype);
if($prvcachecontrol) {
diff --git a/mod/photos.php b/mod/photos.php
index 3ce6f9934d..0723535871 100644
--- a/mod/photos.php
+++ b/mod/photos.php
@@ -5,6 +5,7 @@ require_once('include/acl_selectors.php');
require_once('include/bbcode.php');
require_once('include/security.php');
+
function photos_init(&$a) {
@@ -105,6 +106,8 @@ function photos_post(&$a) {
logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA);
logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA);
+ $phototypes = Photo::supportedTypes();
+
$can_post = false;
$visitor = 0;
@@ -311,7 +314,7 @@ function photos_post(&$a) {
intval($page_owner_uid)
);
if(count($r)) {
- $ph = new Photo($r[0]['data']);
+ $ph = new Photo($r[0]['data'], $r[0]['type']);
if($ph->is_valid()) {
$ph->rotate(270);
@@ -362,6 +365,7 @@ function photos_post(&$a) {
intval($page_owner_uid)
);
if(count($p)) {
+ $ext = $phototypes[$p[0]['type']];
$r = q("UPDATE `photo` SET `desc` = '%s', `album` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource-id` = '%s' AND `uid` = %d",
dbesc($desc),
dbesc($albname),
@@ -386,7 +390,7 @@ function photos_post(&$a) {
$title = '';
$uri = item_new_uri($a->get_hostname(),$page_owner_uid);
-
+
$arr = array();
$arr['uid'] = $page_owner_uid;
@@ -412,7 +416,7 @@ function photos_post(&$a) {
$arr['origin'] = 1;
$arr['body'] = '[url=' . $a->get_baseurl() . '/photos/' . $a->data['user']['nickname'] . '/image/' . $p[0]['resource-id'] . ']'
- . '[img]' . $a->get_baseurl() . '/photo/' . $p[0]['resource-id'] . '-' . $p[0]['scale'] . '.jpg' . '[/img]'
+ . '[img]' . $a->get_baseurl() . '/photo/' . $p[0]['resource-id'] . '-' . $p[0]['scale'] . '.'. $ext . '[/img]'
. '[/url]';
$item_id = item_store($arr);
@@ -581,17 +585,17 @@ function photos_post(&$a) {
$arr['inform'] = $tagged[2];
$arr['origin'] = 1;
$arr['body'] = '[url=' . $tagged[1] . ']' . $tagged[0] . '[/url]' . ' ' . t('was tagged in a') . ' ' . '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . t('photo') . '[/url]' . ' ' . t('by') . ' ' . '[url=' . $owner_record['url'] . ']' . $owner_record['name'] . '[/url]' ;
- $arr['body'] .= "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . '[img]' . $a->get_baseurl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.jpg' . '[/img][/url]' . "\n" ;
+ $arr['body'] .= "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . '[img]' . $a->get_baseurl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.' . $ext . '[/img][/url]' . "\n" ;
$arr['object'] = '' . "\n";
$arr['target'] = '