Fix asset catalog scale-to-file pairing for assets with non-standard scales - #57825
Open
janicduplessis wants to merge 1 commit into
Open
Fix asset catalog scale-to-file pairing for assets with non-standard scales#57825janicduplessis wants to merge 1 commit into
janicduplessis wants to merge 1 commit into
Conversation
…ndard scales The iOS asset catalog path filtered asset scales through filterPlatformAssetScales but indexed the unfiltered asset.files array, so an asset with scales [1, 1.5, 2, 3] would associate the 2x catalog rendition with the 1.5x file and the 3x rendition with the 2x file. Additionally, assets with no standard scale at all (e.g. only @1.5x) produced an imageset actool silently drops from Assets.car, making the image unloadable when RCTUseAssetCatalog is enabled. These assets now map their closest variant into the nearest valid slot (the same "closest larger" fallback filterPlatformAssetScales applies to loose files) with a build-log warning, so every imageset contains at least one rendition actool will compile.
3 tasks
janicduplessis
marked this pull request as ready for review
August 5, 2026 12:27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
saveAssetsfilters an asset's scales throughfilterPlatformAssetScales, butgetImageSetindexes the unfilteredasset.files, so an asset with scales[1, 1.5, 2, 3]gets the 1.5x file in its 2x catalog slot and the 2x file in its 3x slot:Assets.carships the wrong images. An asset with no standard scale at all (only@1.5x, say) produces an imageset actool silently drops from the car, which makes the image unloadable whenRCTUseAssetCatalogis on, since the catalog runtime has no filesystem fallback (#30129).Fix, in
assetCatalogIOS.js:Related: expo/expo#48525 applies the same fix to Expo CLI's mirrored implementation.
Changelog:
[IOS] [FIXED] - Asset catalog imagesets paired wrong files for assets with non-standard scales
Test Plan:
New unit tests in
assetCatalogIOS-test.js: standard 1x/2x/3x pairing, mixed[1, 1.5, 2, 3](regression for the file shift), fractional-only[1.5], and[4]clamping to the 3x slot.End-to-end
Bundled a test app through the real pipeline (Metro →
saveAssets→ actool →assetutil --infoon the compiledAssets.car) with two assets:logoat scales[1, 1.5, 2, 3](100/150/200/300 px) andstarwith only a@1.5xfile (150 px).Assets.carimg_logo1ximg_logo2ximg_logo3ximg_star@1.5ximageset)Running on an iPhone 17 Pro simulator (3x), same app built with the buggy and fixed CLI — the labeled tiles show which file the catalog actually served, and
stargoes from missing to rendering:Repro app used for the screenshots
Built
private/helloworld(Release, simulator) withRCTUseAssetCatalogset totruein its Info.plist, and these assets inimg/, where each file is a solid tile with its scale label and pixel size baked into the image so a screenshot shows exactly which file got served:logo.png(100px, "1x"),logo@1.5x.png(150px, "1.5x"),logo@2x.png(200px, "2x"),logo@3x.png(300px, "3x"), andstar@1.5x.png(150px, "STAR") with no other variants.On the 3x simulator JS resolves
logoto the 3x variant, so the tile that renders is the file the catalog's 3x slot actually contains: the 2x-labeled tile before the fix, the 3x tile after.starresolves to its only variant (@1.5x); before the fix its imageset is dropped by actool and the box renders empty.