about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/lib/media/manip.ts27
-rw-r--r--src/lib/media/manip.web.ts21
-rw-r--r--src/state/gallery.ts29
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`)