2

Trying to access the pixel data on a Canvas, and almost there I think? But I have missed some detail? This compiles but the cgContext.data doesn't seem to be set to a value I can extract here?

The line variable refers to a published array of points.

class Lines:ObservableObject {
  @Published var coordinates:[CGPoint] = []
}

struct ContentView: View {
  @ObservedObject var line = Lines()
  @GestureState var foo = CGPoint.zero
  var body: some View {
  ZStack(alignment: .center) {
    Color.yellow
    .opacity(0.1)

  Canvas { context, size in
    context.withCGContext { cgContext in
      cgContext.setStrokeColor(UIColor.red.cgColor)
      cgContext.setLineWidth(12)
      if line.coordinates.count > 2 {
        cgContext.move(to: line.coordinates[0])
        for p in 1..<line.coordinates.count {
          cgContext.move(to: line.coordinates[p - 1])
          cgContext.addLine(to: line.coordinates[p])
          cgContext.drawPath(using: .eoFillStroke)
        }
        if cgContext.data != nil {
          let rawData:UnsafeMutableRawPointer = cgContext.data!
          let opaquePtr = OpaquePointer(rawData)
          let contextPtr = UnsafeMutablePointer<UInt32>(opaquePtr)
          let pixels = UnsafeMutableBufferPointer<UInt32>(start: contextPtr, count: 256 * 256)
          print("pixels ",pixels.count)
        }
      }
    }
  }
}
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
user3069232
  • 8,587
  • 7
  • 46
  • 87
  • Philip, thanks for taking the time to try and answer. Sadly I cannot accept your response because I am no closer to the answer with it. – user3069232 Nov 23 '21 at 10:05

1 Answers1

2

I think this was discussed before, please see here


First, if you have an empty context then look here, you double check your configuration, Supported Pixel Formats. For 8 bitsPerComponent and RGB color space you have only the few valid alpha options:

Supported Pixel Formats Apple IOS Swift Ref.

Second, please use the CGBITMAP_CONTEXT_LOG_ERRORS env. variable in your scheme in runtime to debug this.


Since you are using core graphics, build an extension and then get the pixeldata from there, credit to Anna from here.

Just reuse your CGContext inside here and see if that works.

extension UIImage {
    func pixelData() -> [UInt8]? {
        let size = self.size
        let dataSize = size.width * size.height * 4
        var pixelData = [UInt8](repeating: 0, count: Int(dataSize))
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let context = CGContext(data: &pixelData,
                                width: Int(size.width),
                                height: Int(size.height),
                                bitsPerComponent: 8,
                                bytesPerRow: 4 * Int(size.width),
                                space: colorSpace,
                                bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue)
        guard let cgImage = self.cgImage else { return nil }
        context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))

        return pixelData
    }
 }
Transformer
  • 6,963
  • 2
  • 26
  • 52