首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从CGContext中获取CGImage

从CGContext中获取CGImage
EN

Stack Overflow用户
提问于 2022-02-18 07:19:44
回答 1查看 590关注 0票数 1

我有一个CGImage,我想在上面画一条线。我认为我应该创建一个CGContext,然后在上面画图像,然后在上面画我的线。但是,我不知道如何从CGImage转到CGContext。我已经看到了从UIImage到CGContext的例子,但我想知道是否有一种更直接的方法(希望更有效)。

我的尝试:

代码语言:javascript
复制
let ctx = CGContext(data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: cgImage.bytesPerRow, space: cgImage.colorSpace!, bitmapInfo: cgImage.bitmapInfo.rawValue)
      
      ctx!.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
      
      ctx!.setFillColor(UIColor.red.cgColor)
      
      ctx!.fillEllipse(in: CGRect(x: 0, y: 0, width: 100, height: 100))
      
      cgImage = (ctx!.makeImage())!
EN

回答 1

Stack Overflow用户

发布于 2022-02-18 14:36:24

它看起来效率低下,创建一个空白的上下文并将图像绘制给它,不是吗?另一方面,这种类型的图像绘制是高度优化的。但让我们看看我们还能做些什么。

注意:请勿复制或粘贴

不要在以下情况下使用程序中的代码块:

  1. 内存泄漏分析
  2. 衡量变化前后的绩效统计数据
  3. 了解输入图像具有某种格式时会发生什么情况,Core不知道如何使用。

向CGContext发送数据

CGContext构造函数接受一个data参数。我们将其设置为nil,让它创建新的数据,但是如果我们给它一些现有的字节,上下文就会出现,并且它的图像已经就位。

但是我们从哪里得到这些字节呢?也许有更好的方法来做这件事,但最简单的是我能找到这样做的方法:

  1. 获取CGImage.dataProvider,然后是CGImageDataProvider.data,它将原始图像字节复制到不可变的CFData对象中。
  2. 分配一个UnsafeMutablePointer<UInt8>并使用CFData的长度。(请记住稍后使用deallocate() )。
  3. CFData内容复制到UnsafeMutablePointer<UInt8>中。
  4. 使用CGContext构造UnsafeMutablePointer<UInt8>

这看起来已经很可疑了:我们可能期望复制图像中的所有字节一次,但是我们要复制它们两次。

把它放在一起

代码语言:javascript
复制
func imageByCopyingBytes(cgImageInput : CGImage) -> CGImage? {
    var cgImageOutput : CGImage? = nil
    
    if let dataProvider = cgImageInput.dataProvider {
        // Here we make a copy of the image bytes.
        // This copy is immutable, so can't be used by CGContext().
        // The CGDataProvider documentation:
        // https://developer.apple.com/documentation/coregraphics/cgdataprovider/1408309-data
        // Says "You are responsible for releasing this object."
        // However, Swift does manage these types:
        // https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/working_with_core_foundation_types
        if let data : CFData = dataProvider.data {
            let length = CFDataGetLength(data)
            
            // We must manually deallocate this memory by calling bytes.deallocate() once we finish it.
            let bytes = UnsafeMutablePointer<UInt8>.allocate(capacity: length)
            
            // Copy the immutable image data into the mutable bytes.
            CFDataGetBytes(data, CFRange(location: 0, length: length), bytes)

            // Create a context with the mutable bytes as the data.
            // This may fail and return nil if the input image bitmapInfo is not supported on this operating system.
            // 
            if let ctx = CGContext(data: bytes, width: cgImageInput.width, height: cgImageInput.height, bitsPerComponent: cgImageInput.bitsPerComponent, bytesPerRow: cgImageInput.bytesPerRow, space: cgImageInput.colorSpace!, bitmapInfo: cgImageInput.bitmapInfo.rawValue) {
                
                // Do your drawing here.
                ctx.setFillColor(UIColor.red.cgColor)
                ctx.fillEllipse(in: CGRect(x: 0, y: 0, width: 100, height: 100))

                // Make a CGImage from the context.
                cgImageOutput = (ctx.makeImage())
                
                if cgImageOutput == nil {
                    print("Failed to make image from CGContext.")
                }
            } else {
                print("Could not create context. Try different image parameters.")
            }
            
            // We have finished with the bytes, so deallocate them.
            bytes.deallocate()
        } else {
            print("Could not get dataProvider.data")
        }
    } else {
        print ("Could not get cgImage.dataProvider")
    }
    
    return cgImageOutput
}

表现:令人失望

我设置函数来创建CGContextCGImage副本,通过这些方法-没有绘图,只是复制。我数了数我能在1秒内运行多少次,从小图标到普通的iPhone照片,再到巨大的全景图。

在小图标图像上,imageByCopyingBytes的速度快了11%到36%,可能还不足以证明程序的复杂性。在正常大小的照片和全景,它是60%的慢!

我不能完全解释。但这确实表明,苹果在优化其绘图功能方面投入了大量工作。千万不要以为你需要和他们打交道。

附加警告: CGContext构造器

您可能会注意到,为了确保在使用变量之前定义了变量,我的imageByCopyingBytes函数是可选的绑定。这会导致函数悄悄地返回nil,其中只有一个日志到控制台,让您知道发生了什么。

我不知道这会不会完好无损,但这是我试过的第一张照片。这是我拥有的一个较小的PNG文件,所以应该是一个安全的测试文件,对吗?不对?

我试图在macOS 11.6.1上作为催化剂应用程序运行。我试图构造CGContext的步骤导致将此错误记录到控制台。由于没有创建CGContext,接下来的步骤将导致崩溃。

代码语言:javascript
复制
CGBitmapContextCreate: unsupported parameter combination: set CGBITMAP_CONTEXT_LOG_ERRORS environmental variable to see the details

错误环境变量?的问题和答案帮助我看到了完全的错误:

代码语言:javascript
复制
CGBitmapContextCreate: unsupported parameter combination:
    8 bits/component; integer;
    32 bits/pixel;
    RGB color space model; kCGImageAlphaLast;
    default byte order;
    720 bytes/row.

接下来将列出支持的格式,这表明它不喜欢kCGImageAlpaLast,并且想要kCGImageAlphaPremultipliedLast或类似的格式。

我指定了我的macOS版本,因为它在iOS 15.2模拟器上工作得很好,尽管它仍然不能用kCGImageAlphaLast处理灰度图片。

所有这一切意味着,我将非常谨慎地创建您的CGContext格式与您的输入图像。我有一种匹配它的冲动,特别是当您从用户那里获取文件,在它们上绘制东西,然后返回编辑的文件时。我喜欢保留图像格式的应用程序。但是核心图形库有他们喜欢的格式,也有它们勉强容忍的格式。对于大多数任务,最好指定您创建的任何CGContext的格式。显然,您不能再使用我们刚才所做的工作来创建上面的字节数组。但是,通过绘制图片复制图片,就像您在问题中所做的一样,应该仍然有效,并让converting来处理转换它的艰苦工作。

结论

如果您一直滚动到这里,这是我对您的问题的最后回答:继续通过绘制来复制图像,但是在CGContext构造函数中指定您自己的bitmapInfo和可能的colorSpace

如果加载带有非标准方向的JPEG,也会得到预期的结果吗?

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71169691

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档