We are developing a game on UnrealEngine4 and we need the PNG representation of a SF Symbol to display it on our UI.
After watching WWDC sessions and reading the documentation, we achieved it by calling:
However, it outputs an image of 18x14 pixels. We need an image of size 64x64 pixels.
How can we resize it before getting the PNG representation so it can be displayed larger on the screen?
After watching WWDC sessions and reading the documentation, we achieved it by calling:
Code Block NSImage* nsImage = [NSImage imageWithSystemSymbolName:symbolNameString accessibilityDescription:nil]; NSImageSymbolConfiguration* config = [NSImageSymbolConfiguration configurationWithPointSize:100 weight:NSFontWeightBlack scale:NSImageSymbolScaleLarge]; NSImage* nsImageWithConfig = [nsImage imageWithSymbolConfiguration:config]; NSData* tiff = [nsImageWithConfig TIFFRepresentation]; NSBitmapImageRep* raw_img = [NSBitmapImageRep imageRepWithData:tiff]; NSDictionary* dict = [NSDictionary dictionary]; NSData* nsData = [raw_img representationUsingType:NSBitmapImageFileTypePNG properties:dict];
However, it outputs an image of 18x14 pixels. We need an image of size 64x64 pixels.
How can we resize it before getting the PNG representation so it can be displayed larger on the screen?
If you pass a rect with the desired size to CGImageForProposedRect it will scale the symbol to fit in that rect:
However this will still scale to the default display's scaleFactor, so on a 2x display you will get a 128x128 CGImage. If you must have it at 1x display scaleFactor no matter what, then you will need to supply your own CTM in the hints dictionary. You can just pass the identity transform:
This isn't something I would normally recommend for user interface code, but I suppose for a game engine you have certain constraints.
As for tinting the image, unfortunately we don't have API for that in NSImage yet. It can be done with CG drawing using a transparency layer and sourceIn blending:
(assuming you have a CGContext to draw into, even if only an offscreen bitmap).
Code Block NSRect symbolRect = NSMakeRect(0, 0, 64, 64); CGImageRef cgImage = [configuredSymbol CGImageForProposedRect:&symbolRect context:nil hints:nil];
However this will still scale to the default display's scaleFactor, so on a 2x display you will get a 128x128 CGImage. If you must have it at 1x display scaleFactor no matter what, then you will need to supply your own CTM in the hints dictionary. You can just pass the identity transform:
Code Block NSRect symbolRect = NSMakeRect(0, 0, 64, 64); CGImageRef cgImage = [configuredSymbol CGImageForProposedRect:&symbolRect context:nil hints:@{NSImageHintCTM: [NSAffineTransform transform]}];
This isn't something I would normally recommend for user interface code, but I suppose for a game engine you have certain constraints.
As for tinting the image, unfortunately we don't have API for that in NSImage yet. It can be done with CG drawing using a transparency layer and sourceIn blending:
Code Block CGContextBeginTransparencyLayerWithRect(context, dstRect, nil); CGContextSetBlendMode(context, kCGBlendModeNormal); CGContextDrawImage(context, glyphAlignmentRect, glyphImage); CGContextSetBlendMode(context, kCGBlendModeSourceIn); CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorWhite)); CGContextFillRect(context, dstRect); CGContextEndTransparencyLayer(context);
(assuming you have a CGContext to draw into, even if only an offscreen bitmap).