diff --git a/src/lib/media/manip.ts b/src/lib/media/manip.ts index a443569e1..907dce0e6 100644 --- a/src/lib/media/manip.ts +++ b/src/lib/media/manip.ts @@ -36,10 +36,11 @@ export async function compressIfNeeded( height: img.height, mode: 'stretch', maxSize, + outputMime: 'image/jpeg', }) const finalImageMovedPath = await moveToPermanentPath( resizedImage.path, - '.jpg', + resizedImage.mime === 'image/jpeg' ? '.jpg' : '.webp', ) const finalImg = { ...resizedImage, @@ -240,12 +241,16 @@ interface DoResizeOpts { height: number mode: 'contain' | 'cover' | 'stretch' maxSize: number + outputMime?: 'image/jpeg' | 'image/webp' } async function doResize( localUri: string, opts: DoResizeOpts, ): Promise { + const outputMime = opts.outputMime ?? 'image/webp' + const outputFormat = + outputMime === 'image/jpeg' ? SaveFormat.JPEG : SaveFormat.WEBP // We need to get the dimensions of the image before we resize it. Previously, the library we used allowed us to enter // a "max size", and it would do the "best possible size" calculation for us. // Now instead, we have to supply the final dimensions to the manipulation function instead. @@ -270,7 +275,7 @@ async function doResize( localUri, [{resize: newDimensions}], { - format: SaveFormat.WEBP, + format: outputFormat, compress: qualityPercentage / 100, }, ) @@ -288,7 +293,7 @@ async function doResize( minQualityPercentage = qualityPercentage newDataUri = { path: normalizePath(resizeRes.uri), - mime: 'image/webp', + mime: outputMime, size: fileInfo.size, width: resizeRes.width, height: resizeRes.height, diff --git a/src/lib/media/manip.web.ts b/src/lib/media/manip.web.ts index 02a9638bd..0470245af 100644 --- a/src/lib/media/manip.web.ts +++ b/src/lib/media/manip.web.ts @@ -15,6 +15,7 @@ export async function compressIfNeeded( height: img.height, mode: 'stretch', maxSize, + outputMime: 'image/jpeg', }) } @@ -83,12 +84,14 @@ interface DoResizeOpts { height: number mode: 'contain' | 'cover' | 'stretch' maxSize: number + outputMime?: 'image/jpeg' | 'image/webp' } async function doResize( dataUri: string, opts: DoResizeOpts, ): Promise { + const outputMime = opts.outputMime ?? 'image/webp' let newDataUri let minQualityPercentage = 0 @@ -103,6 +106,7 @@ async function doResize( height: opts.height, quality: qualityPercentage / 100, mode: opts.mode, + outputMime, }) if (getDataUriSize(tempDataUri) < opts.maxSize) { @@ -118,7 +122,7 @@ async function doResize( } return { path: newDataUri, - mime: 'image/webp', + mime: outputMime, size: getDataUriSize(newDataUri), width: opts.width, height: opts.height, @@ -132,11 +136,13 @@ function createResizedImage( height, quality, mode, + outputMime, }: { width: number height: number quality: number mode: 'contain' | 'cover' | 'stretch' + outputMime: 'image/jpeg' | 'image/webp' }, ): Promise { return new Promise((resolve, reject) => { @@ -161,7 +167,7 @@ function createResizedImage( canvas.height = h ctx.drawImage(img, 0, 0, w, h) - resolve(canvas.toDataURL('image/webp', quality)) + resolve(canvas.toDataURL(outputMime, quality)) }) img.addEventListener('error', ev => { reject(ev.error) diff --git a/src/lib/media/picker.tsx b/src/lib/media/picker.tsx index 6fdfe5438..375738e97 100644 --- a/src/lib/media/picker.tsx +++ b/src/lib/media/picker.tsx @@ -25,7 +25,7 @@ export async function openCamera(customOpts: ImagePickerOptions) { return { path: asset.uri, - mime: asset.mimeType ?? 'image/webp', + mime: asset.mimeType ?? 'image/jpeg', size: asset.fileSize ?? 0, width: asset.width, height: asset.height, diff --git a/src/state/gallery.ts b/src/state/gallery.ts index fcf8cc2b7..8527bc371 100644 --- a/src/state/gallery.ts +++ b/src/state/gallery.ts @@ -284,6 +284,7 @@ export async function compressImage( options?: { highResolution?: boolean increasedBlobSizeLimit?: boolean + outputMime?: 'image/jpeg' | 'image/webp' }, ): Promise { const res = await bypassCompression(img) @@ -293,6 +294,9 @@ export async function compressImage( const source = img.transformed || img.source const highResolution = options?.highResolution ?? false + const outputMime = options?.outputMime ?? 'image/webp' + const outputFormat = + outputMime === 'image/jpeg' ? SaveFormat.JPEG : SaveFormat.WEBP let attempts = 0 let maxDimension = highResolution ? 4000 : POST_IMG_MAX.width let maxBytes = options?.increasedBlobSizeLimit ? 2000000 : POST_IMG_MAX.size @@ -329,7 +333,7 @@ export async function compressImage( [{resize: {width: w, height: h}}], { compress: qualityPercentage / 100, - format: SaveFormat.WEBP, + format: outputFormat, base64: true, }, ) @@ -342,7 +346,7 @@ export async function compressImage( path: await moveIfNecessary(res.uri), width: res.width, height: res.height, - mime: 'image/webp', + mime: outputMime, size, } } else { diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 619286509..c0b9b9ef3 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -465,7 +465,7 @@ let EditableUserAvatar = ({ const onChangeEditImage = useCallback( async (image: ComposerImage) => { - const compressed = await compressImage(image) + const compressed = await compressImage(image, {outputMime: 'image/jpeg'}) onSelectNewAvatar(compressed) }, [onSelectNewAvatar], diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 0e504a787..76f58ddfa 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -115,7 +115,7 @@ export function UserBanner({ const onChangeEditImage = useCallback( async (image: ComposerImage) => { - const compressed = await compressImage(image) + const compressed = await compressImage(image, {outputMime: 'image/jpeg'}) onSelectNewBanner?.(compressed) }, [onSelectNewBanner],