NSColor , colorspace etc. :(

I am trying to take an NSImage and change pixels of a specific color to another color

This is my test code (this SHOULD change all pixels to gray)

func makeMask() {
		let bitmapRep : NSBitmapImageRep = self.representations[0] as! NSBitmapImageRep
		for x in (0...bitmapRep.pixelsWide-1) {
			for y in(0...bitmapRep.pixelsHigh-1) {
				if let color : NSColor = bitmapRep.colorAt(x: x, y:y) {
					let xxx=NSColor(rgb:0x777777).usingColorSpace(color.colorSpace)
					bitmapRep.setColor(xxx!, atX: x, y: y)

where SELF is an NSImage
the line

bitmapRep.setColor(xxx!, atX: x, y: y)

gives these errors
Unrecognized colorspace number -1
Unknown number of components for colorspace model -1

even though I made sure the old [color] and new [xxx] are the same colorspace

and I can't find ANYTHING on the Net the points to a cause :(

Solved …

func makeMask() {
   let BMP  : NSBitmapImageRep = self.representations[0] as! NSBitmapImageRep
   let data = BMP.bitmapData
   var ptr  : Int = 0
   for _ in(0...BMP.pixelsHigh-1) {
      for _ in (0...BMP.pixelsWide-1) {
         let clr = getPixel(data: data, pointer: ptr)
         if clr.IntValue() == NSColor.white.IntValue() {
            putPixel(data: data, pointer: ptr, newColor: NSColor.magenta.withAlphaComponent(0))

  private func getPixel(data:UnsafeMutablePointer<UInt8>?,pointer:Int) -> NSColor {
    let r : CGFloat = CGFloat(data![pointer])/255
    let g : CGFloat = CGFloat(data![pointer+1])/255
    let b : CGFloat = CGFloat(data![pointer+2])/255
    let a : CGFloat = CGFloat(data![pointer+3])/255
    let clr = NSColor(calibratedRed: r, green: g, blue: b, alpha: a)
    // make sure it returns an RGB color
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    return NSColor(cgColor:clr.cgColor.converted(to: rgbColorSpace, intent: .defaultIntent, options: nil)!)!
  private func putPixel(data:UnsafeMutablePointer<UInt8>?,pointer:Int,newColor:NSColor) {
    data![pointer] = UInt8(newColor.redValue*255)
    data![pointer+1] = UInt8(newColor.greenValue*255)
    data![pointer+2] = UInt8(newColor.blueValue*255)
    data![pointer+3] = UInt8(newColor.alpha*255)

IntValue is an extension to NSColor the returns the integervalue of the color… due to the various colorspaces Swift uses, the was a way to make the color directly comparable

also the use of Magenta was unimportant, just the fact the alpha was 0

There are several things here.

  1. A NSImage may not have a NSBitmapImageRep to start with.
  2. The macOS is funny with colorSpaces, it supports a lot, but not all can be used to create colors or images with. IIRC there is only a handful that can actually be used for creation, you must also ensure that the color matches the color space, for instance trying to create a cmyk color with a RGB colorSpace will fail.
  3. Try using the colorSpace of the image and not the pixel, if that fails, use a close matched colorspace.

Xojo makes this easy, by simply ignoring colorSpaces, so it takes some getting use to, to work with colorSpaces.

this app translate everything into sRGB for comparisons