ios - 在将大型 UIImage 绘制到其中后,CGContextDrawImage 非常慢

标签 ios performance core-graphics cgcontextdrawimage

看起来 CGContextDrawImage(CGContextRef, CGRect, CGImageRef) 在绘制由 CoreGraphics(即使用 CGBitmapContextCreateImage)创建的 CGImage 时比在绘制支持 UIImage 的 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。

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

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

更新 3:说得太早了。先前的更新适用于大小为 2048x2048 的图像,但步进到 1936x2592(相机大小)裸 CGImage 方法仍然慢得多,无论操作顺序或内存情况如何。也许有一些 CG 内部限制使 16MB 的图像有效,而 21MB 的图像无法有效处理。绘制相机尺寸比 2048x2048 慢 20 倍。 UIImage 以某种方式提供其 CGImage 数据比纯 CGImage 对象快得多。 o.O

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

更新 5(第 2 天):在创建了比昨天回答的问题更多的问题后,我今天有些 了。我可以肯定地说的是:

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

我通过 1) 首先创建一个非 alpha 上下文 (1936x2592) 证明了这一点。 2) 用随机颜色的 2x2 方 block 填充它。 3) 全帧将 CGImage 绘制到该上下文中是快速的(0.17 秒) 4) 重复实验但使用支持 UIImage 的绘制 CGImage 填充上下文。随后的全帧图像绘制时间为 6 秒以上。慢WWWW。

不知何故,使用(大)UIImage 绘制到上下文中会大大减慢所有后续绘制到该上下文中的速度。

最佳答案

经过大量实验后,我认为我找到了处理此类情况的最快方法。上面的绘图操作需要 6 秒以上,现在是 0.1 秒。是的。这是我的发现:

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

  • 使用 CGLayers!这些使屏幕外绘图性能更好。它的工作原理基本上如下。 1) 使用 CGLayerCreateWithContext 从上下文中创建一个 CGLayer。 2) 对使用 CGLayerGetContext 获得的本层上下文进行任何绘图/绘图属性设置。从原始上下文中读取任何像素或信息。 3) 完成后,使用 CGContextDrawLayerAtPoint 将此 CGLayer“标记”回原始上下文。只要您牢记这一点,就会很快:

  • 1) 在使用 CGContextDrawLayerAtPoint 将图层“标记”回 CGContextRef 之前,释放从上下文创建的任何 CGImage(即使用 CGBitmapContextCreateImage 创建的 CGImage)。这会在绘制该图层时将速度提高 3-4 倍。 2)让你的像素格式在任何地方都一样!! 3) 尽快清理 CG 对象。在内存中徘徊的东西似乎会造成奇怪的减速情况,可能是因为存在与这些强引用相关的回调或检查。只是一个猜测,但我可以说尽快清理内存对性能有很大帮助。

关于ios - 在将大型 UIImage 绘制到其中后,CGContextDrawImage 非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7560979/

相关文章:

c# - StringBuilder 中最快的搜索方法

iphone - 基于图像的核心图形绘制

ios - 在 iPhone 4/4S 和 iPad 2 上生成 54 兆像素图像

ios - 越狱应用程序开发构建和运行应用程序

ios - 了解 CoreData 中 Transformable 的错误

ios - 如何将从互联网下载的数据保存到内部设备?

c++ - Graphviz 的性能

iphone - 创建自定义 UIButton 类

具有多个 union 和 group by 的 MySQL 查询

iPhone : How to change color of particular pixel of a UIImage?