iOS CAEAGLLayer生成UIImage

  1. 使用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使用上面的方法,截出来的图就是黑的。

    查看这个方法的注释

     /** 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包含的一种情况

  1. 对于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实际上是从缓冲区中读取数据,如果使用了双缓冲区,则默认是从正在显示的缓冲(即前缓冲)中读取,而绘制工作是默认绘制到后缓冲区的。因此,如果需要读取已经绘制好的像素,往往需要先交换前后缓冲”

    从缓冲区获取数据会存在一些问题,因为这个缓冲区谁都可以去操作,所以这个方法很难直接使用。

  2. 使用 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来避免闪退。

你可能感兴趣的:(iOS CAEAGLLayer生成UIImage)