When I get imageWithSystemSymbolName, I get black graphics on a transparent background. How can I get white symbols?
When I look at the symbols (like triangle.circle) in SF Symbols, they're all white on transparent. For example, I want to draw triangle.circle.fill on a black screen, so I don't want a black image.
I'm doing something like this to get SF Symbols (as NSData to pass them as a byte array into Unity):
When I look at the symbols (like triangle.circle) in SF Symbols, they're all white on transparent. For example, I want to draw triangle.circle.fill on a black screen, so I don't want a black image.
I'm doing something like this to get SF Symbols (as NSData to pass them as a byte array into Unity):
Code Block objc NSData* GetSymbolImageAsBytes(int width, int height) { GCController *gc = [GCController current]; NSString *name = gc.extendedGamepad.buttonY.sfSymbolsName; NSImage *image = [NSImage imageWithSystemSymbolName: name accessibilityDescription: nil ]; // https://stackoverflow.com/a/38442746/79125 NSSize size = NSMakeSize(width, height); NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:size.width pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:0 bitsPerPixel:0]; rep.size = size; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]]; [image drawInRect:NSMakeRect(0, 0, size.width, size.height) fromRect:NSZeroRect operation:NSCompositingOperationCopy fraction:1.0]; [NSGraphicsContext restoreGraphicsState]; if (rep == nil) { return nil; } // Passing nil gives a warning but seems to work okay. return [rep representationUsingType:NSBitmapImageFileTypePNG properties:nil]; }
Normally any styling (such as tints) are applied at the time the symbol is drawn by the UI element (button, etc) because it's context sensitive to the state of the UI element (pressed, disabled, etc).
To do this yourself, setup a CG transparency layer right before drawing the symbol:
Note that by doing this your are stripping the symbol image of its configuration and layout metrics. It won't be able to adapt to different point sizes or weights, and baseline offsets will be lost. This means, for instance, that the minus symbol will be 3 pixels tall at typical point sizes. If you simply draw that based on its bitmap size it will look like an underscore.
To fix this you need to pay attention to the NSImage's alignmentRect property, which is a rectangle whose bottom edge is the baseline and top edge is the capHeight.
To do this yourself, setup a CG transparency layer right before drawing the symbol:
Code Block Objective-C NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; [graphicsContext saveGraphicsState]; CGContextRef context = [graphicsContext CGContext]; CGContextBeginTransparencyLayerWithRect(context, dstRect, nil); CGContextSetBlendMode(context, kCGBlendModeNormal); /* draw the image */ CGContextSetBlendMode(context, kCGBlendModeSourceIn); CGContextSetFillColor(context, /* desired fill color */); CGContextFillRect(context, dstRect); CGContextEndTransparencyLayer(context);
Note that by doing this your are stripping the symbol image of its configuration and layout metrics. It won't be able to adapt to different point sizes or weights, and baseline offsets will be lost. This means, for instance, that the minus symbol will be 3 pixels tall at typical point sizes. If you simply draw that based on its bitmap size it will look like an underscore.
To fix this you need to pay attention to the NSImage's alignmentRect property, which is a rectangle whose bottom edge is the baseline and top edge is the capHeight.