How to create RGBA CGColorSpace / bitmap CGContext on Mac?

I'm working on migrating some image-drawing code away from NSImage lockFocus() to a bitmap CGContext. This is intended to compose image content for export to formats that support alpha like PNG and TIFF, with precise control over raster resolution etc. (not solely or primarily for window/device content).

I'm trying to create a generic 32-bit RGBA color space for the bitmap, which I thought would be straightforward, but Core Graphics rejects the CGImageAlphaInfo.last info value for a generic RGB color space (it only allows none, or premultiplied options). There is no generic "RGBA" color space constant/name. Is there a way to do this?

Attempt:

Code Block
if let colorspace = CGColorSpace(name: CGColorSpace.genericRGBLinear) {
      if let cgc = CGContext(data: nil,
                    width: Int(pixelWidth),
                    height: Int(pixelHeight),
                    bitsPerComponent: 8,
                    bytesPerRow: 0,
                    space: colorspace,
                    bitmapInfo: CGImageAlphaInfo.last.rawValue) {
// use cgc...
}


Error logged by Core Graphics:
Code Block
CGBitmapContextCreate: unsupported parameter combination:
  8 bits/component; integer;
  32 bits/pixel;
RGB color space model; kCGImageAlphaLast;
default byte order;
320 bytes/row.
Valid parameters for RGB color space model are:
16 bits per pixel, 5 bits per component, kCGImageAlphaNoneSkipFirst
32 bits per pixel, 8 bits per component, kCGImageAlphaNoneSkipFirst
32 bits per pixel, 8 bits per component, kCGImageAlphaNoneSkipLast
32 bits per pixel, 8 bits per component, kCGImageAlphaPremultipliedFirst
32 bits per pixel, 8 bits per component, kCGImageAlphaPremultipliedLast
32 bits per pixel, 10 bits per component, kCGImageAlphaNone|kCGImagePixelFormatRGBCIF10
64 bits per pixel, 16 bits per component, kCGImageAlphaPremultipliedLast
64 bits per pixel, 16 bits per component, kCGImageAlphaNoneSkipLast
64 bits per pixel, 16 bits per component, kCGImageAlphaPremultipliedLast|kCGBitmapFloatComponents|kCGImageByteOrder16Little
64 bits per pixel, 16 bits per component, kCGImageAlphaNoneSkipLast|kCGBitmapFloatComponents|kCGImageByteOrder16Little
128 bits per pixel, 32 bits per component, kCGImageAlphaPremultipliedLast|kCGBitmapFloatComponents
128 bits per pixel, 32 bits per component, kCGImageAlphaNoneSkipLast|kCGBitmapFloatComponents
 See Quartz 2D Programming Guide (available online) for more information.



TIA,
Christopher

Accepted Reply

Posting a reply to my own question here in case others encounter the same... While I'm not certain about the underlying design or when a non-precomposed RGBA setting would be possible or valid for a bitmap CGContext, that configuration turned out to not be needed.

I'm now using this code to generate my CGContext - it's sRGB color space, and the alpha value is set to premultiplied. I was concerned this would mean I would somehow need to do some premultiplied calculation for the use of semi-opaque colors in my drawing code, but this turns out not to be the case - I can obtain an image with a transparent background, and also set partial alpha values in colors set for fill or stroke while drawing, and everything works properly.

Code Block
if let colorspace = CGColorSpace(name: CGColorSpace.sRGB) {
      if let cgc = CGContext(data: nil,
                    width: Int(pixelWidth),
                    height: Int(pixelHeight),
                    bitsPerComponent: 16,
                    bytesPerRow: 0,
                    space: colorspace,
                    bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue |
                    CGBitmapInfo.byteOrder16Little.rawValue |
                    CGBitmapInfo.floatComponents.rawValue) {
...


So my answer in a nutshell is, if you want to use a bitmap CGContext for use in a Mac app with RGB color space that includes transparency, you can just use sRGB color space and premultiplied alpha values for the bitmapInfo parameter.
  • Great question and of course equally great answer. Thank you for posting these. The bitmap CGContext is a tricky animal. I was trying to clip an image to a circle and whatever stands outside the arc got filled with black. Tried different approaches till I got it working the way you did. Was going to publish the solution when I found your Q/A. If you think the solution is only logical. But the lack of detailed docs and some high expectations can make one struggle. Again, thank you for sharing.

Add a Comment

Replies

Posting a reply to my own question here in case others encounter the same... While I'm not certain about the underlying design or when a non-precomposed RGBA setting would be possible or valid for a bitmap CGContext, that configuration turned out to not be needed.

I'm now using this code to generate my CGContext - it's sRGB color space, and the alpha value is set to premultiplied. I was concerned this would mean I would somehow need to do some premultiplied calculation for the use of semi-opaque colors in my drawing code, but this turns out not to be the case - I can obtain an image with a transparent background, and also set partial alpha values in colors set for fill or stroke while drawing, and everything works properly.

Code Block
if let colorspace = CGColorSpace(name: CGColorSpace.sRGB) {
      if let cgc = CGContext(data: nil,
                    width: Int(pixelWidth),
                    height: Int(pixelHeight),
                    bitsPerComponent: 16,
                    bytesPerRow: 0,
                    space: colorspace,
                    bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue |
                    CGBitmapInfo.byteOrder16Little.rawValue |
                    CGBitmapInfo.floatComponents.rawValue) {
...


So my answer in a nutshell is, if you want to use a bitmap CGContext for use in a Mac app with RGB color space that includes transparency, you can just use sRGB color space and premultiplied alpha values for the bitmapInfo parameter.
  • Great question and of course equally great answer. Thank you for posting these. The bitmap CGContext is a tricky animal. I was trying to clip an image to a circle and whatever stands outside the arc got filled with black. Tried different approaches till I got it working the way you did. Was going to publish the solution when I found your Q/A. If you think the solution is only logical. But the lack of detailed docs and some high expectations can make one struggle. Again, thank you for sharing.

Add a Comment