-
使用CALayer的renderInContext,然后从context中获取图片
- (UIImage *)snapshotCALayer { UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale); [window.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; }
这种方法对view对应的layer是CALayer实例是可以的,如果view的layer是CAEAGLLayer的实例就会有问题,比如对GPUImageView使用上面的方法,获取的内容就不是GPUImageView显示的内容。查看这个方法的注释
/** Rendering properties and methods. **/ /* Renders the receiver and its sublayers into 'ctx'. This method * renders directly from the layer tree. Renders in the coordinate space * of the layer. * * WARNING: currently this method does not implement the full * CoreAnimation composition model, use with caution. */ - (void)renderInContext:(CGContextRef)ctx;
不知道是不是* WARNING: currently this method does not implement the full
可能包含的一种情况
-
对于CAEAGLLayer获取截图,网上找了一段代码
+ (UIImage *)glToUIImage:(CGSize)size { CGSize viewSize = size; NSInteger myDataLength = viewSize.width * viewSize.height * 4; // allocate array and read pixels into it. GLubyte *buffer = (GLubyte *) malloc(myDataLength); glReadPixels(0, 0, viewSize.width, viewSize.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); // gl renders "upside down" so swap top to bottom into new array. // there's gotta be a better way, but this works. GLubyte *buffer2 = (GLubyte *) malloc(myDataLength); for(int y = 0; y < viewSize.height; y++) { for(int x = 0; x < viewSize.width* 4; x++) { buffer2[(int)((viewSize.height-1 - y) * viewSize.width * 4 + x)] = buffer[(int)(y * 4 * viewSize.width + x)]; } } // make data provider with data. CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL); // prep the ingredients int bitsPerComponent = 8; int bitsPerPixel = 32; int bytesPerRow = 4 * viewSize.width; CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; // make the cgimage CGImageRef imageRef = CGImageCreate(viewSize.width , viewSize.height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); // then make the uiimage from that UIImage *myImage = [UIImage imageWithCGImage:imageRef]; return myImage; }
对opengl了解不多,但是可以看出数据获取是通过
GLubyte *buffer = (GLubyte *) malloc(myDataLength); glReadPixels(0, 0, viewSize.width, viewSize.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
实现的,仅仅使用了layer的大小,也就是说layer没作为数据源,那数据源从哪里来呢?还是继续搜索,有人说到了这个问题。
“注意:glReadPixels实际上是从缓冲区中读取数据,如果使用了双缓冲区,则默认是从正在显示的缓冲(即前缓冲)中读取,而绘制工作是默认绘制到后缓冲区的。因此,如果需要读取已经绘制好的像素,往往需要先交换前后缓冲”
从缓冲区获取数据会存在一些问题,因为这个缓冲区谁都可以去操作,所以这个方法很难直接使用。
-
使用 UIView (UISnapshotting) 这个分类中的方法
- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates NS_AVAILABLE_IOS(7_0);
经过实践,这个方法对于layer是CAEAGLLayer实例的view也生效。iOS 7.0 开始生效。
截图可以使用这个 https://github.com/shinydevelopment/SDScreenshotCapture
使用 drawViewHierarchyInRect 可能会出现闪退,原因是在遍历layers的时候,layers数组已经发生了改变。如果你要截取的内容包含collectionView这类,很可能会发生闪退,可以使用try-catch来避免闪退。
网友评论