Add resolution downsizing to image compression (#10117)

This commit is contained in:
Eric Bailey
2026-03-24 14:34:51 -05:00
committed by GitHub
parent 6a15ca88b6
commit 3e37696d88
+24 -13
View File
@@ -207,27 +207,38 @@ export async function compressImage(
}, },
): Promise<PickerImage> { ): Promise<PickerImage> {
const source = img.transformed || img.source const source = img.transformed || img.source
const highResolution = options?.highResolution ?? false
const [w, h] = containImageRes( let attempts = 0
source.width, let maxDimension = highResolution ? 4000 : POST_IMG_MAX.width
source.height,
options?.highResolution
? {
width: 4000,
height: 4000,
}
: POST_IMG_MAX,
)
let minQualityPercentage = 0 let minQualityPercentage = 0
let maxQualityPercentage = 101 // exclusive let maxQualityPercentage = 101 // exclusive
let newDataUri let newDataUri
while (maxQualityPercentage - minQualityPercentage > 1) { while (maxQualityPercentage - minQualityPercentage > 1) {
if (attempts >= 4) break
const [w, h] = containImageRes(source.width, source.height, maxDimension)
const qualityPercentage = Math.round( const qualityPercentage = Math.round(
(maxQualityPercentage + minQualityPercentage) / 2, (maxQualityPercentage + minQualityPercentage) / 2,
) )
/*
* In the event the image doesn't compress well, we want to avoid
* unecessary iterations. In this case, binary search will check 51, 26,
* 13(rounded). We don't want to go below 25, so if we've halved to 13,
* reset the loop and reduce the image dimensions instead.
*/
if (qualityPercentage <= 13) {
minQualityPercentage = 0
maxQualityPercentage = 101
attempts++
// 4000px → 3200px → 2560px → 2048px → ~1638px
maxDimension = Math.floor(maxDimension * 0.8)
continue
}
const res = await manipulateAsync( const res = await manipulateAsync(
source.path, source.path,
[{resize: {width: w, height: h}}], [{resize: {width: w, height: h}}],
@@ -366,12 +377,12 @@ function joinPath(a: string, b: string) {
function containImageRes( function containImageRes(
w: number, w: number,
h: number, h: number,
{width: maxW, height: maxH}: {width: number; height: number}, max: number,
): [width: number, height: number] { ): [width: number, height: number] {
let scale = 1 let scale = 1
if (w > maxW || h > maxH) { if (w > max || h > max) {
scale = w > h ? maxW / w : maxH / h scale = w > h ? max / w : max / h
w = Math.floor(w * scale) w = Math.floor(w * scale)
h = Math.floor(h * scale) h = Math.floor(h * scale)
} }