大型UIImage绘制后,CGContextDrawImage非常慢

当绘制由CoreGraphics创建的CGImage(即使用CGBitmapContextCreateImage)时,CGContextDrawImage(CGContextRef,CGRect,CGImageRef)似乎执行MUCH WORSE,而不是绘制支持UIImage的CGImage时绘制的CGImage。 看到这个测试方法:

-(void)showStrangePerformanceOfCGContextDrawImage { ///Setup : Load an image and start a context: UIImage *theImage = [UIImage imageNamed:@"reallyBigImage.png"]; UIGraphicsBeginImageContext(theImage.size); CGContextRef ctxt = UIGraphicsGetCurrentContext(); CGRect imgRec = CGRectMake(0, 0, theImage.size.width, theImage.size.height); ///Why is this SO MUCH faster... NSDate * startingTimeForUIImageDrawing = [NSDate date]; CGContextDrawImage(ctxt, imgRec, theImage.CGImage); //Draw existing image into context Using the UIImage backing NSLog(@"Time was %f", [[NSDate date] timeIntervalSinceDate:startingTimeForUIImageDrawing]); /// Create a new image from the context to use this time in CGContextDrawImage: CGImageRef theImageConverted = CGBitmapContextCreateImage(ctxt); ///This is WAY slower but why?? Using a pure CGImageRef (ass opposed to one behind a UIImage) seems like it should be faster but AT LEAST it should be the same speed!? NSDate * startingTimeForNakedGImageDrawing = [NSDate date]; CGContextDrawImage(ctxt, imgRec, theImageConverted); NSLog(@"Time was %f", [[NSDate date] timeIntervalSinceDate:startingTimeForNakedGImageDrawing]); } 

所以我想问题是,#1可能导致这种情况,#2是否有解决方法,即创建CGImageRef的其他方法可能更快? 我意识到我可以先将所有东西转换为UIImages,但这是一个如此丑陋的解决方案。 我已经有CGContextRef坐在那里。

更新:在绘制小图像时,这似乎不一定是真的吗? 这可能是一个线索 – 当使用大图像(即全尺寸相机图片)时,这个问题会被放大。 640×480在两种方法的执行时间方面似乎非常相似

更新2:好的,所以我发现了一些新东西..它实际上不是改变性能的CGImage的支持。 我可以翻转2步的顺序,使UIImage方法表现得很慢,而“裸”的CGImage会超快。 无论你在第二场比赛中表现出来都会遭遇糟糕的表现。 这似乎就是这种情况,除非我通过在CGBitmapContextCreateImage创建的图像上调用CGImageRelease来释放内存。 然后UIImage支持的方法随后会很快。 反之不然。 是什么赋予了? “拥挤”的记忆不应该影响这样的表现,不是吗?

更新3:太快说了。 之前的更新适用于尺寸为2048×2048的图像,但步进至1936×2592(相机尺寸),裸CGImage方法仍然较慢,无论操作顺序或内存情况如何。 也许有一些CG内部限制使16MB图像有效,而21MB图像无法有效处理。 它的绘制相机尺寸比2048×2048慢20倍。 不知何故,UIImage提供的CGImage数据比纯CGImage对象快得多。 OO

更新4:我认为这可能与某些内存缓存有关,但无论UIImage是否加载了非缓存[UIImage imageWithContentsOfFile],结果都是相同的,就像使用了[UIImage imageNamed]一样。

更新5(第2天):在创建了比昨天回答的问题之后,我今天有了一些可靠的东西 。 我可以肯定的是以下内容:

  • UIImage背后的CGImages不使用alpha。 (kCGImageAlphaNoneSkipLast)。 我认为也许它们绘制得更快,因为我的上下文使用alpha。 所以我改变了上下文以使用kCGImageAlphaNoneSkipLast。 这使得绘图更快,除非:
  • 使用UIImage FIRST绘制成CGContextRef会使所有后续图像绘制变慢

我通过1)首先创建一个非alpha上下文(1936×2592)certificate了这一点。 2)用随机着色的2×2正方形填充。 3)将CGImage绘制到该上下文中的全帧是快速的(.17秒)4)重复实验但是用支持UIImage的绘制CGImage填充上下文。 随后的全帧图像绘制为6秒以上。 SLOWWWWW。

以某种方式绘制到具有(大)UIImage的上下文会大大减慢所有后续绘制到该上下文中的速度。

经过一段时间的实验,我认为我找到了处理这种情况的最快方法。 上面的绘图操作现在需要6秒以上.1秒。 是。 这是我发现的:

  • 使用像素格式均衡您的上下文和图像! 我问的问题的根源归结为UIImage中的CGImages使用相同的像素格式作为我的上下文。 因此快。 CGImages是一种不同的格式,因此很慢。 使用CGImageGetAlphaInfo检查图像以查看它们使用的像素格式。 我现在正在使用kCGImageAlphaNoneSkipLast,因为我不需要使用alpha。 如果您不在任何地方使用相同的像素格式,则在将图像绘制到上下文中时,Quartz将被迫为每个像素执行昂贵的像素转换。 =慢

  • 使用CGLayers! 这些使得屏幕外绘图性能更好。 这是如何工作的基本如下。 1)使用CGLayerCreateWithContext从上下文创建CGLayer。 2)在CGLayerGetContext获得的THIS LAYER上下文中绘制/设置绘图属性。 从ORIGINAL上下文中读取任何像素或信息。 3)完成后,使用CGContextDrawLayerAtPoint将此CGLayer“标记”回原始上下文。只要您记住,这是快速的:

  • 1)释放从上下文创建的任何CGImages(即使用CGBitmapContextCreateImage创建的CGImages),然后使用CGContextDrawLayerAtPoint将图层“标记”回CGContextRef。 绘制该图层时,这会使速度提高3-4倍。 2)保持你的像素格式无处不在!! 3)尽可能清理CG对象。 在内存中闲逛的东西似乎会产生奇怪的减速情况,可能是因为存在与这些强引用相关联的回调或检查。 只是一个猜测,但我可以说,尽快清理内存有助于提高性能。

我有类似的问题。 我的应用程序必须重新绘制几乎与屏幕大小一样大的图片。 问题在于尽可能快地绘制两个相同分辨率的图像,既不旋转也不翻转,而是每次都缩放并定位在屏幕的不同位置。 毕竟,我在iPad 1上获得了大约15-20 FPS,在iPad4上获得了大约20-25 FPS。 所以…希望这有助于某人:

  1. 正如打字机所说,你必须使用相同的像素格式。 使用AlphaNone可以提高速度。 但更重要的是,在我的案例中,argb32_image调用会进行多次调用,将像素从ARGB转换为BGRA。 所以对我来说最好的bitmapInfo值是(当时; Apple有可能在未来改变一些东西): const CGBitmabInfo g_bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast; const CGBitmabInfo g_bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast;
  2. 如果矩形参数是完整的(通过CGRectIntegral),CGContextDrawImage可以更快地工作。 当图像按因子接近1缩放时,似乎会产生更大的效果。
  3. 使用图层实际上减慢了我的速度。 自2011年以来,一些内部电话可能发生了变化。
  4. 设置低于默认值的上下文的插值质量(通过CGContextSetInterpolationQuality)很重要。 我建议使用(IS_RETINA_DISPLAY ? kCGInterpolationNone : kCGInterpolationLow) 。 宏IS_RETINA_DISPLAY取自此处 。
  5. 确保在创建上下文时从CGColorSpaceCreateDeviceRGB()等获取CGColorSpaceRef。 报告了一些性能问题,用于获取固定颜色空间而不是请求设备的颜色空间。
  6. 从UIImageViewinheritance视图类并简单地将self.image设置为从上下文创建的图像对我来说非常有用。 但是,如果你想这样做,请首先阅读有关使用UIImageView的内容,因为它需要对代码逻辑进行一些更改(因为不再调用drawRect:)。
  7. 如果您可以避免在实际绘图时缩放图像,请尝试这样做。 绘制非缩放图像要快得多 – 不幸的是,对我来说这不是一个选择。