diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index c5bcb226ff..8973219b49 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; } /**