@@ -85,6 +85,8 @@ export const useUploadStore = defineStore('upload', () => {
8585 const uploads = reactive < UploadsState > ( { } )
8686 const currentUploadId = ref < string | undefined > ( undefined )
8787 const localUrls = reactive < Record < string , string > > ( { } )
88+ const compressionJobs : Record < string , Promise < File | null > | undefined > = { }
89+ const compressedFileSizes = reactive < Record < string , number > > ( { } )
8890
8991 /**
9092 * The user's choices for the current upload. They are only valid until it
@@ -168,7 +170,7 @@ export const useUploadStore = defineStore('upload', () => {
168170 /**
169171 * Returns the local URL of uploaded image
170172 *
171- * @param referenceId
173+ * @param referenceId the temporary message's reference id
172174 */
173175 function getLocalUrl ( referenceId : string ) : string | undefined {
174176 return localUrls [ referenceId ]
@@ -213,6 +215,9 @@ export const useUploadStore = defineStore('upload', () => {
213215 if ( localUrl ) {
214216 localUrls [ temporaryMessage . referenceId ] = localUrl
215217 }
218+ if ( supportImageCompression ( file . type ) && file . size > 0 ) {
219+ void initCompressImage ( temporaryMessage . referenceId , file )
220+ }
216221 }
217222
218223 /**
@@ -306,6 +311,7 @@ export const useUploadStore = defineStore('upload', () => {
306311 const uploadId = currentUploadId . value !
307312 for ( const index in uploads [ uploadId ] . files ) {
308313 if ( uploads [ uploadId ] . files [ index ] . temporaryMessage ! . id === temporaryMessageId ) {
314+ dismissCompressImage ( uploads [ uploadId ] . files [ index ] . temporaryMessage ! . referenceId )
309315 delete uploads [ uploadId ] . files [ index ]
310316 }
311317 }
@@ -374,9 +380,50 @@ export const useUploadStore = defineStore('upload', () => {
374380 }
375381 EventBus . emit ( 'upload-discard' )
376382
383+ for ( const [ _index , uploadedFile ] of getUploadsArray ( uploadId ) ) {
384+ dismissCompressImage ( uploadedFile . temporaryMessage . referenceId )
385+ }
386+
377387 delete uploads [ uploadId ]
378388 }
379389
390+ /**
391+ * Compresses a staged image eagerly, exposing resulting preview size.
392+ * The job output is kept, so compressUploadedImage() can reuse it.
393+ * Starts a job only once per file, and returns the pending or finished one.
394+ *
395+ * @param referenceId the temporary message's reference id
396+ * @param file the staged file
397+ */
398+ function initCompressImage ( referenceId : string , file : File ) : Promise < File | null > {
399+ const startedJob = compressionJobs [ referenceId ]
400+ if ( startedJob ) {
401+ return startedJob
402+ }
403+ const newJob = async ( ) => {
404+ try {
405+ const compressed = await compressImage ( file )
406+ compressedFileSizes [ referenceId ] = compressed ?. size ?? file . size
407+ return compressed
408+ } catch ( error ) {
409+ console . error ( 'Failed to compress image, uploading original: ' , error )
410+ return null
411+ }
412+ }
413+ compressionJobs [ referenceId ] = newJob ( )
414+ return compressionJobs [ referenceId ]
415+ }
416+
417+ /**
418+ * Drops the job and size preview, release resources
419+ *
420+ * @param referenceId the temporary message's reference id
421+ */
422+ function dismissCompressImage ( referenceId : string ) {
423+ delete compressionJobs [ referenceId ]
424+ delete compressedFileSizes [ referenceId ]
425+ }
426+
380427 /**
381428 * Re-encodes an initialised image upload in place, replacing the staged file
382429 * and its local preview URL.
@@ -395,9 +442,10 @@ export const useUploadStore = defineStore('upload', () => {
395442 return null
396443 }
397444
445+ const referenceId = uploadedFile . temporaryMessage . referenceId
398446 try {
399447 // @ts -expect-error: UploadFile.file is a custom type, not a File
400- const compressed = await compressImage ( currentFile )
448+ const compressed = await initCompressImage ( referenceId , currentFile )
401449 if ( ! compressed ) {
402450 // Compression was not beneficial, the original file is kept
403451 return null
@@ -407,7 +455,6 @@ export const useUploadStore = defineStore('upload', () => {
407455 uploads [ uploadId ] . files [ index ] . file = compressed
408456 uploads [ uploadId ] . files [ index ] . totalSize = compressed . size
409457
410- const referenceId = uploadedFile . temporaryMessage . referenceId
411458 if ( localUrls [ referenceId ] ) {
412459 URL . revokeObjectURL ( localUrls [ referenceId ] )
413460 }
@@ -449,6 +496,7 @@ export const useUploadStore = defineStore('upload', () => {
449496 const compressed = compressImages
450497 ? await compressUploadedImage ( uploadId , index )
451498 : null
499+ dismissCompressImage ( uploadedFile . temporaryMessage . referenceId )
452500
453501 // Store the previously created temporary message
454502 const message = {
@@ -823,6 +871,7 @@ export const useUploadStore = defineStore('upload', () => {
823871 uploads,
824872 currentUploadId,
825873 localUrls,
874+ compressedFileSizes,
826875 allowUpdate,
827876 skipCompression,
828877
0 commit comments