SKTexture initialized with system UIImage has slightly wrong aspect ratio and ignores system symbol color

On macOS, system symbols displays in a SKTexture as expected, with the correct color and aspect ratio.

But on iOS they are always displayed in black, and sometimes with slightly wrong aspect ratio.

Is there a solution to this problem?

import SpriteKit
#if os(macOS)
import AppKit
#else
import UIKit
#endif

class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        let systemImage = "square.and.arrow.up"
        let width = 400.0
        #if os(macOS)
        let image = NSImage(systemSymbolName: systemImage, accessibilityDescription: nil)!.withSymbolConfiguration(.init(hierarchicalColor: .white))!
        let scale = NSScreen.main!.backingScaleFactor
        image.size = CGSize(width: width * scale, height: width / image.size.width * image.size.height * scale)
        #else
        let image = UIImage(systemName: systemImage)!.applyingSymbolConfiguration(.init(pointSize: width))!.applyingSymbolConfiguration(.init(hierarchicalColor: .white))!
        #endif
        let texture = SKTexture(image: image)
        print(image.size, texture.size(), image.size.width / image.size.height)
        let size = CGSize(width: width, height: width / image.size.width * image.size.height)
        addChild(SKSpriteNode(texture: texture, size: size))
    }

}
Answered by Nickkk in 803966022

In principle you could render the UIImage into a graphics context and then create your SKTexture from that.

That's a great idea. I changed the iOS code to this and it seems to work for both aspect ratio and color:

var image = UIImage(systemName: systemImage)!.applyingSymbolConfiguration(.init(pointSize: width))!.applyingSymbolConfiguration(.init(hierarchicalColor: .white))!
image = UIGraphicsImageRenderer(size: image.size).image { context in
    image.draw(at: .zero)
}

This may be a bug in SpriteKit given your description.

Have you filed a bug report? If so please reply with the Feedback ID.

Have you filed a bug report? If so please reply with the Feedback ID.

I filed FB15095279 shortly before I created this post.

Acknowledged and appreciated!

UIImage and CGImage have different aspect ratios for SF Symbols, due to padding. Have a look at this thread:

https://developer.apple.com/forums/thread/716773

It wouldn’t surprise me if SKTexture does the same thing.

UIImage and CGImage have different aspect ratios for SF Symbols, due to padding.

I tried using SKTexture(image: image) and SKTexture(cgImage: image.cgImage!) and they both produce the same result. Do you think this is expected or do you have a suggestion for how one could do it differently?

I believe there is no way to get the extra padding info. Yes I filed a bug ha ha ha. In principle you could render the UIImage into a graphics context and then create your SKTexture from that. Do you actually care about accurate typographic alignment of your symbol? If not, just use what you have.

I know nothing about the colour issues you have mentioned.

Accepted Answer

In principle you could render the UIImage into a graphics context and then create your SKTexture from that.

That's a great idea. I changed the iOS code to this and it seems to work for both aspect ratio and color:

var image = UIImage(systemName: systemImage)!.applyingSymbolConfiguration(.init(pointSize: width))!.applyingSymbolConfiguration(.init(hierarchicalColor: .white))!
image = UIGraphicsImageRenderer(size: image.size).image { context in
    image.draw(at: .zero)
}

^ looks like a reasonable workaround.

The only remaining concern is performance but it seems like you would only call this sparingly during view layout.

SKTexture initialized with system UIImage has slightly wrong aspect ratio and ignores system symbol color
 
 
Q