0

I'm trying to create a CGContext in which I can draw an image to retrieve the raw pixel data for later processing. I'm creating the CGContext using a color space dependent upon the image I'm processing. This works fine when I use a grayscale or CMYK colorspace, but I can't get a valid CGContext when working with any RGB color space. The snippets below illustrate the behavior I'm seeing (with Swift 4, XCode 10.1). I've got to be missing something obvious but for the life of me I can't find it. Any help would be greatly appreciated!

//let colorSpace3:CGColorSpace = CGColorSpaceCreateDeviceGray() // get good context
//let colorSpace3:CGColorSpace = CGColorSpaceCreateDeviceCMYK() // get good context
//let colorSpace3: CGColorSpace = CGColorSpace(name: CGColorSpace.linearGray)! // get good context
//let colorSpace3: CGColorSpace = CGColorSpace(name: CGColorSpace.genericCMYK)! // get good context
//let colorSpace3:CGColorSpace = CGColorSpaceCreateDeviceRGB() //context3 is nil
//let colorSpace3: CGColorSpace = CGColorSpace(name: CGColorSpace.sRGB)! //context3 is nil
//let colorSpace3: CGColorSpace = CGColorSpace(name: CGColorSpace.linearSRGB)! // context3 is nil
let colorSpace3: CGColorSpace = CGColorSpace(name: CGColorSpace.adobeRGB1998)! // context3 is nil

let bmpinfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue) // bmpinfo different settings doesn't change behavior

let context3 = CGContext(data: nil, width: 256, height: 256, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace3, bitmapInfo: bmpinfo.rawValue)

print(context3) // prints nil whenever colorSpace3 is an RGB space??
SteveB
  • 3
  • 4

1 Answers1

4

You should be seeing CGBitmapContextCreate: unsupported parameter combination in the console. Just change

let bmpinfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)

to

let bmpinfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

and you should be good to go. Example:

let colorSpace3: CGColorSpace = CGColorSpace(name: CGColorSpace.sRGB)!
let bmpinfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
let context3 = CGContext(data: nil, width: 256, height: 256, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace3, bitmapInfo: bmpinfo.rawValue)!
print(context3)

Prints:

<CGContext 0x600000165580> (kCGContextTypeBitmap)
    <<CGColorSpace 0x60000022a9c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)>
        width = 256, height = 256, bpc = 8, bpp = 32, row bytes = 1024 
        kCGImageAlphaPremultipliedLast | 0 (default byte order) 

By the way, your little conversion dance is unnecessary. You can just set your bmpInfo to CGImageAlphaInfo.premultipliedLast.rawValue and pass it straight into the function as the bitmapInfo argument. You only need the conversion if you're also combining byte-ordering information with the alpha information.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • matt, thanks for the help. I tried that and it works. Also, since I don't have an alpha channel, I tried CGImageAlphaInfo.noneSkipLast.rawValue for bmpinfo and that also worked. So it looks like CGContext doesn't like the CGImageAlphaInfo.none option for bitmapInfo with an RGB colorspace (but it's ok for the other color spaces)? seems strange to me. – SteveB Mar 04 '19 at 00:59
  • I suppose that whether _you_ have an alpha channel in a particular image is irrelevant. This is about color spaces. RGB color spaces all have a place for alpha info, and you have to say _something_ about what that place should be. (That's just guesswork but you have to admit it sounds good.) – matt Mar 04 '19 at 01:04
  • Also please see the edit of my answer; you're doing an unnecessary conversion dance in the second line. – matt Mar 04 '19 at 01:14
  • 1
    thanks again. Just some quick follow up. I did some digging and you were correct: there is no supported RGB 8bpc format without an alpha channel. I turned on CGBITMAP_CONTEXT_LOG_ERRORS env variable and it spits out the valid combos -- 24-bit is not one of them. Also as explained in [this] (https://stackoverflow.com/questions/8704577/is-it-possible-to-make-a-nsbitmapimagerep-with-24-bpp-and-no-alpha-channel) SO post and ... – SteveB Mar 07 '19 at 02:22
  • the [Quartz Documentation](https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-CJBEAGHH). Still a bit confusing to me, but your answer is indeed correct. Now my question is: if I have a 24-bit (no alpha) RGB input image and want to draw it in a new context, how do I do that? – SteveB Mar 07 '19 at 02:22