views:

710

answers:

4
+2  Q: 

GLPaint save image

I'm trying to develop a complex painting application on the iPhone. I'm currently drawing using Quartz (e.g. CGContext...). Unfortunately the Quartz overhead is just too slow for the type of drawing I'm doing, and I'm porting to OpenGL calls using the GLPaint example as a reference point.

Is there a way to get a UIImage/CGImage from the EAGLview class (the equivalent of Quartz's UIGraphicsGetImageFromCurrentImageContext)? Basically I need to save the pictures drawn by the GLPaint application.

+2  A: 

Hey Drew,

It's definitely possible. The trick is to use glReadPixels to pull the image data out of the OpenGL framebuffer into memory you can use. Once you have a pointer to the image data, you can use CGDataProviderCreateWithData and CGImageCreate to create a CGImage from the data. I'm working on an OpenGL-based drawing app that uses this technique a lot!

Ben Gotow
+1  A: 
-(UIImage *) saveImageFromGLView
{
    NSInteger myDataLength = 320 * 480 * 4;
    // allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, 320, 480, 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 <480; y++)
    {
        for(int x = 0; x <320 * 4; x++)
        {
            buffer2[(479 - y) * 320 * 4 + x] = buffer[y * 4 * 320 + 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 * 320;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    // make the cgimage
    CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
    // then make the uiimage from that
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];
    return myImage;
}
Quakeboy
Thanks so much Quakeboy! It works and saved me a lot of time! :)
paul_sns
A: 

hi.. i wonder if we have to use the same methodology in order to save a state and then later retrieve the same state after the application is relaunched

A: 
void SaveScreenImage()

{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGImageRef cgImage = UIGetScreenImage();
void *imageBytes = NULL;
if (cgImage == NULL) {
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
imageBytes = malloc(320 * 480 * 4);
CGContextRef context = CGBitmapContextCreate(imageBytes, 320, 480, 8, 320 * 4, colorspace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorspace);
for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
        CGRect bounds = [window bounds];
        CALayer *layer = [window layer];
        CGContextSaveGState(context);
        if ([layer contentsAreFlipped]) {
            CGContextTranslateCTM(context, 0.0f, bounds.size.height);
            CGContextScaleCTM(context, 1.0f, -1.0f);
        }
[layer renderInContext:(CGContextRef)context];
        CGContextRestoreGState(context);
    }
    cgImage = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
}
UIImage *image=[UIImage imageWithCGImage:cgImage];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); 
[pool release];
}

This code will save as you see on the screen.But it maybe private api.