0

我正在尝试layers: [CGImageRef]drawLayer(thisLayer: CALayer!, inContext ctx: CGContext!)我的 custom 例程中进行 alpha 混合NSView。到目前为止,我一直CGContextDrawImage()将这些图层绘制到 drawLayer 上下文中。在进行分析时,我注意到CGContextDrawImage()需要 70% 的 CPU 时间,因此我决定尝试 Accelerate 框架。我更改了代码,但它只是崩溃了,我不知道可能是什么原因。

我正在创建这样的图层:

func addLayer() {
    let colorSpace: CGColorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)
    let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.rawValue)

    var layerContext = CGBitmapContextCreate(nil, UInt(canvasSize.width), UInt(canvasSize.height), 8, UInt(canvasSize.width * 4), colorSpace, bitmapInfo)
    var newLayer = CGBitmapContextCreateImage(layerContext)

    layers.append( newLayer )
}

我的 drawLayers 例程如下所示:

override func drawLayer(thisLayer: CALayer!, inContext ctx: CGContext!)
{
    var ctxImageBuffer = vImage_Buffer(data:CGBitmapContextGetData(ctx),
        height:CGBitmapContextGetHeight(ctx),
        width:CGBitmapContextGetWidth(ctx),
        rowBytes:CGBitmapContextGetBytesPerRow(ctx))
    
    for imageLayer in layers
    {
        //CGContextDrawImage(ctx, CGRect(origin: frameOffset, size: canvasSize), imageLayer)
        
        var inProvider:CGDataProviderRef = CGImageGetDataProvider(imageLayer)
        var inBitmapData:CFDataRef = CGDataProviderCopyData(inProvider)
        var buffer:vImage_Buffer = vImage_Buffer(data: &inBitmapData, height:
            CGImageGetHeight(imageLayer), width: CGImageGetWidth(imageLayer), rowBytes:
            CGImageGetBytesPerRow(imageLayer))
            
        vImageAlphaBlend_ARGB8888(&buffer, &ctxImageBuffer, &ctxImageBuffer, 0)
    }
}

canvasSize 总是相同的,并且所有图层的大小都相同,所以我不明白为什么最后一行会崩溃。

我也看不到如何使用新的便利函数直接从 CGLayerRefs 创建 vImageBuffers。这就是为什么我用复杂的方式来做这件事。

任何帮助表示赞赏。

编辑

inBitmapData确实包含反映我设置的背景颜色的像素数据。但是,调试器不能po &inBitmapData并且失败并显示此消息:

错误:对“CFData”的引用未用于初始化 inout 参数 &inBitmapData

所以我寻找一种方法来获取指向 inBitmapData 的指针。这就是我想出的:

var bitmapPtr: UnsafeMutablePointer<CFDataRef> = UnsafeMutablePointer<CFDataRef>.alloc(1)
bitmapPtr.initialize(inBitmapData)

我还必须更改指向 alpha 混合输入所需的两个缓冲区的数据的方式。现在它不再崩溃了,幸运的是,可以使用分析器检查速度提升(vImageAlphaBlend只需要大约三分之一CGContextDrawImage),但不幸的是,图像会导致透明图像出现像素故障,而不是白色图像背景。

到目前为止,我不再收到任何运行时错误,但由于结果不如预期,我担心我仍然没有正确使用 alpha blend 函数。

4

1 回答 1

3

vImage_Buffer.data 应该指向 CFData 数据(像素数据),而不是 CFDataRef。

此外,并非所有图像都将其数据存储为四通道,每通道 8 位数据。如果结果是三通道或 RGBA 或单色,您可能会得到更多崩溃或有趣的颜色。此外,您假设原始图像数据未预乘,这可能不是一个安全的假设。

最好使用 vImageBuffer_initWithCGImage,这样可以保证原始图像数据的格式和色彩空间。关于该功能的更具体的问题可能会帮助我们解决您对此的困惑。

一些 CG 调用依赖于 vImage 来完成这项工作。在这种情况下,以这种方式重写代码可能无利可图。通常首先要做的正确的事情是仔细查看 CG 调用中的回溯,以尝试了解您为什么要为此付出如此多的工作。通常答案是色彩空间转换。我会仔细查看绘图表面的 CGBitmapInfo 和色彩空间以及您的图像,看看是否有什么我可以做的让它们更好地匹配。

IIRC,CALayerRefs 通常将它们的数据存储在不可缓存的存储中,以便更好地访问 GPU。这可能会导致 CPU 出现问题。如果数据在 CALayerRef 中,我会使用 CA 来进行合成。此外,我认为 CALayers 几乎总是 BGRA 8 位预乘。如果您不打算使用 CA 进行合成,那么正确的 vImage 函数可能是 vImagePremultipliedAlphaBlend_RGBA/BGRA8888。

于 2015-02-02T16:03:27.847 回答