Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resize large images attachments on upload #1824

Merged
merged 5 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion composables/masto/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,62 @@ export function useUploadMediaAttachment(draftRef: Ref<Draft>) {
let failedAttachments = $ref<MediaAttachmentUploadError[]>([])
const dropZoneRef = ref<HTMLDivElement>()

const maxPixels
= currentInstance.value!.configuration?.mediaAttachments?.imageMatrixLimit
?? 4096 ** 2

const loadImage = (inputFile: Blob) => new Promise<HTMLImageElement>((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<Blob | null> {
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 = []
Expand All @@ -131,7 +187,7 @@ export function useUploadMediaAttachment(draftRef: Ref<Draft>) {
isExceedingAttachmentLimit = false
try {
const attachment = await client.v1.mediaAttachments.create({
file,
file: await processFile(file),
})
draft.attachments.push(attachment)
}
Expand Down
2 changes: 1 addition & 1 deletion nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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\''],
Expand Down