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對應(yīng)的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獲取截圖,網(wǎng)上找了一段代碼

     + (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了解不多,但是可以看出數(shù)據(jù)獲取是通過

     GLubyte *buffer = (GLubyte *) malloc(myDataLength);
     glReadPixels(0, 0, viewSize.width, viewSize.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    

    實現(xiàn)的,僅僅使用了layer的大小,也就是說layer沒作為數(shù)據(jù)源,那數(shù)據(jù)源從哪里來呢?還是繼續(xù)搜索,有人說到了這個問題。

    “注意:glReadPixels實際上是從緩沖區(qū)中讀取數(shù)據(jù),如果使用了雙緩沖區(qū),則默認是從正在顯示的緩沖(即前緩沖)中讀取,而繪制工作是默認繪制到后緩沖區(qū)的。因此,如果需要讀取已經(jīng)繪制好的像素,往往需要先交換前后緩沖”

    從緩沖區(qū)獲取數(shù)據(jù)會存在一些問題,因為這個緩沖區(qū)誰都可以去操作,所以這個方法很難直接使用。

  2. 使用 UIView (UISnapshotting) 這個分類中的方法

     - (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates NS_AVAILABLE_IOS(7_0);
    

    經(jīng)過實踐,這個方法對于layer是CAEAGLLayer實例的view也生效。iOS 7.0 開始生效。

截圖可以使用這個 https://github.com/shinydevelopment/SDScreenshotCapture

使用 drawViewHierarchyInRect 可能會出現(xiàn)閃退,原因是在遍歷layers的時候,layers數(shù)組已經(jīng)發(fā)生了改變。如果你要截取的內(nèi)容包含collectionView這類,很可能會發(fā)生閃退,可以使用try-catch來避免閃退。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容