about summary refs log tree commit diff
path: root/src/lib/images.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/images.ts')
-rw-r--r--src/lib/images.ts97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/lib/images.ts b/src/lib/images.ts
new file mode 100644
index 000000000..caeb96d27
--- /dev/null
+++ b/src/lib/images.ts
@@ -0,0 +1,97 @@
+import RNFetchBlob from 'rn-fetch-blob'
+import ImageResizer from '@bam.tech/react-native-image-resizer'
+import {Image as PickedImage} from 'react-native-image-crop-picker'
+
+export interface DownloadAndResizeOpts {
+  uri: string
+  width: number
+  height: number
+  mode: 'contain' | 'cover' | 'stretch'
+  maxSize: number
+  timeout: number
+}
+
+export async function downloadAndResize(opts: DownloadAndResizeOpts) {
+  let appendExt
+  try {
+    const urip = new URL(opts.uri)
+    const ext = urip.pathname.split('.').pop()
+    if (ext === 'jpg' || ext === 'jpeg') {
+      appendExt = 'jpeg'
+    } else if (ext === 'png') {
+      appendExt = 'png'
+    } else {
+      return
+    }
+  } catch (e: any) {
+    console.error('Invalid URI', opts.uri, e)
+    return
+  }
+
+  let downloadRes
+  try {
+    const downloadResPromise = RNFetchBlob.config({
+      fileCache: true,
+      appendExt,
+    }).fetch('GET', opts.uri)
+    const to1 = setTimeout(() => downloadResPromise.cancel(), opts.timeout)
+    downloadRes = await downloadResPromise
+    clearTimeout(to1)
+
+    let localUri = downloadRes.path()
+    if (!localUri.startsWith('file://')) {
+      localUri = `file://${localUri}`
+    }
+
+    return await resize(localUri, opts)
+  } finally {
+    if (downloadRes) {
+      downloadRes.flush()
+    }
+  }
+}
+
+export interface ResizeOpts {
+  width: number
+  height: number
+  mode: 'contain' | 'cover' | 'stretch'
+  maxSize: number
+}
+
+export async function resize(localUri: string, opts: ResizeOpts) {
+  for (let i = 0; i < 9; i++) {
+    const quality = 1.0 - i / 10
+    const resizeRes = await ImageResizer.createResizedImage(
+      localUri,
+      opts.width,
+      opts.height,
+      'JPEG',
+      quality,
+      undefined,
+      undefined,
+      undefined,
+      {mode: opts.mode},
+    )
+    console.log(quality, resizeRes)
+    if (resizeRes.size < opts.maxSize) {
+      return resizeRes
+    }
+  }
+  throw new Error(
+    `This image is too big! We couldn't compress it down to ${opts.maxSize} bytes`,
+  )
+}
+
+export async function compressIfNeeded(img: PickedImage, maxSize: number) {
+  const origUri = `file://${img.path}`
+  if (img.size < maxSize) {
+    return origUri
+  }
+  const resizeRez = await resize(origUri, {
+    width: img.width,
+    height: img.height,
+    mode: 'stretch',
+    maxSize,
+  })
+  return resizeRez.uri
+}