You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在macOS用SwiftUI显示UInt8数组为图片时遇CGSWindowShmem错误

问题:CGImage赋值状态变量后运行报错,调试时可正常显示

我正在开发实用学习应用,学习Xcode、SwiftUI等技术。目前实现了将[UInt16]数据缩放为[UInt8]生成灰度CGImage的功能,但赋值给状态变量时出现如下错误:

2023-06-13 10:03:04.497662-0700 DisplayFM2Image[6160:76497] [default] CGSWindowShmemCreateWithPort failed on port 0

调试时CGImage能正常显示,但继续运行就触发报错。怀疑是CGImage未保留数据指针,或者GeometryReader代码存在问题。缩放后的[UInt8]数组及元数据存储在自定义类TheImage的实例theImage中。需求是实现文件选择、图片显示,以及通过工具提示查看原始数据的功能。


创建CGImage的函数

import SwiftUI
import CoreGraphics

// 计算Core Graphics图像并赋值给ContentView的状态变量"cgImage"
func createCGImageFromUint8( _ cgImage: inout CGImage?) {
    
    let width: Int = theImage.nCols
    let height: Int = theImage.nRows
    let numBytes = theImage.scaledArray.count
    let numComponents = numBytes / (height * width)
    let colorspace = CGColorSpaceCreateDeviceGray()
    let grayScaleData = CFDataCreate(nil, theImage.scaledArray, numBytes)
    let provider = CGDataProvider(data: grayScaleData!)!
    
    cgImage = CGImage(
        width: width,
        height: height,
        bitsPerComponent: 8,
        bitsPerPixel: 8 * numComponents,
        bytesPerRow: width * numComponents,
        space: colorspace,
        //bitmapInfo: CGBitmapInfo(rawValue: 0),
        bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
        provider: provider,
        decode: nil,
        shouldInterpolate: true,
        intent: CGColorRenderingIntent.defaultIntent)!
    
    // 断点处
     print("Return from createCGImageFromUint8")
    // 在该断点调试时能正常显示cgImage!
}

ContentView起始代码

import SwiftUI
import CoreGraphics

var theImage = TheImage() // 图片相关变量定义在外部文件

struct ContentView: View {
    
    @State var haveNewImage: Bool = false
    @State private var cgImage: CGImage? = nil
        
    // @State var imageDataView: (any View)? // 这行代码的作用是什么?
    
    var body: some View {
        VStack(alignment: .leading ) {
            
            FilePickerView(cgImage: $cgImage)
                .padding()  // 位于左上角,功能正常
            
            // 如果选择了新文件:处理并显示图片
            if theImage.isNew { // 显示图片等功能正常
                Text("DEBUG New Image")
                CGImageView(cgImage: $cgImage)
            } else {
                HStack {
                    Spacer()
                    Text("尚未选择图片。")
                    Spacer()
                }
            }
        }    
    }

CGImageView代码

import SwiftUI
import CoreGraphics
import AppKit

struct CGImageView: View {
    @Binding var cgImage: CGImage?

    @State private var opacity = 0.0
    @State private var minMax = theImage.minMax
    @State private var dnData: [UInt16] = theImage.backingArray
    
    var body: some View {
        var dnText = "" // 用于显示工具提示
        Text(theImage.displayName)
            .padding(10)
        
        HStack {
            GeometryReader { geometry in
            //    Image(decorative: $cgImage as! CGImage , scale: 1.0)
                  Image(decorative: self.cgImage! , scale: 1.0)
                    .aspectRatio(contentMode: .fit)
                    .border(Color.red)
            }
            .frame(width: CGFloat(theImage.nCols), height: CGFloat(theImage.nRows))
            .opacity(opacity)
            .animation(.easeInOut(duration: 1.5), value: opacity)
            
            .onAppear {
                opacity = 1.0
            }
            
            .onDisappear {
                opacity = 0.0
            }
            
            .onTapGesture {
                print("TAPPED!") // 后续实现功能
            }
            .onHover { (hover: Bool) in
                if hover {
                    //   let mouseLocation = NSEvent.mouseLocation
                    //   print("Mouse location: \(mouseLocation)")
                    NSCursor.crosshair.push()
                } else {
                    NSCursor.pop()
                }
            }
            
            .onContinuousHover { phase in
                switch phase {
                case .active(let location):  // 列、行坐标
                    let dn = theImage.getToolTipValue(mouse: location)
                    dnText = "原始DN值 \(dn)"
                    print("---> 位置x: \(location.x)")
                case .ended:
                    break
                }
            }
            .padding(10)

            Text("最小值 \(minMax[0])\n最大值 \(minMax[1])\n\(dnText)")
                
        }
    }
}

内容的提问来源于stack exchange,提问作者Nate Lockwood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 21:02:08