1

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

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

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

问题是,CGContextDraw 只需要一个目标矩形 - 并拉伸源 CGImage 以填充它。

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

起初我认为这将是一个“便宜”的操作——每个 CGImage 似乎没有必要包含自己的图像位副本——但是,分析表明使用 CGImageCreateWithImageInRect() 是一项相当昂贵的操作。

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


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

4

4 回答 4

2

I was in the same boat as you. CGImageCreateWithImageInRect() worked better for my needs but previously I had attempted to convert to an NSImage, and prior to that I was clipping the context I was drawing in, and translating so that CGContextDrawImage() would draw the right data into the clipped region.

Of all of the solutions I tried:

  1. Clipping and translating was prohibitively tolling on the CPU. It was too slow. It seemed that increasing the amount of bitmap data only slightly made significant performance impacts, suggesting that this approach lacks any sort of scalability.

  2. Conversion to NSImage was relatively efficient, at least for the data we were using. There didn't seem to be any duplication of bitmap data that I could see, which was mostly what I was afraid of going from one image object to another.

  3. At one point I converted to a CIImage, as this class also allows drawing subregions of the image. This seemed to be slower than converting to NSImage, but did offer me the chance to fiddle around with the bitmap by passing through some of the Core Image filters.

  4. Using CGImageCreateWithImageInRect() was the fastest of the lot; maybe this has been optimised since you had last used it. The documentation for this function says the resulting image retains a reference to the original image, this seems to agree with what you had assumed regarding copy-on-write semantics. In my benchmarks, there appears to be no duplication of data but maybe I'm reading the results wrong. We went with this method because it was not only the fastest but it seemed like a more “clean” approach, keeping the whole process in one framework.

于 2012-12-04T01:29:37.137 回答
0

使用 CGImage 创建一个 NSImage。NSImage 对象可以很容易地只将它的一部分绘制到目标矩形

于 2010-08-25T14:10:10.923 回答
0

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

于 2010-08-25T17:14:26.850 回答
0

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

我获得体面表现的唯一方法是:

1) 使用 CGContextDrawImage() 将 tilesheet CGImage 预渲染为 CGBitmapContext

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

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

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

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

于 2019-04-25T04:31:17.713 回答