user3069232
user3069232

Reputation: 8995

How can I access the pixels data in SwiftUI Canvas

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)
        }
      }
    }
  }
}
}

Upvotes: 2

Views: 1382

Answers (1)

Transformer
Transformer

Reputation: 7439

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
    }
 }

Upvotes: 2

Related Questions