From 3c23b910c66de18ef20ca91f62bacedde789e019 Mon Sep 17 00:00:00 2001 From: Kacper Wygoda Date: Fri, 2 Oct 2026 12:49:35 +0200 Subject: [PATCH] fix(ios): honour numeric Image.compress options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On iOS every numeric Image.compress option (maxWidth, maxHeight, quality, progressDivider) was silently replaced by its default, so images always came out bounded by 1280 px at quality 0.8. Nitro hands JS numbers to Swift as Double, and ImageCompressorOptions read them with `as? Int` / `as? Float`, which never match a Double. Read them through NSNumber instead, as VideoMain already does for its options. The harness image test already passed maxWidth/maxHeight 8 for a 16×16 fixture but only checked that the output was non-empty; it now asserts the bound. Fixes #417 Co-Authored-By: Claude Opus 5.5 --- harness/native-compressor.harness.ts | 3 +++ ios/Image/ImageCompressorOptions.swift | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/harness/native-compressor.harness.ts b/harness/native-compressor.harness.ts index 4cd89a27..32e39a36 100644 --- a/harness/native-compressor.harness.ts +++ b/harness/native-compressor.harness.ts @@ -133,6 +133,9 @@ describe('react-native-compressor native harness', () => { const metadata = await getImageMetaData(output); expect(metadata.ImageWidth).toBeGreaterThan(0); expect(metadata.ImageHeight).toBeGreaterThan(0); + // the fixture is 16×16, so maxWidth/maxHeight must shrink it (#417) + expect(metadata.ImageWidth).toBeLessThanOrEqual(8); + expect(metadata.ImageHeight).toBeLessThanOrEqual(8); expect(metadata.size).toBeGreaterThan(0); expect(metadata.exif).toBeTruthy(); diff --git a/ios/Image/ImageCompressorOptions.swift b/ios/Image/ImageCompressorOptions.swift index d45b88df..ded6951a 100644 --- a/ios/Image/ImageCompressorOptions.swift +++ b/ios/Image/ImageCompressorOptions.swift @@ -28,14 +28,18 @@ class ImageCompressorOptions: NSObject { switch key { case "compressionMethod": options.autoCompress = (value as? String ?? "") != "manual" + // Nitro hands every JS number over as a Swift Double, which `as? Int` and + // `as? Float` never match, so these options silently fell back to their + // defaults (#417). NSNumber bridges a Double, an Int and an NSNumber alike, + // the same cast VideoMain uses for its numeric options. case "maxWidth": - options.maxWidth = (value as? Int) ?? 1280 + options.maxWidth = (value as? NSNumber)?.intValue ?? 1280 case "maxHeight": - options.maxHeight = (value as? Int) ?? 1280 + options.maxHeight = (value as? NSNumber)?.intValue ?? 1280 case "progressDivider": - options.progressDivider = (value as? Int) ?? 0 + options.progressDivider = (value as? NSNumber)?.intValue ?? 0 case "quality": - options.quality = (value as? Float) ?? 0.8 + options.quality = (value as? NSNumber)?.floatValue ?? 0.8 case "input": options.parseInput(value as? String) case "output":