Skip to content

Commit 83d9b83

Browse files
chore(preprod): Add AssetCatalog Parsing support for Multisize sets (#2879)
Certain assets weren't getting picked up for the Firefox app, and the ones missing appeared to be multisize sets, like this ``` { "vector": false, "type": 0, "imageId": "42D31467-E63B-49D8-8D9B-1B608059E344", "size": 236, "height": 1024, "name": "AppIcon_Alt_Color_Purple", "filename": "AppIcon_Alt_Color_Purple", "idiom": "phone", "width": 1024 }, ``` They won't have a a file extension either it seems (ex. `Assets.car/AppIcon_Alt_Color_Purple`). So we'll go ahead and save them as a (default type) png
1 parent f57b472 commit 83d9b83

File tree

1 file changed

+81
-5
lines changed

1 file changed

+81
-5
lines changed

apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,32 @@ enum AssetUtil {
153153
let type = rendition.getUInt(forKey: "type") ?? 0
154154

155155
let isVector = type == 9
156-
let (width, height, unslicedImage) = resolveImageDimensions(rendition, isVector)
156+
let isMultisizeImageSet = type == 1010
157157
let assetType = determineAssetType(key)
158158
let imageId = UUID().uuidString
159-
160159
let fileExtension = (renditionTypeName as NSString).pathExtension.lowercased()
161160

162-
// Skip files without an extension or SVGs
163-
if !fileExtension.isEmpty && fileExtension != "svg", let unslicedImage = unslicedImage {
164-
images[imageId] = (cgImage: unslicedImage, format: fileExtension)
161+
var width: Int?
162+
var height: Int?
163+
var unslicedImage: CGImage?
164+
165+
if isMultisizeImageSet {
166+
// Look up the actual image rendition from the multisize set
167+
if let result = findImageForMultisizeSet(rendition, key, assetKeys, structuredThemeStore) {
168+
unslicedImage = result.image
169+
width = result.width
170+
height = result.height
171+
images[imageId] = (cgImage: unslicedImage!, format: "png")
172+
}
173+
} else {
174+
// Get image dimensions from regular rendition
175+
(width, height, unslicedImage) = resolveImageDimensions(rendition, isVector)
176+
177+
// Skip SVGs, but save images even if they don't have an extension (default to png)
178+
if fileExtension != "svg", let unslicedImage = unslicedImage {
179+
let format = fileExtension.isEmpty ? "png" : fileExtension
180+
images[imageId] = (cgImage: unslicedImage, format: format)
181+
}
165182
}
166183

167184
let idiomValue = key.getUInt(forKey: "themeIdiom")
@@ -276,6 +293,65 @@ enum AssetUtil {
276293
}
277294
return true
278295
}
296+
297+
private static func findImageForMultisizeSet(
298+
_ rendition: NSObject,
299+
_ key: NSObject,
300+
_ assetKeys: [NSObject],
301+
_ structuredThemeStore: NSObject
302+
) -> (image: CGImage, width: Int, height: Int)? {
303+
// Get the sizeIndexes to find the actual image
304+
guard rendition.responds(to: Selector(("sizeIndexes"))),
305+
let sizeIndexesResult = rendition.perform(Selector(("sizeIndexes"))),
306+
let sizeIndexesArray = sizeIndexesResult.takeUnretainedValue() as? NSArray,
307+
sizeIndexesArray.count > 0 else {
308+
return nil
309+
}
310+
311+
// Get the first size index
312+
let sizeIndexObj = sizeIndexesArray.object(at: 0) as! NSObject
313+
314+
// Get the idiom and subtype from the size index
315+
let idiom = sizeIndexObj.getUInt(forKey: "idiom") ?? 0
316+
let subtype = sizeIndexObj.getUInt(forKey: "subtype") ?? 0
317+
let keyElement = key.getUInt(forKey: "themeElement") ?? 0
318+
319+
// Look for a rendition with matching idiom and subtype in the asset keys
320+
for otherKey in assetKeys {
321+
let otherKeyIdiom = otherKey.getUInt(forKey: "themeIdiom") ?? 0
322+
let otherKeySubtype = otherKey.getUInt(forKey: "themeSubtype") ?? 0
323+
let otherKeyElement = otherKey.getUInt(forKey: "themeElement") ?? 0
324+
325+
// Find a key with matching element, idiom, and subtype
326+
guard otherKeyElement == keyElement,
327+
otherKeyIdiom == idiom,
328+
otherKeySubtype == subtype else {
329+
continue
330+
}
331+
332+
let otherKeyList = unsafeBitCast(
333+
otherKey.perform(Selector(("keyList"))),
334+
to: UnsafeMutableRawPointer.self
335+
)
336+
337+
guard let imageRendition = createRendition(from: structuredThemeStore, otherKeyList) else {
338+
continue
339+
}
340+
341+
let renditionType = imageRendition.getUInt(forKey: "type") ?? 0
342+
343+
// Skip if this is another multisize set (type 1010)
344+
guard renditionType != 1010,
345+
let result = imageRendition.perform(Selector(("unslicedImage"))) else {
346+
continue
347+
}
348+
349+
let image = result.takeUnretainedValue() as! CGImage
350+
return (image, image.width, image.height)
351+
}
352+
353+
return nil
354+
}
279355

280356
private static func determineAssetType(_ key: NSObject) -> AssetType {
281357
let themeElement = key.getUInt(forKey: "themeElement") ?? 0

0 commit comments

Comments
 (0)