this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Optimize compressImage method to also use binary search (#7490)

* use binary search for compressImage

* use binary search for doResize (mobile version)

* use binary search for doResize (web version)

* use safeDeleteAsync in compressImage

---------

Co-authored-by: nguyen <nguyensvo123@gmail.com>

authored by

Kae
nguyen
and committed by
GitHub
1eb678ca ea718190

+56 -21
+20 -7
src/lib/media/manip.ts
··· 178 178 height: imageRes.height, 179 179 }) 180 180 181 - for (let i = 0; i < 9; i++) { 182 - // nearest 10th 183 - const quality = Math.round((1 - 0.1 * i) * 10) / 10 181 + let minQualityPercentage = 0 182 + let maxQualityPercentage = 101 // exclusive 183 + let newDataUri 184 + 185 + while (maxQualityPercentage - minQualityPercentage > 1) { 186 + const qualityPercentage = Math.round( 187 + (maxQualityPercentage + minQualityPercentage) / 2, 188 + ) 184 189 const resizeRes = await manipulateAsync( 185 190 localUri, 186 191 [{resize: newDimensions}], 187 192 { 188 193 format: SaveFormat.JPEG, 189 - compress: quality, 194 + compress: qualityPercentage / 100, 190 195 }, 191 196 ) 192 197 ··· 198 203 } 199 204 200 205 if (fileInfo.size < opts.maxSize) { 201 - safeDeleteAsync(imageRes.uri) 202 - return { 206 + minQualityPercentage = qualityPercentage 207 + newDataUri = { 203 208 path: normalizePath(resizeRes.uri), 204 209 mime: 'image/jpeg', 205 210 size: fileInfo.size, ··· 207 212 height: resizeRes.height, 208 213 } 209 214 } else { 210 - safeDeleteAsync(resizeRes.uri) 215 + maxQualityPercentage = qualityPercentage 211 216 } 217 + 218 + safeDeleteAsync(resizeRes.uri) 212 219 } 220 + 221 + if (newDataUri) { 222 + safeDeleteAsync(imageRes.uri) 223 + return newDataUri 224 + } 225 + 213 226 throw new Error( 214 227 `This image is too big! We couldn't compress it down to ${opts.maxSize} bytes`, 215 228 )
+16 -5
src/lib/media/manip.web.ts
··· 72 72 async function doResize(dataUri: string, opts: DoResizeOpts): Promise<RNImage> { 73 73 let newDataUri 74 74 75 - for (let i = 0; i <= 10; i++) { 76 - newDataUri = await createResizedImage(dataUri, { 75 + let minQualityPercentage = 0 76 + let maxQualityPercentage = 101 //exclusive 77 + 78 + while (maxQualityPercentage - minQualityPercentage > 1) { 79 + const qualityPercentage = Math.round( 80 + (maxQualityPercentage + minQualityPercentage) / 2, 81 + ) 82 + const tempDataUri = await createResizedImage(dataUri, { 77 83 width: opts.width, 78 84 height: opts.height, 79 - quality: 1 - i * 0.1, 85 + quality: qualityPercentage / 100, 80 86 mode: opts.mode, 81 87 }) 82 - if (getDataUriSize(newDataUri) < opts.maxSize) { 83 - break 88 + 89 + if (getDataUriSize(tempDataUri) < opts.maxSize) { 90 + minQualityPercentage = qualityPercentage 91 + newDataUri = tempDataUri 92 + } else { 93 + maxQualityPercentage = qualityPercentage 84 94 } 85 95 } 96 + 86 97 if (!newDataUri) { 87 98 throw new Error('Failed to compress image') 88 99 }
+20 -9
src/state/gallery.ts
··· 13 13 import {nanoid} from 'nanoid/non-secure' 14 14 15 15 import {POST_IMG_MAX} from '#/lib/constants' 16 - import {getImageDim} from '#/lib/media/manip' 16 + import {getImageDim, safeDeleteAsync} from '#/lib/media/manip' 17 17 import {openCropper} from '#/lib/media/picker' 18 18 import {getDataUriSize} from '#/lib/media/util' 19 19 import {isIOS, isNative} from '#/platform/detection' ··· 212 212 const [w, h] = containImageRes(source.width, source.height, POST_IMG_MAX) 213 213 const cacheDir = isNative && getImageCacheDirectory() 214 214 215 - for (let i = 10; i > 0; i--) { 216 - // Float precision 217 - const factor = i / 10 215 + let minQualityPercentage = 0 216 + let maxQualityPercentage = 101 // exclusive 217 + let newDataUri 218 + 219 + while (maxQualityPercentage - minQualityPercentage > 1) { 220 + const qualityPercentage = Math.round( 221 + (maxQualityPercentage + minQualityPercentage) / 2, 222 + ) 218 223 219 224 const res = await manipulateAsync( 220 225 source.path, 221 226 [{resize: {width: w, height: h}}], 222 227 { 223 - compress: factor, 228 + compress: qualityPercentage / 100, 224 229 format: SaveFormat.JPEG, 225 230 base64: true, 226 231 }, ··· 229 234 const base64 = res.base64 230 235 231 236 if (base64 !== undefined && getDataUriSize(base64) <= POST_IMG_MAX.size) { 232 - return { 237 + minQualityPercentage = qualityPercentage 238 + newDataUri = { 233 239 path: await moveIfNecessary(res.uri), 234 240 width: res.width, 235 241 height: res.height, 236 242 mime: 'image/jpeg', 243 + } 244 + } else { 245 + maxQualityPercentage = qualityPercentage 246 + if (cacheDir) { 247 + await safeDeleteAsync(res.uri) 237 248 } 238 249 } 250 + } 239 251 240 - if (cacheDir) { 241 - await deleteAsync(res.uri) 242 - } 252 + if (newDataUri) { 253 + return newDataUri 243 254 } 244 255 245 256 throw new Error(`Unable to compress image`)