0

I've been trying to find a good way to convert white pixels in an NSImage on the fly to transparent pixels. I've seen Swift examples for UIImage, but not NSImage. Below is what I've created (and which is working). Two questions:

  • Is there a better way to lose the alpha channel on an NSImage? I'm now converting it first to the JPEG representation (which doesn't have an alpha channel) and then to another representation again. That feels rather ugly

  • Is there a method / way to only trim white pixels on the edges of the images (not on the 'inside' of an image?


func mask(color: NSColor, tolerance: CGFloat = 4) -> NSImage {
    guard let data = tiffRepresentation,
          // This is an extremely ugly hack to strip the alpha channel from a bitmap representation (because maskingColorComponents does not want an alpha channel)
          // https://stackoverflow.com/questions/43852900/swift-3-cgimage-copy-always-nil
          // https://stackoverflow.com/questions/36770611/replace-a-color-colour-in-a-skspritenode
            let rep = NSBitmapImageRep(data: (NSBitmapImageRep(data: data)?.representation(using: .jpeg, properties: [:])!)!) else {
              return self
    }
    
    if let ciColor = CIColor(color: color) {
        NSLog("trying to mask image")
        let maskComponents: [CGFloat] = [ciColor.red, ciColor.green, ciColor.blue].flatMap { value in
            [(value * 255) - tolerance, (value * 255) + tolerance]
        }
        
        guard let masked = rep.cgImage(forProposedRect: nil, context: nil, hints: nil)?.copy(maskingColorComponents: maskComponents) else { return self }
        return NSImage(cgImage: masked, size: size)
    }

    return self
}
burnsi
  • 6,194
  • 13
  • 17
  • 27
mdbraber
  • 1
  • 1
  • This is a pretty tricky problem to solve automatically. There's a few challenges here: 1) You're seldom going to find "truly" white pixels (255, 255, 255), so you'll need to have some leeway. Too little, and you'll leave some background, too much and you'll starting eating into the actual subject. 2) The edges of objects aren't infinitely sharp, so you'll see a gradient from the subject colour to the background. You'll need to tweak all of those pixels, otherwise you'll see a white "glow" around your subject 3) Any holes in your subject that aren't reachable from the edge will stay white – Alexander Feb 03 '23 at 15:32
  • 4) inflating a large image into a bitmap (to do the processing on) in memory might go over your memory limit and terminate your app. Unfortunately, this looks like a really really tricky problem, and I have no particular suggestions beside "look for somebody who has already solved it" – Alexander Feb 03 '23 at 15:33

0 Answers0