5

When I try to use this method to convert a OpenGL view to UIImage, only the view's background is returned, but not the GLView content. How can I convert OpenGL's context into a UIImage?

Community
  • 1
  • 1
ohho
  • 50,879
  • 75
  • 256
  • 383
  • I had the same problem and with the answers provided here I got a black screen. See my answer to this question to see how I finally got it to work. http://stackoverflow.com/questions/11036288/xcode-screenshot-eaglcontext/11868013#11868013 – Nate_Hirsch Aug 08 '12 at 15:39

3 Answers3

9

It depends on what OpenGL view you are using. Since iOS 5 you can make use of GLKit and the corresponding GLKView that greatly simplifies the process of rendering an UIImage.

GLKView* v = (GLKView*) _previewViewController.view;
UIImage* thumbnail = [v snapshot];

http://developer.apple.com/library/ios/#documentation/GLkit/Reference/GLKView_ClassReference/Reference/Reference.html

Christoph
  • 1,965
  • 16
  • 35
6

Use the below code to convert your opengl view in UIImage .

GLubyte *buffer = (GLubyte *) malloc(backingWidth * backingHeight * 4);
 GLubyte *buffer2 = (GLubyte *) malloc(backingWidth * backingHeight * 4);
 GLvoid *pixel_data = nil;
 glReadPixels(0, 0, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE,
         (GLvoid *)buffer);
for (int y=0; y<backingHeight; y++) {
     for (int x=0; x<backingWidth*4; x++) {
         buffer2[y * 4 * backingWidth + x] =
     buffer[(backingHeight - y - 1) * backingWidth * 4 + x];
     }
 }
 CGDataProviderRef provider;
 provider = CGDataProviderCreateWithData(NULL, buffer2,
                                          backingWidth * backingHeight * 4,
                                          freeImageData);
 // set up for CGImage creation
 int bitsPerComponent = 8;
 int bitsPerPixel = 32;
 int bytesPerRow = 4 * backingWidth;
 CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
 CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
 // Use this to retain alpha
 //CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
 CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
 CGImageRef imageRef = CGImageCreate(backingWidth, backingHeight,
                                 bitsPerComponent, bitsPerPixel,
                                 bytesPerRow, colorSpaceRef,
                                 bitmapInfo, provider,
                                 NULL, NO,
                                 renderingIntent);
 // this contains our final image.
 UIImage *newUIImage = [UIImage imageWithCGImage:imageRef];

Taken from

Jhaliya - Praveen Sharma
  • 31,697
  • 9
  • 72
  • 76
4

Thanks for the code. I find it usefull but I had to put some extra code in order to properly release allocated memory with buffer, buffer2, imageRef, colorSpaceRef and provider pointer. Note that buffer2 is released with provider release function.

static void myProviderReleaseData (void *info,const void *data,size_t size)
{
    free((void*)data);
}

- (UIImage*)renderToImage
{
    // The image size should be grabbed from your ESRenderer class. 
    // That parameter is get in renderer function: 
    // - (BOOL) resizeFromLayer:(CAEAGLLayer *)layer {
    // glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    GLint backingWidth = renderer.backingWidth;
    GLint backingHeight = renderer.backingHeight;

    GLubyte *buffer = (GLubyte *) malloc(backingWidth * backingHeight * 4);
    GLubyte *buffer2 = (GLubyte *) malloc(backingWidth * backingHeight * 4);

    glReadPixels(0, 0, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE,
                 (GLvoid *)buffer);
    for (int y=0; y<backingHeight; y++) {
        for (int x=0; x<backingWidth*4; x++) {
            buffer2[y * 4 * backingWidth + x] =
            buffer[(backingHeight - y - 1) * backingWidth * 4 + x];
        }
    }
    free(buffer);
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2,
                                            backingWidth * backingHeight * 4,
                                        myProviderReleaseData);
    // set up for CGImage creation
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * backingWidth;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    // Use this to retain alpha
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    CGImageRef imageRef = CGImageCreate(backingWidth, backingHeight,
                                        bitsPerComponent, bitsPerPixel,
                                    bytesPerRow, colorSpaceRef,
                                    bitmapInfo, provider,
                                    NULL, NO,
                                    renderingIntent);
    // this contains our final image.
    UIImage *newUIImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(provider);

    return newUIImage;
}   
Krešimir Prcela
  • 4,257
  • 33
  • 46
  • This renders black background on the layer whereas i have already set my layer background to clear color in initwithcoder ????? – manishnath Sep 19 '11 at 07:47