如何在SwiftUI和Xcode中将cgImage作为ImageView返回,用于macOS?

huangapple go评论61阅读模式
英文:

How do I return a cgImage as an ImageView using SwiftUI and Xcode for macOS/

问题

以下是翻译好的部分:

我有数据存储在一个Data对象中,格式为[UInt8],要渲染为8位灰度图像。 我不知道如何从cgImage转换为图像视图 以下代码至少可以编译,但缺少返回值,但我不确定它是否正确。 我需要添加什么来返回图像作为视图?

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 }
    }
}
英文:

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&lt;T&gt;() -&gt; T {
        return self.withUnsafeBytes { $0.pointee }
    }
}

答案1

得分: 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.

英文:

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.

答案2

得分: 0

display CGImage to SwiftUI:

// this
Image(decorative: cgImage, scale: 3, orientation: .up)
// and decoration
    .renderingMode(.template)
    .foregroundColor(.white)
英文:

display CGImage to SwiftUI:

// this
Image(decorative: cgImage, scale: 3, orientation: .up)
// and decoration
    .renderingMode(.template)
    .foregroundColor(.white)

huangapple
  • 本文由 发表于 2023年5月17日 06:48:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76267548.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定