Support Blurhash
This commit is contained in:
		
					parent
					
						
							
								22e2578b23
							
						
					
				
			
			
				commit
				
					
						a5be5b27e3
					
				
			
		
					 16 changed files with 152 additions and 17 deletions
				
			
		|  | @ -70,7 +70,8 @@ | ||||||
| 		"npm-asset/moment": "^2.24", | 		"npm-asset/moment": "^2.24", | ||||||
| 		"npm-asset/perfect-scrollbar": "0.6.16", | 		"npm-asset/perfect-scrollbar": "0.6.16", | ||||||
| 		"npm-asset/textcomplete": "^0.18.2", | 		"npm-asset/textcomplete": "^0.18.2", | ||||||
| 		"npm-asset/typeahead.js": "^0.11.1" | 		"npm-asset/typeahead.js": "^0.11.1", | ||||||
|  | 		"kornrunner/blurhash": "^1.2" | ||||||
| 	}, | 	}, | ||||||
| 	"repositories": [ | 	"repositories": [ | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								composer.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								composer.lock
									
										
									
										generated
									
									
									
								
							|  | @ -4,7 +4,7 @@ | ||||||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", |         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | ||||||
|         "This file is @generated automatically" |         "This file is @generated automatically" | ||||||
|     ], |     ], | ||||||
|     "content-hash": "2e082bac083ca61cc0c22f7055d690bf", |     "content-hash": "f8e7baec685d20e6aee56978c275d64c", | ||||||
|     "packages": [ |     "packages": [ | ||||||
|         { |         { | ||||||
|             "name": "asika/simple-console", |             "name": "asika/simple-console", | ||||||
|  | @ -1116,6 +1116,50 @@ | ||||||
|             ], |             ], | ||||||
|             "time": "2022-06-20T21:43:03+00:00" |             "time": "2022-06-20T21:43:03+00:00" | ||||||
|         }, |         }, | ||||||
|  |         { | ||||||
|  |             "name": "kornrunner/blurhash", | ||||||
|  |             "version": "v1.2.2", | ||||||
|  |             "source": { | ||||||
|  |                 "type": "git", | ||||||
|  |                 "url": "https://github.com/kornrunner/php-blurhash.git", | ||||||
|  |                 "reference": "bc8a4596cb0a49874f0158696a382ab3933fefe4" | ||||||
|  |             }, | ||||||
|  |             "dist": { | ||||||
|  |                 "type": "zip", | ||||||
|  |                 "url": "https://api.github.com/repos/kornrunner/php-blurhash/zipball/bc8a4596cb0a49874f0158696a382ab3933fefe4", | ||||||
|  |                 "reference": "bc8a4596cb0a49874f0158696a382ab3933fefe4", | ||||||
|  |                 "shasum": "" | ||||||
|  |             }, | ||||||
|  |             "require": { | ||||||
|  |                 "php": "^7.3|^8.0" | ||||||
|  |             }, | ||||||
|  |             "require-dev": { | ||||||
|  |                 "ext-gd": "*", | ||||||
|  |                 "ocramius/package-versions": "^1.4|^2.0", | ||||||
|  |                 "phpstan/phpstan": "^0.12", | ||||||
|  |                 "phpunit/phpunit": "^9", | ||||||
|  |                 "vimeo/psalm": "^4.3" | ||||||
|  |             }, | ||||||
|  |             "type": "library", | ||||||
|  |             "autoload": { | ||||||
|  |                 "psr-4": { | ||||||
|  |                     "kornrunner\\Blurhash\\": "src" | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "notification-url": "https://packagist.org/downloads/", | ||||||
|  |             "license": [ | ||||||
|  |                 "MIT" | ||||||
|  |             ], | ||||||
|  |             "authors": [ | ||||||
|  |                 { | ||||||
|  |                     "name": "Boris Momčilović", | ||||||
|  |                     "email": "boris.momcilovic@gmail.com" | ||||||
|  |                 } | ||||||
|  |             ], | ||||||
|  |             "description": "Pure PHP implementation of Blurhash", | ||||||
|  |             "homepage": "https://github.com/kornrunner/php-blurhash", | ||||||
|  |             "time": "2022-07-13T19:38:39+00:00" | ||||||
|  |         }, | ||||||
|         { |         { | ||||||
|             "name": "league/html-to-markdown", |             "name": "league/html-to-markdown", | ||||||
|             "version": "4.10.0", |             "version": "4.10.0", | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| -- ------------------------------------------ | -- ------------------------------------------ | ||||||
| -- Friendica 2022.12-dev (Giant Rhubarb) | -- Friendica 2022.12-dev (Giant Rhubarb) | ||||||
| -- DB_UPDATE_VERSION 1496 | -- DB_UPDATE_VERSION 1497 | ||||||
| -- ------------------------------------------ | -- ------------------------------------------ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1088,6 +1088,7 @@ CREATE TABLE IF NOT EXISTS `photo` ( | ||||||
| 	`height` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', | 	`height` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', | ||||||
| 	`width` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', | 	`width` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', | ||||||
| 	`datasize` int unsigned NOT NULL DEFAULT 0 COMMENT '', | 	`datasize` int unsigned NOT NULL DEFAULT 0 COMMENT '', | ||||||
|  | 	`blurhash` varbinary(255) COMMENT 'BlurHash representation of the photo', | ||||||
| 	`data` mediumblob NOT NULL COMMENT '', | 	`data` mediumblob NOT NULL COMMENT '', | ||||||
| 	`scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', | 	`scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', | ||||||
| 	`profile` boolean NOT NULL DEFAULT '0' COMMENT '', | 	`profile` boolean NOT NULL DEFAULT '0' COMMENT '', | ||||||
|  | @ -1313,6 +1314,7 @@ CREATE TABLE IF NOT EXISTS `post-media` ( | ||||||
| 	`height` smallint unsigned COMMENT 'Height of the media', | 	`height` smallint unsigned COMMENT 'Height of the media', | ||||||
| 	`width` smallint unsigned COMMENT 'Width of the media', | 	`width` smallint unsigned COMMENT 'Width of the media', | ||||||
| 	`size` bigint unsigned COMMENT 'Media size', | 	`size` bigint unsigned COMMENT 'Media size', | ||||||
|  | 	`blurhash` varbinary(255) COMMENT 'BlurHash representation of the image', | ||||||
| 	`preview` varbinary(512) COMMENT 'Preview URL', | 	`preview` varbinary(512) COMMENT 'Preview URL', | ||||||
| 	`preview-height` smallint unsigned COMMENT 'Height of the preview picture', | 	`preview-height` smallint unsigned COMMENT 'Height of the preview picture', | ||||||
| 	`preview-width` smallint unsigned COMMENT 'Width of the preview picture', | 	`preview-width` smallint unsigned COMMENT 'Width of the preview picture', | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ Fields | ||||||
| | height        |                                                                     | smallint unsigned  | NO   |     | 0                   |                | | | height        |                                                                     | smallint unsigned  | NO   |     | 0                   |                | | ||||||
| | width         |                                                                     | smallint unsigned  | NO   |     | 0                   |                | | | width         |                                                                     | smallint unsigned  | NO   |     | 0                   |                | | ||||||
| | datasize      |                                                                     | int unsigned       | NO   |     | 0                   |                | | | datasize      |                                                                     | int unsigned       | NO   |     | 0                   |                | | ||||||
|  | | blurhash      | BlurHash representation of the photo                                | varbinary(255)     | YES  |     | NULL                |                | | ||||||
| | data          |                                                                     | mediumblob         | NO   |     | NULL                |                | | | data          |                                                                     | mediumblob         | NO   |     | NULL                |                | | ||||||
| | scale         |                                                                     | tinyint unsigned   | NO   |     | 0                   |                | | | scale         |                                                                     | tinyint unsigned   | NO   |     | 0                   |                | | ||||||
| | profile       |                                                                     | boolean            | NO   |     | 0                   |                | | | profile       |                                                                     | boolean            | NO   |     | 0                   |                | | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ Fields | ||||||
| | height          | Height of the media                                                | smallint unsigned | YES  |     | NULL    |                | | | height          | Height of the media                                                | smallint unsigned | YES  |     | NULL    |                | | ||||||
| | width           | Width of the media                                                 | smallint unsigned | YES  |     | NULL    |                | | | width           | Width of the media                                                 | smallint unsigned | YES  |     | NULL    |                | | ||||||
| | size            | Media size                                                         | bigint unsigned   | YES  |     | NULL    |                | | | size            | Media size                                                         | bigint unsigned   | YES  |     | NULL    |                | | ||||||
|  | | blurhash        | BlurHash representation of the image                               | varbinary(255)    | YES  |     | NULL    |                | | ||||||
| | preview         | Preview URL                                                        | varbinary(512)    | YES  |     | NULL    |                | | | preview         | Preview URL                                                        | varbinary(512)    | YES  |     | NULL    |                | | ||||||
| | preview-height  | Height of the preview picture                                      | smallint unsigned | YES  |     | NULL    |                | | | preview-height  | Height of the preview picture                                      | smallint unsigned | YES  |     | NULL    |                | | ||||||
| | preview-width   | Width of the preview picture                                       | smallint unsigned | YES  |     | NULL    |                | | | preview-width   | Width of the preview picture                                       | smallint unsigned | YES  |     | NULL    |                | | ||||||
|  |  | ||||||
|  | @ -94,7 +94,7 @@ class Attachment extends BaseFactory | ||||||
| 	 */ | 	 */ | ||||||
| 	public function createFromPhoto(int $id): array | 	public function createFromPhoto(int $id): array | ||||||
| 	{ | 	{ | ||||||
| 		$photo = Photo::selectFirst(['resource-id', 'uid', 'id', 'title', 'type', 'width', 'height'], ['id' => $id]); | 		$photo = Photo::selectFirst(['resource-id', 'uid', 'id', 'title', 'type', 'width', 'height', 'blurhash'], ['id' => $id]); | ||||||
| 		if (empty($photo)) { | 		if (empty($photo)) { | ||||||
| 			return []; | 			return []; | ||||||
| 		} | 		} | ||||||
|  | @ -104,6 +104,7 @@ class Attachment extends BaseFactory | ||||||
| 			'description' => $photo['title'], | 			'description' => $photo['title'], | ||||||
| 			'width'       => $photo['width'], | 			'width'       => $photo['width'], | ||||||
| 			'height'      => $photo['height'], | 			'height'      => $photo['height'], | ||||||
|  | 			'blurhash'    => $photo['blurhash'], | ||||||
| 		]; | 		]; | ||||||
| 
 | 
 | ||||||
| 		$photoTypes = Images::supportedTypes(); | 		$photoTypes = Images::supportedTypes(); | ||||||
|  |  | ||||||
|  | @ -74,6 +74,7 @@ class Card extends BaseFactory | ||||||
| 				$data['image']         = $attached['preview']; | 				$data['image']         = $attached['preview']; | ||||||
| 				$data['width']         = $attached['preview-width']; | 				$data['width']         = $attached['preview-width']; | ||||||
| 				$data['height']        = $attached['preview-height']; | 				$data['height']        = $attached['preview-height']; | ||||||
|  | 				$data['blurhash']      = $attached['blurhash']; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -76,7 +76,7 @@ class Relation | ||||||
| 	 */ | 	 */ | ||||||
| 	public static function discoverByUser(int $uid) | 	public static function discoverByUser(int $uid) | ||||||
| 	{ | 	{ | ||||||
| 		$contact = Contact::selectFirst(['id', 'url'], ['uid' => $uid, 'self' => true]); | 		$contact = Contact::selectFirst(['id', 'url', 'network'], ['uid' => $uid, 'self' => true]); | ||||||
| 		if (empty($contact)) { | 		if (empty($contact)) { | ||||||
| 			Logger::warning('Self contact for user not found', ['uid' => $uid]); | 			Logger::warning('Self contact for user not found', ['uid' => $uid]); | ||||||
| 			return; | 			return; | ||||||
|  |  | ||||||
|  | @ -436,6 +436,7 @@ class Photo | ||||||
| 			'height' => $image->getHeight(), | 			'height' => $image->getHeight(), | ||||||
| 			'width' => $image->getWidth(), | 			'width' => $image->getWidth(), | ||||||
| 			'datasize' => strlen($image->asString()), | 			'datasize' => strlen($image->asString()), | ||||||
|  | 			'blurhash' => $image->getBlurHash(), | ||||||
| 			'data' => $data, | 			'data' => $data, | ||||||
| 			'scale' => $scale, | 			'scale' => $scale, | ||||||
| 			'photo-type' => $type, | 			'photo-type' => $type, | ||||||
|  |  | ||||||
|  | @ -117,7 +117,7 @@ class Media | ||||||
| 	 */ | 	 */ | ||||||
| 	private static function unsetEmptyFields(array $media): array | 	private static function unsetEmptyFields(array $media): array | ||||||
| 	{ | 	{ | ||||||
| 		$fields = ['mimetype', 'height', 'width', 'size', 'preview', 'preview-height', 'preview-width', 'description']; | 		$fields = ['mimetype', 'height', 'width', 'size', 'preview', 'preview-height', 'preview-width', 'blurhash', 'description']; | ||||||
| 		foreach ($fields as $field) { | 		foreach ($fields as $field) { | ||||||
| 			if (empty($media[$field])) { | 			if (empty($media[$field])) { | ||||||
| 				unset($media[$field]); | 				unset($media[$field]); | ||||||
|  | @ -203,6 +203,7 @@ class Media | ||||||
| 				$media['size'] = $imagedata['size']; | 				$media['size'] = $imagedata['size']; | ||||||
| 				$media['width'] = $imagedata[0]; | 				$media['width'] = $imagedata[0]; | ||||||
| 				$media['height'] = $imagedata[1]; | 				$media['height'] = $imagedata[1]; | ||||||
|  | 				$media['blurhash'] = $imagedata['blurhash'] ?? null; | ||||||
| 			} else { | 			} else { | ||||||
| 				Logger::notice('No image data', ['media' => $media]); | 				Logger::notice('No image data', ['media' => $media]); | ||||||
| 			} | 			} | ||||||
|  | @ -232,6 +233,7 @@ class Media | ||||||
| 			$media['preview'] = $data['images'][0]['src'] ?? null; | 			$media['preview'] = $data['images'][0]['src'] ?? null; | ||||||
| 			$media['preview-height'] = $data['images'][0]['height'] ?? null; | 			$media['preview-height'] = $data['images'][0]['height'] ?? null; | ||||||
| 			$media['preview-width'] = $data['images'][0]['width'] ?? null; | 			$media['preview-width'] = $data['images'][0]['width'] ?? null; | ||||||
|  | 			$media['blurhash'] = $data['images'][0]['blurhash'] ?? null; | ||||||
| 			$media['description'] = $data['text'] ?? null; | 			$media['description'] = $data['text'] ?? null; | ||||||
| 			$media['name'] = $data['title'] ?? null; | 			$media['name'] = $data['title'] ?? null; | ||||||
| 			$media['author-url'] = $data['author_url'] ?? null; | 			$media['author-url'] = $data['author_url'] ?? null; | ||||||
|  | @ -287,6 +289,7 @@ class Media | ||||||
| 		$media['preview'] = null; | 		$media['preview'] = null; | ||||||
| 		$media['preview-height'] = null; | 		$media['preview-height'] = null; | ||||||
| 		$media['preview-width'] = null; | 		$media['preview-width'] = null; | ||||||
|  | 		$media['blurhash'] = null; | ||||||
| 		$media['description'] = $item['body']; | 		$media['description'] = $item['body']; | ||||||
| 		$media['name'] = $item['title']; | 		$media['name'] = $item['title']; | ||||||
| 		$media['author-url'] = $item['author-link']; | 		$media['author-url'] = $item['author-link']; | ||||||
|  | @ -328,6 +331,7 @@ class Media | ||||||
| 		$media['preview'] = null; | 		$media['preview'] = null; | ||||||
| 		$media['preview-height'] = null; | 		$media['preview-height'] = null; | ||||||
| 		$media['preview-width'] = null; | 		$media['preview-width'] = null; | ||||||
|  | 		$media['blurhash'] = null; | ||||||
| 		$media['description'] = $contact['about']; | 		$media['description'] = $contact['about']; | ||||||
| 		$media['name'] = $contact['name']; | 		$media['name'] = $contact['name']; | ||||||
| 		$media['author-url'] = $contact['url']; | 		$media['author-url'] = $contact['url']; | ||||||
|  | @ -357,6 +361,7 @@ class Media | ||||||
| 			$media['size'] = $photo['datasize']; | 			$media['size'] = $photo['datasize']; | ||||||
| 			$media['width'] = $photo['width']; | 			$media['width'] = $photo['width']; | ||||||
| 			$media['height'] = $photo['height']; | 			$media['height'] = $photo['height']; | ||||||
|  | 			$media['blurhash'] = $photo['blurhash']; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['preview'] ?? '', $matches)) { | 		if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['preview'] ?? '', $matches)) { | ||||||
|  |  | ||||||
|  | @ -46,6 +46,8 @@ class Attachment extends BaseDataTransferObject | ||||||
| 	protected $text_url; | 	protected $text_url; | ||||||
| 	/** @var string */ | 	/** @var string */ | ||||||
| 	protected $description; | 	protected $description; | ||||||
|  | 	/** @var string */ | ||||||
|  | 	protected $blurhash; | ||||||
| 	/** @var array */ | 	/** @var array */ | ||||||
| 	protected $meta; | 	protected $meta; | ||||||
| 
 | 
 | ||||||
|  | @ -68,6 +70,7 @@ class Attachment extends BaseDataTransferObject | ||||||
| 		$this->remote_url = $remote; | 		$this->remote_url = $remote; | ||||||
| 		$this->text_url = $this->remote_url ?? $this->url; | 		$this->text_url = $this->remote_url ?? $this->url; | ||||||
| 		$this->description = $attachment['description']; | 		$this->description = $attachment['description']; | ||||||
|  | 		$this->blurhash = $attachment['blurhash']; | ||||||
| 		if ($type === 'image') { | 		if ($type === 'image') { | ||||||
| 			if ((int) $attachment['width'] > 0 && (int) $attachment['height'] > 0) { | 			if ((int) $attachment['width'] > 0 && (int) $attachment['height'] > 0) { | ||||||
| 				$this->meta['original']['width'] = (int) $attachment['width']; | 				$this->meta['original']['width'] = (int) $attachment['width']; | ||||||
|  |  | ||||||
|  | @ -52,6 +52,8 @@ class Card extends BaseDataTransferObject | ||||||
| 	protected $height; | 	protected $height; | ||||||
| 	/** @var string */ | 	/** @var string */ | ||||||
| 	protected $image; | 	protected $image; | ||||||
|  | 	/** @var string */ | ||||||
|  | 	protected $blurhash; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a card record from an attachment array. | 	 * Creates a card record from an attachment array. | ||||||
|  | @ -72,6 +74,7 @@ class Card extends BaseDataTransferObject | ||||||
| 		$this->width         = $attachment['width'] ?? 0; | 		$this->width         = $attachment['width'] ?? 0; | ||||||
| 		$this->height        = $attachment['height'] ?? 0; | 		$this->height        = $attachment['height'] ?? 0; | ||||||
| 		$this->image         = $attachment['image'] ?? ''; | 		$this->image         = $attachment['image'] ?? ''; | ||||||
|  | 		$this->blurhash      = $attachment['blurhash'] ?? ''; | ||||||
| 		$this->history       = $history; | 		$this->history       = $history; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,13 +26,15 @@ use Friendica\DI; | ||||||
| use Friendica\Util\Images; | use Friendica\Util\Images; | ||||||
| use Imagick; | use Imagick; | ||||||
| use ImagickPixel; | use ImagickPixel; | ||||||
|  | use GDImage; | ||||||
|  | use kornrunner\Blurhash\Blurhash; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class to handle images |  * Class to handle images | ||||||
|  */ |  */ | ||||||
| class Image | class Image | ||||||
| { | { | ||||||
| 	/** @var Imagick|resource */ | 	/** @var GDImage|Imagick|resource */ | ||||||
| 	private $image; | 	private $image; | ||||||
| 
 | 
 | ||||||
| 	/* | 	/* | ||||||
|  | @ -695,14 +697,13 @@ class Image | ||||||
| 			try { | 			try { | ||||||
| 				/* Clean it */ | 				/* Clean it */ | ||||||
| 				$this->image = $this->image->deconstructImages(); | 				$this->image = $this->image->deconstructImages(); | ||||||
| 				$string = $this->image->getImagesBlob(); | 				return $this->image->getImagesBlob(); | ||||||
| 				return $string; |  | ||||||
| 			} catch (Exception $e) { | 			} catch (Exception $e) { | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ob_start(); | 		$stream = fopen('php://memory','r+'); | ||||||
| 
 | 
 | ||||||
| 		// Enable interlacing
 | 		// Enable interlacing
 | ||||||
| 		imageinterlace($this->image, true); | 		imageinterlace($this->image, true); | ||||||
|  | @ -710,18 +711,82 @@ class Image | ||||||
| 		switch ($this->getType()) { | 		switch ($this->getType()) { | ||||||
| 			case 'image/png': | 			case 'image/png': | ||||||
| 				$quality = DI::config()->get('system', 'png_quality'); | 				$quality = DI::config()->get('system', 'png_quality'); | ||||||
| 				imagepng($this->image, null, $quality); | 				imagepng($this->image, $stream, $quality); | ||||||
| 				break; | 				break; | ||||||
| 
 | 
 | ||||||
| 			case 'image/jpeg': | 			case 'image/jpeg': | ||||||
| 			case 'image/jpg': | 			case 'image/jpg': | ||||||
| 				$quality = DI::config()->get('system', 'jpeg_quality'); | 				$quality = DI::config()->get('system', 'jpeg_quality'); | ||||||
| 				imagejpeg($this->image, null, $quality); | 				imagejpeg($this->image, $stream, $quality); | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
| 		$string = ob_get_contents(); | 		rewind($stream); | ||||||
| 		ob_end_clean(); | 		return stream_get_contents($stream); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 		return $string; | 	/** | ||||||
|  | 	 * Create a blurhash out of a given image string | ||||||
|  | 	 * | ||||||
|  | 	 * @param string $img_str | ||||||
|  | 	 * @return string | ||||||
|  | 	 */ | ||||||
|  | 	public function getBlurHash(): string | ||||||
|  | 	{ | ||||||
|  | 		if ($this->isImagick()) { | ||||||
|  | 			// Imagick is not supported
 | ||||||
|  | 			return ''; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$width = $this->getWidth(); | ||||||
|  | 		$height = $this->getHeight(); | ||||||
|  | 
 | ||||||
|  | 		if (max($width, $height) > 90) { | ||||||
|  | 			$this->scaleDown(90); | ||||||
|  | 			$width = $this->getWidth(); | ||||||
|  | 			$height = $this->getHeight(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$pixels = []; | ||||||
|  | 		for ($y = 0; $y < $height; ++$y) { | ||||||
|  | 			$row = []; | ||||||
|  | 			for ($x = 0; $x < $width; ++$x) { | ||||||
|  | 				$index = imagecolorat($this->image, $x, $y); | ||||||
|  | 				$colors = imagecolorsforindex($this->image, $index); | ||||||
|  | 
 | ||||||
|  | 				$row[] = [$colors['red'], $colors['green'], $colors['blue']]; | ||||||
|  | 			} | ||||||
|  | 			$pixels[] = $row; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// The components define the amount of details (1 to 9).
 | ||||||
|  | 		$components_x = 9; | ||||||
|  | 		$components_y = 9; | ||||||
|  | 
 | ||||||
|  | 		return Blurhash::encode($pixels, $components_x, $components_y); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Create an image out of a blurhash | ||||||
|  | 	 * | ||||||
|  | 	 * @param string $blurhash | ||||||
|  | 	 * @param integer $width | ||||||
|  | 	 * @param integer $height | ||||||
|  | 	 * @return void | ||||||
|  | 	 */ | ||||||
|  | 	public function getFromBlurHash(string $blurhash, int $width, int $height) | ||||||
|  | 	{ | ||||||
|  | 		if ($this->isImagick()) { | ||||||
|  | 			// Imagick is not supported
 | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$pixels = Blurhash::decode($blurhash, $width, $height); | ||||||
|  | 		$this->image  = imagecreatetruecolor($width, $height); | ||||||
|  | 		for ($y = 0; $y < $height; ++$y) { | ||||||
|  | 			for ($x = 0; $x < $width; ++$x) { | ||||||
|  | 				[$r, $g, $b] = $pixels[$y][$x]; | ||||||
|  | 				imagesetpixel($this->image, $x, $y, imagecolorallocate($this->image, $r, $g, $b)); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ use Friendica\Core\Logger; | ||||||
| use Friendica\DI; | use Friendica\DI; | ||||||
| use Friendica\Model\Photo; | use Friendica\Model\Photo; | ||||||
| use Friendica\Network\HTTPClient\Client\HttpClientAccept; | use Friendica\Network\HTTPClient\Client\HttpClientAccept; | ||||||
|  | use Friendica\Object\Image; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Image utilities |  * Image utilities | ||||||
|  | @ -244,6 +245,9 @@ class Images | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if ($data) { | 		if ($data) { | ||||||
|  | 			$image = new Image($img_str); | ||||||
|  | 
 | ||||||
|  | 			$data['blurhash'] = $image->getBlurHash(); | ||||||
| 			$data['size']     = $filesize; | 			$data['size']     = $filesize; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -567,6 +567,7 @@ class ParseUrl | ||||||
| 						$image['width'] = $photodata[0]; | 						$image['width'] = $photodata[0]; | ||||||
| 						$image['height'] = $photodata[1]; | 						$image['height'] = $photodata[1]; | ||||||
| 						$image['contenttype'] = $photodata['mime']; | 						$image['contenttype'] = $photodata['mime']; | ||||||
|  | 						$image['blurhash'] = $photodata['blurhash'] ?? null; | ||||||
| 						unset($image['url']); | 						unset($image['url']); | ||||||
| 						ksort($image); | 						ksort($image); | ||||||
| 					} else { | 					} else { | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ | ||||||
| use Friendica\Database\DBA; | use Friendica\Database\DBA; | ||||||
| 
 | 
 | ||||||
| if (!defined('DB_UPDATE_VERSION')) { | if (!defined('DB_UPDATE_VERSION')) { | ||||||
| 	define('DB_UPDATE_VERSION', 1496); | 	define('DB_UPDATE_VERSION', 1497); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| return [ | return [ | ||||||
|  | @ -1129,6 +1129,7 @@ return [ | ||||||
| 			"height" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""], | 			"height" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""], | ||||||
| 			"width" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""], | 			"width" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""], | ||||||
| 			"datasize" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""], | 			"datasize" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""], | ||||||
|  | 			"blurhash" => ["type" => "varbinary(255)", "comment" => "BlurHash representation of the photo"], | ||||||
| 			"data" => ["type" => "mediumblob", "not null" => "1", "comment" => ""], | 			"data" => ["type" => "mediumblob", "not null" => "1", "comment" => ""], | ||||||
| 			"scale" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], | 			"scale" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], | ||||||
| 			"profile" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], | 			"profile" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], | ||||||
|  | @ -1340,6 +1341,7 @@ return [ | ||||||
| 			"height" => ["type" => "smallint unsigned", "comment" => "Height of the media"], | 			"height" => ["type" => "smallint unsigned", "comment" => "Height of the media"], | ||||||
| 			"width" => ["type" => "smallint unsigned", "comment" => "Width of the media"], | 			"width" => ["type" => "smallint unsigned", "comment" => "Width of the media"], | ||||||
| 			"size" => ["type" => "bigint unsigned", "comment" => "Media size"], | 			"size" => ["type" => "bigint unsigned", "comment" => "Media size"], | ||||||
|  | 			"blurhash" => ["type" => "varbinary(255)", "comment" => "BlurHash representation of the image"], | ||||||
| 			"preview" => ["type" => "varbinary(512)", "comment" => "Preview URL"], | 			"preview" => ["type" => "varbinary(512)", "comment" => "Preview URL"], | ||||||
| 			"preview-height" => ["type" => "smallint unsigned", "comment" => "Height of the preview picture"], | 			"preview-height" => ["type" => "smallint unsigned", "comment" => "Height of the preview picture"], | ||||||
| 			"preview-width" => ["type" => "smallint unsigned", "comment" => "Width of the preview picture"], | 			"preview-width" => ["type" => "smallint unsigned", "comment" => "Width of the preview picture"], | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue