2013年9月10日 星期二

如何把OpenGL ES的view做snapshot再轉成UIImage?

摘自https://developer.apple.com/library/ios/qa/qa1704/_index.html

Q:  How do I take a snapshot of my OpenGL ES view and save the result in a UIImage?

// IMPORTANT: Call this method after you draw and before -presentRenderbuffer:.

- (UIImage*)snapshot:(UIView*)eaglview

{

    GLint backingWidth, backingHeight;



    // Bind the color renderbuffer used to render the OpenGL ES view

    // If your application only creates a single color renderbuffer which is already bound at this point,

    // this call is redundant, but it is needed if you're dealing with multiple renderbuffers.

    // Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class.

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, _colorRenderbuffer);



    // Get the size of the backing CAEAGLLayer

    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);

    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);



    NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight;

    NSInteger dataLength = width * height * 4;

    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));



    // Read pixel data from the framebuffer

    glPixelStorei(GL_PACK_ALIGNMENT, 4);

    glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);



    // Create a CGImage with the pixel data

    // If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel

    // otherwise, use kCGImageAlphaPremultipliedLast

    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);

    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();

    CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,

                                    ref, NULL, true, kCGRenderingIntentDefault);



    // OpenGL ES measures data in PIXELS

    // Create a graphics context with the target size measured in POINTS

    NSInteger widthInPoints, heightInPoints;

    if (NULL != UIGraphicsBeginImageContextWithOptions) {

        // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration

        // Set the scale parameter to your OpenGL ES view's contentScaleFactor

        // so that you get a high-resolution snapshot when its value is greater than 1.0

        CGFloat scale = eaglview.contentScaleFactor;

        widthInPoints = width / scale;

        heightInPoints = height / scale;

        UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);

    }

    else {

        // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext

        widthInPoints = width;

        heightInPoints = height;

        UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));

    }



    CGContextRef cgcontext = UIGraphicsGetCurrentContext();



    // UIKit coordinate system is upside down to GL/Quartz coordinate system

    // Flip the CGImage by rendering it to the flipped bitmap context

    // The size of the destination area is measured in POINTS

    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);

    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);



    // Retrieve the UIImage from the current context

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();



    UIGraphicsEndImageContext();



    // Clean up

    free(data);

    CFRelease(ref);

    CFRelease(colorspace);

    CGImageRelease(iref);



    return image;

}

沒有留言:

張貼留言