如何更快地将视图渲染成图像?
我正在做放大镜的应用程序,它允许用户触摸屏幕并移动他的手指,将有一个放大镜与他的手指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运行程序段,然后再次设置绿灯。