From a47d172d60b1ae712738e0ba5dfbb6b81be3f809 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 18 Dec 2022 15:40:38 +0900 Subject: enhance(client): Compress non-animated PNG files (#9334) * style: fix TS lint errors about `ev.target` * enhance: compress non-animated PNG * PNG to PNG? * defer jest things (add it later) * Delete jest.config.cjs * check the compressed file size * log compression stats * use ?? * handle if ($i == null) Co-authored-by: tamaina --- packages/client/src/scripts/upload.ts | 47 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'packages/client/src/scripts/upload.ts') diff --git a/packages/client/src/scripts/upload.ts b/packages/client/src/scripts/upload.ts index 51f1c1b86f..9a39652ef5 100644 --- a/packages/client/src/scripts/upload.ts +++ b/packages/client/src/scripts/upload.ts @@ -1,6 +1,7 @@ import { reactive, ref } from 'vue'; import * as Misskey from 'misskey-js'; import { readAndCompressImage } from 'browser-image-resizer'; +import { getCompressionConfig } from './upload/compress-config'; import { defaultStore } from '@/store'; import { apiUrl } from '@/config'; import { $i } from '@/account'; @@ -16,12 +17,6 @@ type Uploading = { }; export const uploads = ref([]); -const compressTypeMap = { - 'image/jpeg': { quality: 0.85, mimeType: 'image/jpeg' }, - 'image/webp': { quality: 0.85, mimeType: 'image/jpeg' }, - 'image/svg+xml': { quality: 1, mimeType: 'image/png' }, -} as const; - const mimeTypeMap = { 'image/webp': 'webp', 'image/jpeg': 'jpg', @@ -34,16 +29,18 @@ export function uploadFile( name?: string, keepOriginal: boolean = defaultStore.state.keepOriginalUploading, ): Promise { + if ($i == null) throw new Error('Not logged in'); + if (folder && typeof folder === 'object') folder = folder.id; return new Promise((resolve, reject) => { const id = Math.random().toString(); const reader = new FileReader(); - reader.onload = async (ev) => { + reader.onload = async (): Promise => { const ctx = reactive({ id: id, - name: name || file.name || 'untitled', + name: name ?? file.name ?? 'untitled', progressMax: undefined, progressValue: undefined, img: window.URL.createObjectURL(file), @@ -51,20 +48,22 @@ export function uploadFile( uploads.value.push(ctx); - let resizedImage: any; - if (!keepOriginal && file.type in compressTypeMap) { - const imgConfig = compressTypeMap[file.type]; - - const config = { - maxWidth: 2048, - maxHeight: 2048, - debug: true, - ...imgConfig, - }; - + const config = !keepOriginal ? await getCompressionConfig(file) : undefined; + let resizedImage: Blob | undefined; + if (config) { try { - resizedImage = await readAndCompressImage(file, config); - ctx.name = file.type !== imgConfig.mimeType ? `${ctx.name}.${mimeTypeMap[compressTypeMap[file.type].mimeType]}` : ctx.name; + const resized = await readAndCompressImage(file, config); + if (resized.size < file.size || file.type === 'image/webp') { + // The compression may not always reduce the file size + // (and WebP is not browser safe yet) + resizedImage = resized; + } + if (_DEV_) { + const saved = ((1 - resized.size / file.size) * 100).toFixed(2); + console.log(`Image compression: before ${file.size} bytes, after ${resized.size} bytes, saved ${saved}%`); + } + + ctx.name = file.type !== config.mimeType ? `${ctx.name}.${mimeTypeMap[config.mimeType]}` : ctx.name; } catch (err) { console.error('Failed to resize image', err); } @@ -73,13 +72,13 @@ export function uploadFile( const formData = new FormData(); formData.append('i', $i.token); formData.append('force', 'true'); - formData.append('file', resizedImage || file); + formData.append('file', resizedImage ?? file); formData.append('name', ctx.name); if (folder) formData.append('folderId', folder); const xhr = new XMLHttpRequest(); xhr.open('POST', apiUrl + '/drive/files/create', true); - xhr.onload = (ev) => { + xhr.onload = ((ev: ProgressEvent) => { if (xhr.status !== 200 || ev.target == null || ev.target.response == null) { // TODO: 消すのではなくて(ネットワーク的なエラーなら)再送できるようにしたい uploads.value = uploads.value.filter(x => x.id !== id); @@ -122,7 +121,7 @@ export function uploadFile( resolve(driveFile); uploads.value = uploads.value.filter(x => x.id !== id); - }; + }) as (ev: ProgressEvent) => any; xhr.upload.onprogress = ev => { if (ev.lengthComputable) { -- cgit v1.2.3-freya