如何更快地将视图渲染成图像?

我正在做放大镜的应用程序,它允许用户触摸屏幕并移动他的手指,将有一个放大镜与他的手指path。 我用截图实现它,并将图像分配给放大镜图像视图,如下所示:

CGSize imageSize = frame.size; UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0); CGContextRef c = UIGraphicsGetCurrentContext(); CGContextScaleCTM(c, scaleFactor, scaleFactor); CGContextConcatCTM(c, CGAffineTransformMakeTranslation(-frame.origin.x, -frame.origin.y)); [self.layer renderInContext:c]; UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return screenshot; 

问题是self.layer renderInContext速度很慢,所以用户在移动手指的时候感觉不舒服。 而我试图在其他线程中运行self.layer renderInContext ,但是,这使放大镜图像看起来很奇怪,因为放大镜中的图像显示延迟。

有没有更好的方法来渲染视图到图像? renderInContext:使用GPU?

不,在iOS6中,renderInContext:是唯一的方法。 这很慢。 它使用CPU。

呈现UIKit内容的方法

renderInContext:

 [view.layer renderInContext:UIGraphicsGetCurrentContext()]; 
  • 需要iOS 2.0。 它运行在CPU中 。
  • 它不捕获非仿射变换,OpenGL或video内容的视图。
  • 如果animation正在运行,您可以select捕捉:
    • view.layer捕获animation的最后一帧。
    • view.presentationLayer ,它捕获animation的当前帧。

snapshotViewAfterScreenUpdates:

 UIView *snapshot = [view snapshotViewAfterScreenUpdates:YES]; 
  • 需要iOS 7。
  • 这是最快的方法。
  • 视图contents是不可变的。 如果你想应用效果不好。
  • 它捕获所有内容types(UIKit,OpenGL或video)。

resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets

 [view resizableSnapshotViewFromRect:rect afterScreenUpdates:YES withCapInsets:edgeInsets] 
  • 需要iOS 7。
  • snapshotViewAfterScreenUpdates:相同snapshotViewAfterScreenUpdates:但可resize的插页。 content也是不变的。

drawViewHierarchyInRect:afterScreenUpdates:

 [view drawViewHierarchyInRect:rect afterScreenUpdates:YES]; 
  • 需要iOS 7。
  • 它吸取了当前的情况。
  • 根据会话226,它比renderInContext:更快。

请参阅WWDC 2013 Session 226实现在iOS上使用UI来了解新的快照API。


如果有任何帮助,下面是一些代码,当一个仍在运行时放弃捕获尝试。

这个限制一次阻止执行,并放弃其他人。 从这个SO回答 。

 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); dispatch_queue_t renderQueue = dispatch_queue_create("com.throttling.queue", NULL); - (void) capture { if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW) == 0) { dispatch_async(renderQueue, ^{ // capture dispatch_semaphore_signal(semaphore); }); } } 

这是干什么的?

  • 为一(1)个资源创build一个信号量。
  • 创build一个串行队列。
  • DISPATCH_TIME_NOW表示超时时间为无,因此在红灯时立即返回非零值。 因此,不执行if内容。
  • 如果绿灯亮起,请asynchronous运行程序段,然后再次设置绿灯。