What is the way to extract the value of an Image pixel given that a GCPoint value is available?

87 views Asked by At

I have an Image View which displays an image and the CGPoint when the cursor is over the image. I am able to get and display the cursor position in pixels but cannot figure out how to get the value of the pixel rgb.

import SwiftUI

struct ImageView: View {
    
    @State var location: CGPoint = .zero
    @State var didHover = false
    
    var body: some View {
        VStack {
            Text("Os trĂªs")
                .font(.system(size: 16))
            
            Image("Burros_1") // placeholder
                .resizable()
                .scaledToFit()
                .aspectRatio(contentMode: .fit)
                .background(Color.black.opacity(0.5))
                .frame(width: 640, height: 480)
                .border(.green)
                .onHover { hover in
                    if hover {
                        NSCursor.crosshair.push()
                    } else {
                        NSCursor.pop()
                    }
                }
                .onContinuousHover { phase in // (col, row)
                    switch phase {
                    case .active(let location):
                        NSCursor.crosshair.push()
                        self.location = location // WORKS
                        self.didHover = true
                    case .ended:
                        self.didHover = false
                        break
                    }
                }
            
            // GOAT add DN
            let rowString = String(format: "%03d", Int(round(location.x)))
            let colString = String(format: "%03d", Int(round(location.y)))
            
            if didHover {  // Missing pixel value GOAT
                Text("(r, c, DN) \(rowString), \(colString), ??")
                    .monospaced()
            }
            else {  // this conserves a line for the Text
                Text(" ")
            }
        } // VStack
    } //
}

I've searched on-line, including stack overflow, extensively but most results are for iOS, not macOS, and don't really address my problem or won't compile. I've also 'jumped' to definitions to try to spot a method but no luck.

1

There are 1 answers

5
workingdog support Ukraine On BEST ANSWER

You could try this approach using NSBitmapImageRep, to get the pixel rgb.

Example code:

struct ContentView: View {
    var body: some View {
        ImageView()
    }
}

struct ImageView: View {
    let nsimg = NSImage(named: "mycat")!
    @State private var location: CGPoint = .zero
    @State private var pixelColor: NSColor?
    
    var body: some View {
        VStack {
            Text("location: \(location.debugDescription)")
            Text("color: \(pixelColor?.debugDescription ?? "no color")")
            
            GeometryReader { geo in
                Image(nsImage: nsimg)
                    .resizable()
                    .frame(width: 640, height: 480)
                    .onContinuousHover { phase in
                        switch phase {
                        case .active(let location):
                            NSCursor.crosshair.push()
                            self.location = location
                            
                            // todo convert coords using GeometryReader
                            
                            pixelColor = nsimg.colorAt(location)
                        case .ended:
                            break
                        }
                    }
                    .border(.green)
            }
        }
        .onAppear {
            pixelColor = nsimg.colorAt(CGPoint(x: 20, y: 60)) // for testing
            print("---> pixelColor: \(pixelColor)")
        }
    }
    
}

extension NSImage {
    func colorAt(_ pos: CGPoint) -> NSColor? {
        let imageRep = NSBitmapImageRep(data: self.tiffRepresentation!)
        return imageRep?.colorAt(x: Int(pos.x), y: Int(pos.y))
    }
}