From 99adbfd1ea896e6fbaf6417d6ecf8aab50d58a8b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 5 Aug 2021 13:04:20 +0100 Subject: [PATCH 1/2] Skip sending a thumbnail if it is not a sufficient saving over the original --- src/ContentMessages.tsx | 49 +++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index c5bcb226fff..8973219b495 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -209,6 +209,14 @@ async function loadImageElement(imageFile: File) { return { width, height, img }; } +// Minimum size for image files before we generate a thumbnail for them. +const IMAGE_SIZE_THRESHOLD_THUMBNAIL = 1 << 15; // 32KB +// Minimum size improvement for image thumbnails, if both are not met then don't bother uploading thumbnail. +const IMAGE_THUMBNAIL_MIN_REDUCTION_SIZE = 1 << 16; // 1MB +const IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT = 0.1; // 10% +// We don't apply these thresholds to video thumbnails as a poster image is always useful +// and videos tend to be much larger. + /** * Read the metadata for an image file and create and upload a thumbnail of the image. * @@ -217,23 +225,40 @@ async function loadImageElement(imageFile: File) { * @param {File} imageFile The image to read and thumbnail. * @return {Promise} A promise that resolves with the attachment info. */ -function infoForImageFile(matrixClient, roomId, imageFile) { +async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imageFile: File) { + if (imageFile.size <= IMAGE_SIZE_THRESHOLD_THUMBNAIL) { + // don't bother generating a thumbnail, image is small enough already + return {}; + } + let thumbnailType = "image/png"; if (imageFile.type === "image/jpeg") { thumbnailType = "image/jpeg"; } - let imageInfo; - return loadImageElement(imageFile).then((r) => { - return createThumbnail(r.img, r.width, r.height, thumbnailType); - }).then((result) => { - imageInfo = result.info; - return uploadFile(matrixClient, roomId, result.thumbnail); - }).then((result) => { - imageInfo.thumbnail_url = result.url; - imageInfo.thumbnail_file = result.file; - return imageInfo; - }); + const imageElement = await loadImageElement(imageFile); + + if (imageElement.width < MAX_WIDTH && imageElement.height < MAX_HEIGHT) { + // don't bother uploading thumbnail as it'd be the same resolution as the original. + return {}; + } + + const result = await createThumbnail(imageElement.img, imageElement.width, imageElement.height, thumbnailType); + const imageInfo = result.info; + + const sizeDifference = imageFile.size - imageInfo.thumbnail_info.size; + if (sizeDifference <= IMAGE_THUMBNAIL_MIN_REDUCTION_SIZE && + sizeDifference <= (imageFile.size * IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT) + ) { + // don't bother uploading thumbnail as it not sufficiently smaller than the original. + return {}; + } + + const uploadResult = await uploadFile(matrixClient, roomId, result.thumbnail); + + imageInfo["thumbnail_url"] = uploadResult.url; + imageInfo["thumbnail_file"] = uploadResult.file; + return imageInfo; } /** From 980b284642cbbdbcb88920b8dd1e89bf312cc820 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 5 Aug 2021 13:12:01 +0100 Subject: [PATCH 2/2] Fix image & blurhash info when skipping thumbnail due to thresholds --- src/ContentMessages.tsx | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index 8973219b495..14a0c1ed517 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -226,11 +226,6 @@ const IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT = 0.1; // 10% * @return {Promise} A promise that resolves with the attachment info. */ async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imageFile: File) { - if (imageFile.size <= IMAGE_SIZE_THRESHOLD_THUMBNAIL) { - // don't bother generating a thumbnail, image is small enough already - return {}; - } - let thumbnailType = "image/png"; if (imageFile.type === "image/jpeg") { thumbnailType = "image/jpeg"; @@ -238,20 +233,18 @@ async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imag const imageElement = await loadImageElement(imageFile); - if (imageElement.width < MAX_WIDTH && imageElement.height < MAX_HEIGHT) { - // don't bother uploading thumbnail as it'd be the same resolution as the original. - return {}; - } - const result = await createThumbnail(imageElement.img, imageElement.width, imageElement.height, thumbnailType); const imageInfo = result.info; + // we do all sizing checks here because we still rely on thumbnail generation for making a blurhash from. const sizeDifference = imageFile.size - imageInfo.thumbnail_info.size; - if (sizeDifference <= IMAGE_THUMBNAIL_MIN_REDUCTION_SIZE && - sizeDifference <= (imageFile.size * IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT) + if ( + imageFile.size <= IMAGE_SIZE_THRESHOLD_THUMBNAIL || // image is small enough already + (sizeDifference <= IMAGE_THUMBNAIL_MIN_REDUCTION_SIZE && // thumbnail is not sufficiently smaller than original + sizeDifference <= (imageFile.size * IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT)) ) { - // don't bother uploading thumbnail as it not sufficiently smaller than the original. - return {}; + delete imageInfo["thumbnail_info"]; + return imageInfo; } const uploadResult = await uploadFile(matrixClient, roomId, result.thumbnail);