I'm trying to use an NSImage
that represents an SF Symbol as the contents
of a CALayer
. NSImage
has an API for this in the form of [NSImage layerContentsForContentsScale:]
. On the NSImage
documentation page, there's even a few paragraph at the top dedicated to using this very method.
But how do you set the color you want the image to render as if the image is an SF Symbol? NSImageView
has .contentTintColor
which works great, but CALayer
has no such property.
final class SymbolLayer: CALayer {
func display() {
// Just an example...
let image = NSImage(systemSymbolName: "paperclip", accessibilityDescription: nil)!
let actualScaleFactor = image.recommendedLayerContentsScale(contentsScale)
// This obviously produces a black image because there's no color or tint information anywhere.
contents = image.layerContents(forContentsScale: actualScaleFactor)
}
}
Is there a way you can configure the CALayer
or the NSImage
itself to have some sort of color information when it generates the layer contents? I've attempted to play around with the SymbolConfiguration
coolers but without any success. (Even when wrapped inside NSAppearance.performAsCurrentDrawingAppearance
.)
The best I can come up with is to use CALayer.draw(in:)
and then use the old NSImage.cgImage(forProposedRect:...)
API. I can then set the fill color on the CGContext
and go from there. Is there a more efficient way?
override func draw(in context: CGContext) {
let image = NSImage(systemSymbolName: "paperclip", accessibilityDescription: nil)!
var rect = bounds
image.size = bounds.size
let cgImage = image.cgImage(
forProposedRect: &rect,
context: nil,
hints: [.ctm: AffineTransform(scale: contentsScale)]
)!
NSApp.effectiveAppearance.performAsCurrentDrawingAppearance {
// Draw using an Appearance-sensitive color.
context.clip(to: bounds, mask: cgImage)
context.setFillColor(NSColor.labelColor.cgColor)
context.fill(bounds)
}
}
This is for macOS 12+.