From cfe5101b9b89ebf3821439069f9f05fc4890dddf Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 4 Dec 2022 14:58:53 +0000
Subject: [PATCH] Use the blurhash when the remote picture doesn't load

---
 src/Model/Photo.php  |  8 +++++++-
 src/Module/Photo.php | 22 +++++++++++++++-------
 src/Object/Image.php | 16 ++++++++++++----
 3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/src/Model/Photo.php b/src/Model/Photo.php
index 213551b11..6dd921283 100644
--- a/src/Model/Photo.php
+++ b/src/Model/Photo.php
@@ -346,11 +346,14 @@ class Photo
 	 * @param string $url      Image URL
 	 * @param int    $uid      User ID of the requesting person
 	 * @param string $mimetype Image mime type. Is guessed by file name when empty.
+	 * @param string $blurhash The blurhash that will be used to generate a picture when the original picture can't be fetched
+	 * @param int    $width    Image width
+	 * @param int    $height   Image height
 	 *
 	 * @return array
 	 * @throws \Exception
 	 */
-	public static function createPhotoForExternalResource(string $url, int $uid = 0, string $mimetype = ''): array
+	public static function createPhotoForExternalResource(string $url, int $uid = 0, string $mimetype = '', string $blurhash = '', int $width = 0, int $height = 0): array
 	{
 		if (empty($mimetype)) {
 			$mimetype = Images::guessTypeByExtension($url);
@@ -364,6 +367,9 @@ class Photo
 		$photo['backend-ref']   = json_encode(['url' => $url, 'uid' => $uid]);
 		$photo['type']          = $mimetype;
 		$photo['cacheable']     = true;
+		$photo['blurhash']      = $blurhash;
+		$photo['width']         = $width;
+		$photo['height']        = $height;
 
 		return $photo;
 	}
diff --git a/src/Module/Photo.php b/src/Module/Photo.php
index 1847b4f70..a4ef6ab41 100644
--- a/src/Module/Photo.php
+++ b/src/Module/Photo.php
@@ -153,8 +153,12 @@ class Photo extends BaseModule
 		$stamp = microtime(true);
 
 		$imgdata = MPhoto::getImageDataForPhoto($photo);
-		if (empty($imgdata)) {
+		if (empty($imgdata) && empty($photo['blurhash'])) {
 			throw new HTTPException\NotFoundException();
+		} elseif (empty($imgdata) && !empty($photo['blurhash'])) {
+			$image = New Image('', 'image/png');
+			$image->getFromBlurHash($photo['blurhash'], $photo['width'], $photo['height']);
+			$imgdata = $image->asString();
 		}
 
 		// The mimetype for an external or system resource can only be known reliably after it had been fetched
@@ -240,14 +244,18 @@ class Photo extends BaseModule
 	{
 		switch($type) {
 			case 'preview':
-				$media = DBA::selectFirst('post-media', ['preview', 'url', 'mimetype', 'type', 'uri-id'], ['id' => $id]);
+				$media = DBA::selectFirst('post-media', ['preview', 'url', 'preview-height', 'preview-width', 'height', 'width', 'mimetype', 'type', 'uri-id', 'blurhash'], ['id' => $id]);
 				if (empty($media)) {
 					return false;
 				}
-				$url = $media['preview'];
+				$url    = $media['preview'];
+				$width  = $media['preview-width'];
+				$height = $media['preview-height'];
 
 				if (empty($url) && ($media['type'] == Post\Media::IMAGE)) {
-					$url = $media['url'];
+					$url    = $media['url'];
+					$width  = $media['width'];
+					$height = $media['height'];
 				}
 
 				if (empty($url)) {
@@ -258,9 +266,9 @@ class Photo extends BaseModule
 					return MPhoto::getPhoto($matches[1], $matches[2]);
 				}
 
-				return MPhoto::createPhotoForExternalResource($url, (int)DI::userSession()->getLocalUserId(), $media['mimetype'] ?? '');
+				return MPhoto::createPhotoForExternalResource($url, (int)DI::userSession()->getLocalUserId(), $media['mimetype'] ?? '', $media['blurhash'], $width, $height);
 			case 'media':
-				$media = DBA::selectFirst('post-media', ['url', 'mimetype', 'uri-id'], ['id' => $id, 'type' => Post\Media::IMAGE]);
+				$media = DBA::selectFirst('post-media', ['url', 'height', 'width', 'mimetype', 'uri-id', 'blurhash'], ['id' => $id, 'type' => Post\Media::IMAGE]);
 				if (empty($media)) {
 					return false;
 				}
@@ -269,7 +277,7 @@ class Photo extends BaseModule
 					return MPhoto::getPhoto($matches[1], $matches[2]);
 				}
 
-				return MPhoto::createPhotoForExternalResource($media['url'], (int)DI::userSession()->getLocalUserId(), $media['mimetype']);
+				return MPhoto::createPhotoForExternalResource($media['url'], (int)DI::userSession()->getLocalUserId(), $media['mimetype'], $media['blurhash'], $media['width'], $media['height']);
 			case 'link':
 				$link = DBA::selectFirst('post-link', ['url', 'mimetype'], ['id' => $id]);
 				if (empty($link)) {
diff --git a/src/Object/Image.php b/src/Object/Image.php
index c2cfa9e2f..87401304d 100644
--- a/src/Object/Image.php
+++ b/src/Object/Image.php
@@ -780,13 +780,21 @@ class Image
 			return;
 		}
 
-		$pixels = Blurhash::decode($blurhash, $width, $height);
-		$this->image  = imagecreatetruecolor($width, $height);
-		for ($y = 0; $y < $height; ++$y) {
-			for ($x = 0; $x < $width; ++$x) {
+		$scaled = Images::getScalingDimensions($width, $height, 90);
+		$pixels = Blurhash::decode($blurhash, $scaled['width'], $scaled['height']);
+
+		$this->image = imagecreatetruecolor($scaled['width'], $scaled['height']);
+		for ($y = 0; $y < $scaled['height']; ++$y) {
+			for ($x = 0; $x < $scaled['width']; ++$x) {
 				[$r, $g, $b] = $pixels[$y][$x];
 				imagesetpixel($this->image, $x, $y, imagecolorallocate($this->image, $r, $g, $b));
 			}
 		}
+
+		$this->width  = imagesx($this->image);
+		$this->height = imagesy($this->image);
+		$this->valid  = true;
+
+		$this->scaleUp(min($width, $height));
 	}
 }