skip to Main Content

I have data stored in a Data object as [UInt8] to be rendered as a grayscale 8-bit image. I don’t know how to get from a cgImage to an image View. The code below at least compiles up to the lack of a return value but I’m not certain that it is correct. What do I need to add to return the image as a view?

import SwiftUI

struct ImageView_2: View {
    var data: Data
    
    var body: some View {
        
        let width = 320
        let height = 240
        
        let colorSpace = CGColorSpaceCreateDeviceGray()
        
        let context = CGContext(data: data.castToCPointer(), width: width, height: height, bitsPerComponent: 8, bytesPerRow: width, space: colorSpace, bitmapInfo: CGImageAlphaInfo.alphaOnly.rawValue)
        let imageRef = CGContext.makeImage(context!)
        let imageRep = NSBitmapImageRep(cgImage: imageRef()!)
        let image = imageRep.cgImage

        return
          //  .resizable()
          //  .aspectRatio(contentMode: .fit)
    }  
    
}

The extension to Data:

extension Data {
    func castToCPointer<T>() -> T {
        return self.withUnsafeBytes { $0.pointee }
    }
}

2

Answers


  1. Your castToCPointer is undefined behavior and can definitely crash, particularly when optimizations are turned on. It is invalid to access the pointer from a Data outside of the withUnsafeBytes closure. Luckily, it’s also unnecessary.

    The image View in SwiftUI is Image, and accepts a NSImage as an input.

    I haven’t tested it out, but this should do what you’re looking for:

    struct ImageView_2: View {
        var data: Data
    
        var body: some View {
    
            let width = 320
            let height = 240
    
            let colorSpace = CGColorSpaceCreateDeviceGray()
    
            let provider = CGDataProvider(data: data as CFData)!
    
            let image = CGImage(width: width,
                                height: height,
                                bitsPerComponent: 8,
                                bitsPerPixel: 8 * 1,
                                bytesPerRow: width,
                                space: colorSpace,
                                bitmapInfo: [],
                                provider: provider,
                                decode: nil,
                                shouldInterpolate: false,
                                intent: .defaultIntent)!
    
            return Image(nsImage: NSImage(cgImage: image,
                                          size: CGSize(width: width, height: height)))
        }
    }
    

    Note that the ! usage here will crash if the data is in a bad format. You can fix that using if-let to check them for nil. In that case, though, you will still need to return a valid View.

    Login or Signup to reply.
  2. display CGImage to SwiftUI:

    // this
    Image(decorative: cgImage, scale: 3, orientation: .up)
    // and decoration
        .renderingMode(.template)
        .foregroundColor(.white)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search