Skip to content

fix(ios): honour numeric Image.compress options - #422

Merged
numandev1 merged 1 commit into
numandev1:mainfrom
TheWygoda:fix/ios-image-numeric-options
Oct 25, 2026
Merged

numandev1 merged 1 commit into
numandev1:mainfrom
TheWygoda:fix/ios-image-numeric-options

Conversation

@TheWygoda

@TheWygoda TheWygoda commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

On iOS every numeric option passed to Image.compress (maxWidth, maxHeight, quality, progressDivider) is silently replaced by its default, so images always come out bounded by 1280 px at quality 0.8. This is the bug reported in #417.

Cause: Nitro hands JS numbers to Swift as Double (AnyValue.number(Double)). Neither normalize() nor the NSDictionary round-trip in HybridCompressor.dictionary(from:) boxes them into NSNumber. ImageCompressorOptions.fromDictionary then reads them with as? Int / as? Float. Those casts never match a Double, so every value falls back to its ?? default.

These paths are not affected:

  • Android: React Native's native map converts the double in getInt.
  • Video: VideoMain already reads its numeric options through NSNumber.

Fix: read the four numeric options through NSNumber (.intValue / .floatValue), which bridges a Double, an Int and an NSNumber alike. Defaults and all other options are unchanged.

Test: the harness image test already compressed the 16×16 fixture with maxWidth/maxHeight: 8, but only asserted that the output was non-empty. It now asserts the 8 px bound, so it fails without this fix.

Changelog

[iOS] [Fixed] - Image.compress honours maxWidth, maxHeight, quality and progressDivider instead of always using their defaults

Test Plan

  • Ran the local JS PR gate, yarn test:pr: 13/13 tests pass, typecheck is clean, lint reports 0 errors (the 9 warnings are pre-existing, in other files).

  • Ran the harness on an iOS simulator, yarn test:harness:ios: 9/9 pass. Setup: iPhone 17 Pro on iOS 26.5, picked via RN_HARNESS_IOS_DEVICE / RN_HARNESS_IOS_VERSION; Xcode 26.6; example app built with the same xcodebuild command as build-ios.yml.

    • Control: the same build with the original ImageCompressorOptions.swift and the new assertion fails 1 test (8 pass) with expected 1280 to be less than or equal to 8. Without the fix, manual mode used the 1280 default bound and scaled the 16×16 fixture up to 1280 px.
  • Replayed the exact option hand-off in a standalone Swift script: a Nitro Double, through normalize() and the NSDictionary round-trips, into the patched ImageCompressorOptions.fromDictionary.

    Input Before After
    maxWidth/maxHeight: 480, quality: 0.7 1280 / 0.8 480 / 0.7
    No options 1280 / 0.8 1280 / 0.8 (defaults unchanged)
  • Applied the same change to 2.0.3 through a patch in an app (RN 0.86.3, react-native-nitro-modules 0.37.1, iOS 26.5 simulator). Compressing a 5712×4284 JPEG with maxWidth/maxHeight: 480 gave 1280×960 before and 480×361 after.

🤖 Generated with Claude Code

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 numandev1#417

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The narrow conversion fix preserves defaults and includes targeted regression assertions, with no blocking issues identified.

No open issues 🎉

What changed in this PR

Fixes #417 by allowing the iOS image compressor to read numeric options passed through Nitro instead of falling back to defaults.

Changes:

  • Reads all four numeric image options through NSNumber, preserving existing defaults.
  • Strengthens the native harness test to assert that compressed dimensions respect the requested 8 px bounds.

Native runtime tests were not independently rerun during this review.

File Description
ios/​Image/​ImageCompressorOptions.swift Corrects numeric option conversion for dimensions, quality, and progress interval.
harness/​native-compressor.harness.ts Adds dimension assertions to catch the resizing regression.

Review effort: Balanced

@numandev1
numandev1 marked this pull request as ready for review October 25, 2026 00:32
@numandev1
numandev1 merged commit 80a7d7a into numandev1:main Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants