From 32eaee82e20b03d71c574ae8bd7aa141da60ad06 Mon Sep 17 00:00:00 2001 From: Zaidhaan Date: Wed, 1 Mar 2023 05:58:19 +0800 Subject: [PATCH] fix: resize large images attachments on upload (#1824) --- composables/masto/publish.ts | 58 +++++++++++++++++++++++++++++++++++- nuxt.config.ts | 2 +- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/composables/masto/publish.ts b/composables/masto/publish.ts index b70daeba..fb743fff 100644 --- a/composables/masto/publish.ts +++ b/composables/masto/publish.ts @@ -120,6 +120,62 @@ export function useUploadMediaAttachment(draftRef: Ref) { let failedAttachments = $ref([]) const dropZoneRef = ref() + const maxPixels + = currentInstance.value!.configuration?.mediaAttachments?.imageMatrixLimit + ?? 4096 ** 2 + + const loadImage = (inputFile: Blob) => new Promise((resolve, reject) => { + const url = URL.createObjectURL(inputFile) + const img = new Image() + + img.onerror = err => reject(err) + img.onload = () => resolve(img) + + img.src = url + }) + + function resizeImage(img: CanvasImageSource, type = 'image/png'): Promise { + const { width, height } = img + + const aspectRatio = (width as number) / (height as number) + + const canvas = document.createElement('canvas') + + const resizedWidth = canvas.width = Math.round(Math.sqrt(maxPixels * aspectRatio)) + const resizedHeight = canvas.height = Math.round(Math.sqrt(maxPixels / aspectRatio)) + + const context = canvas.getContext('2d') + + context?.drawImage(img, 0, 0, resizedWidth, resizedHeight) + + return new Promise((resolve) => { + canvas.toBlob(resolve, type) + }) + } + + async function processImageFile(file: File) { + try { + const image = await loadImage(file) as HTMLImageElement + + if (image.width * image.height > maxPixels) + file = await resizeImage(image, file.type) as File + + return file + } + catch (e) { + // Resize failed, just use the original file + console.error(e) + return file + } + } + + async function processFile(file: File) { + if (file.type.startsWith('image/')) + return await processImageFile(file) + + return file + } + async function uploadAttachments(files: File[]) { isUploading = true failedAttachments = [] @@ -131,7 +187,7 @@ export function useUploadMediaAttachment(draftRef: Ref) { isExceedingAttachmentLimit = false try { const attachment = await client.v1.mediaAttachments.create({ - file, + file: await processFile(file), }) draft.attachments.push(attachment) } diff --git a/nuxt.config.ts b/nuxt.config.ts index a687728d..75f8a090 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -206,7 +206,7 @@ export default defineNuxtConfig({ 'font-src': ['\'self\''], 'form-action': ['\'none\''], 'frame-ancestors': ['\'none\''], - 'img-src': ['\'self\'', 'https:', 'http:', 'data:'], + 'img-src': ['\'self\'', 'https:', 'http:', 'data:', 'blob:'], 'media-src': ['\'self\'', 'https:', 'http:'], 'object-src': ['\'none\''], 'script-src': ['\'self\'', '\'unsafe-inline\'', '\'wasm-unsafe-eval\''],