绘制CGImage的一部分

问题描述 投票:1回答:4

我有一个从CGImage中绘制图像的应用程序。

使用CGImageSourceCreateImageAtIndex加载CImage本身以从PNG文件创建图像。

这构成了精灵引擎的一部分 - 在单个PNG文件上有多个精灵图像,因此每个精灵都有一个CGRect,用于定义在CGImage上找到它的位置。

问题是,CGContextDraw只接受目标rect - 并拉伸源CGImage来填充它。

因此,要绘制每个精灵图像,我们需要使用CGImageCreateWithImageInRect()从原始源创建多个CGImages。

我一开始认为这将是一个“便宜”的操作 - 似乎每个CGImage都不需要包含它自己的图像位副本 - 但是,分析表明使用CGImageCreateWithImageInRect()是一个相当昂贵的操作。

是否有更优化的方法将CGImage的子部分绘制到CGContext上,所以我不经常需要CGImageCreateWithImageInRect()?


鉴于缺少源矩形,以及在CGImage上从矩形制作CGImage的容易性,我开始怀疑CGImage可能实现了写入时复制语义,其中由CGImage制作的CGImage将指向一个子矩形与父级相同的物理位。分析似乎证明这是错误的:/

cocoa core-graphics cgimage
4个回答
2
投票

我和你在同一条船上。 CGImageCreateWithImageInRect()更好地满足了我的需求但之前我曾试图转换为NSImage,在此之前我正在剪切我正在绘制的上下文,并进行翻译以便CGContextDrawImage()将正确的数据绘制到剪切区域。

在我尝试的所有解决方案中:

  1. 削减和翻译对CPU造成了极大的负担。太慢了。似乎增加位图数据量只会略微产生重大的性能影响,这表明这种方法缺乏任何可扩展性。
  2. 转换到NSImage相对有效,至少对我们使用的数据而言。似乎没有任何重复的位图数据,我可以看到,这主要是我害怕从一个图像对象到另一个图像对象。
  3. 有一次我转换为CIImage,因为这个类也允许绘制图像的子区域。这似乎比转换为NSImage慢,但确实让我有机会通过一些Core Image过滤器来摆弄位图。
  4. 使用CGImageCreateWithImageInRect()是最快的;也许这已经被优化,因为你上次使用它。 documentation for this function表示生成的图像保留了对原始图像的引用,这似乎与您对写入时复制语义的假设一致。在我的基准测试中,似乎没有重复的数据,但也许我读错了结果。我们采用这种方法是因为它不仅速度最快,而且似乎是一种更“干净”的方法,将整个过程保持在一个框架中。


0
投票

我相信建议使用裁剪区域。


0
投票

在编写一个简单的基于2D平铺的游戏时,我遇到了类似的问题。

我获得不错表现的唯一方法是:

1)使用CGContextDrawImage()将tileheet CGImage预呈现为CGBitmapContext

2)创建另一个CGBitmapContext作为屏幕外渲染缓冲区,其大小与我绘制的UIView相同,并且与(1)中的上下文相同。

3)编写我自己的快速blit例程,该例程将像素区域(CGRect)从(1)中创建的位图上下文复制到(2)中创建的位图上下文。这很简单:只需简单的内存复制(以及一些额外的每像素操作,以便在需要时进行alpha混合),请记住栅格在缓冲区中的顺序相反(图像中的最后一行像素位于缓冲区的开头)。

4)绘制帧后,使用CGContextDrawImage()在视图中绘制屏幕外缓冲区。

据我所知,每次调用CGImageCreateWithImageInRect()时,它都会将整个PNG文件解码为原始位图,然后将所需的位图区域复制到目标上下文。

© www.soinside.com 2019 - 2024. All rights reserved.