2

I can't figure out how to use the GLKView:snapshot method.

I'm using a GLKView to render some OpenGL stuff. It all works; seems like I have it all set up correctly.

But, when I try to do a snapshot, it fails: I get a null return value, and the following log message:

Error: CGImageCreate: invalid image size: 0 x 0.

Seems like this would mean the view itself is invalid for some reason, but it's not -- everything is working, aside from this.

I've looked at a few code samples, and I'm not doing anything different.

So... anyone seen this before? Ideas?

Anna Dickinson
  • 3,307
  • 24
  • 43
  • Any update on this? I am getting the same thing. – The Way Jul 09 '13 at 09:09
  • I found this http://stackoverflow.com/a/4787311/273312 Its seems that when working with CAEAGLLayer as in the GLPaint sample one must use a different, more direct means to create a UIImage. – The Way Jul 09 '13 at 09:51

2 Answers2

1

I never figured out the above problem; however, I found an excellent workaround. I found this chunk which just reads the render buffer and saves it to a UIImage. Problem solved!

- (UIImage*)snapshotRenderBuffer {

    // 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, viewRenderbuffer);

    NSInteger dataLength = backingWidth * backingHeight * 4;
    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));

    // Read pixel data from the framebuffer
    glPixelStorei(GL_PACK_ALIGNMENT, 4);
    glReadPixels(0.0f, 0.0f, backingWidth, backingHeight, 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(
                                    backingWidth, backingHeight, 8, 32, backingWidth * 4, colorspace, 
                                    kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast,
                                    ref, NULL, true, kCGRenderingIntentDefault);

    // (sayeth abd)
    // This creates a context with the device pixel dimensions -- not points. 
    // To be compatible with all devices, you're meant to keep everything as points and a scale factor;  but,
    // this gives us a scaled down image for purposes of saving.  So, keep everything in device resolution,
    // and worry about it later...
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(backingWidth, backingHeight), NO, 0.0f);
    CGContextRef cgcontext = UIGraphicsGetCurrentContext();
    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, backingWidth, backingHeight), iref);

    // Retrieve the UIImage from the current context
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    // Clean up
    free(data);

    return image;
}
Anna Dickinson
  • 3,307
  • 24
  • 43
  • 1
    This is a very bad idea. [Apple docs say explicitly not to do this](http://developer.apple.com/library/ios/documentation/GLkit/Reference/GLKView_ClassReference/Reference/Reference.html#//apple_ref/occ/instm/GLKView/snapshot) : "never attempt to directly read the contents of the underlying framebuffer using OpenGL ES functions". Most likely, your problem lies in not properly binding the correct framebuffer during your draw call, as M-V said in another comment. – admsyn Oct 11 '12 at 19:50
0

Maybe this doesn't apply in your case, but the docs for GLKView:snapshot say:

Never call this method inside your drawing function.

M-V
  • 5,167
  • 7
  • 52
  • 55
  • maybe you can take a look at - (void)bindDrawable - I had an issue once where missing this call caused problems with FBOs. – M-V Aug 07 '12 at 10:50