diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/media/manip.ts | 27 | ||||
-rw-r--r-- | src/lib/media/manip.web.ts | 21 | ||||
-rw-r--r-- | src/state/gallery.ts | 29 |
3 files changed, 56 insertions, 21 deletions
diff --git a/src/lib/media/manip.ts b/src/lib/media/manip.ts index 7f052068d..f6ef8347d 100644 --- a/src/lib/media/manip.ts +++ b/src/lib/media/manip.ts @@ -178,15 +178,20 @@ async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> { height: imageRes.height, }) - for (let i = 0; i < 9; i++) { - // nearest 10th - const quality = Math.round((1 - 0.1 * i) * 10) / 10 + let minQualityPercentage = 0 + let maxQualityPercentage = 101 // exclusive + let newDataUri + + while (maxQualityPercentage - minQualityPercentage > 1) { + const qualityPercentage = Math.round( + (maxQualityPercentage + minQualityPercentage) / 2, + ) const resizeRes = await manipulateAsync( localUri, [{resize: newDimensions}], { format: SaveFormat.JPEG, - compress: quality, + compress: qualityPercentage / 100, }, ) @@ -198,8 +203,8 @@ async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> { } if (fileInfo.size < opts.maxSize) { - safeDeleteAsync(imageRes.uri) - return { + minQualityPercentage = qualityPercentage + newDataUri = { path: normalizePath(resizeRes.uri), mime: 'image/jpeg', size: fileInfo.size, @@ -207,9 +212,17 @@ async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> { height: resizeRes.height, } } else { - safeDeleteAsync(resizeRes.uri) + maxQualityPercentage = qualityPercentage } + + safeDeleteAsync(resizeRes.uri) } + + if (newDataUri) { + safeDeleteAsync(imageRes.uri) + return newDataUri + } + throw new Error( `This image is too big! We couldn't compress it down to ${opts.maxSize} bytes`, ) diff --git a/src/lib/media/manip.web.ts b/src/lib/media/manip.web.ts index 4761f2fe0..ffef7314d 100644 --- a/src/lib/media/manip.web.ts +++ b/src/lib/media/manip.web.ts @@ -72,17 +72,28 @@ interface DoResizeOpts { async function doResize(dataUri: string, opts: DoResizeOpts): Promise<RNImage> { let newDataUri - for (let i = 0; i <= 10; i++) { - newDataUri = await createResizedImage(dataUri, { + let minQualityPercentage = 0 + let maxQualityPercentage = 101 //exclusive + + while (maxQualityPercentage - minQualityPercentage > 1) { + const qualityPercentage = Math.round( + (maxQualityPercentage + minQualityPercentage) / 2, + ) + const tempDataUri = await createResizedImage(dataUri, { width: opts.width, height: opts.height, - quality: 1 - i * 0.1, + quality: qualityPercentage / 100, mode: opts.mode, }) - if (getDataUriSize(newDataUri) < opts.maxSize) { - break + + if (getDataUriSize(tempDataUri) < opts.maxSize) { + minQualityPercentage = qualityPercentage + newDataUri = tempDataUri + } else { + maxQualityPercentage = qualityPercentage } } + if (!newDataUri) { throw new Error('Failed to compress image') } diff --git a/src/state/gallery.ts b/src/state/gallery.ts index f4c8b712e..55d08785e 100644 --- a/src/state/gallery.ts +++ b/src/state/gallery.ts @@ -13,7 +13,7 @@ import { import {nanoid} from 'nanoid/non-secure' import {POST_IMG_MAX} from '#/lib/constants' -import {getImageDim} from '#/lib/media/manip' +import {getImageDim, safeDeleteAsync} from '#/lib/media/manip' import {openCropper} from '#/lib/media/picker' import {getDataUriSize} from '#/lib/media/util' import {isIOS, isNative} from '#/platform/detection' @@ -212,15 +212,20 @@ export async function compressImage(img: ComposerImage): Promise<ImageMeta> { const [w, h] = containImageRes(source.width, source.height, POST_IMG_MAX) const cacheDir = isNative && getImageCacheDirectory() - for (let i = 10; i > 0; i--) { - // Float precision - const factor = i / 10 + let minQualityPercentage = 0 + let maxQualityPercentage = 101 // exclusive + let newDataUri + + while (maxQualityPercentage - minQualityPercentage > 1) { + const qualityPercentage = Math.round( + (maxQualityPercentage + minQualityPercentage) / 2, + ) const res = await manipulateAsync( source.path, [{resize: {width: w, height: h}}], { - compress: factor, + compress: qualityPercentage / 100, format: SaveFormat.JPEG, base64: true, }, @@ -229,17 +234,23 @@ export async function compressImage(img: ComposerImage): Promise<ImageMeta> { const base64 = res.base64 if (base64 !== undefined && getDataUriSize(base64) <= POST_IMG_MAX.size) { - return { + minQualityPercentage = qualityPercentage + newDataUri = { path: await moveIfNecessary(res.uri), width: res.width, height: res.height, mime: 'image/jpeg', } + } else { + maxQualityPercentage = qualityPercentage + if (cacheDir) { + await safeDeleteAsync(res.uri) + } } + } - if (cacheDir) { - await deleteAsync(res.uri) - } + if (newDataUri) { + return newDataUri } throw new Error(`Unable to compress image`) |