获取openGL图像 - 在模拟器中运行,在iPad上崩溃

时间:2012-07-03 20:51:52

标签: iphone objective-c ios ios5 ios-simulator

此函数的目的是从openGL图像返回UIImage。它被转换为CG图像的原因是openGL和UIKit元素可以在彼此之上呈现,这在另一个函数中处理。

奇怪的是,当应用程序在模拟器中运行时,一切正常。但是,在多个不同的iPad上测试应用程序后,在drawGlToImage上调用self方法时,应用程序崩溃时出现EXC_BAD_ACCESS代码= 1错误。有谁知道我在这做什么导致这个?我已经读过UIGraphicsBeginImageContext()曾经遇到线程安全问题,但似乎在iOS 4中修复了这个问题。

    - (UIImage *)drawGlToImage
{
    self.context = [EAGLContext currentContext];
    [EAGLContext setCurrentContext:self.context];
    UIGraphicsBeginImageContext(self.view.frame.size);

    unsigned char buffer[1024 * 768 * 4];
    NSInteger dataSize = 1024 * 768 * 4;

    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    UIGraphicsPushContext(currentContext);

    glReadPixels(0, 0, 1024, 768, GL_RGBA, GL_UNSIGNED_BYTE, &buffer);

    //flip the image
    GLubyte *flippedBuffer = (GLubyte *) malloc(dataSize);

    for(int y = 0; y <768; y++)
    {
        for(int x = 0; x <1024 * 4; x++)
        {
            if(buffer[y* 4 * 1024 + x]==0)
                flippedBuffer[(767 - y) * 1024 * 4 + x]=1;
            else
                flippedBuffer[(767 - y) * 1024 * 4 + x] = buffer[y* 4 * 1024 + x];
        }
    }



    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, flippedBuffer, 1024 * 768 * 4, NULL);
    CGImageRef iref = CGImageCreate(1024,768,8,32,1024*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaLast, ref, NULL, true, kCGRenderingIntentDefault);

    CGContextScaleCTM(currentContext, 1.0, -1.0);
    CGContextTranslateCTM(currentContext, 0, -self.view.frame.size.height);

    UIGraphicsPopContext();
    UIImage *image = [[UIImage alloc] initWithCGImage:iref];
    UIGraphicsEndImageContext();

    return image;
    free(flippedBuffer);
    UIGraphicsPopContext();
}

当按下某个按钮时,调用的方法会进行此分配,从而导致应用程序崩溃。

UIImage *glImage = [self drawGlToImage];

2 个答案:

答案 0 :(得分:0)

我不确定您在哪个阶段调用此方法。但在调用任何OpenGL函数之前,您需要设置正确的OpenGL上下文。在Xcode模板中,就是这一行

[EAGLContext setCurrentContext:self.context];

答案 1 :(得分:0)

以下是用于解决问题的代码

- (UIImage *)drawGlToImage {

    // Code borrowed and tweaked from:
    // http://stackoverflow.com/questions/9881143/missing-part-of-the-image-when-taking-screenshot-while-supporting-retina-display

    CGFloat scale = UIScreen.mainScreen.scale;
    CGFloat xOffset = 40.0f;
    CGFloat yOffset = -16.0f;
    CGSize size = CGSizeMake((self.chart.frame.size.width) * scale,
                             self.chart.frame.size.height * scale);

    //Create buffer for pixels
    GLuint bufferLength = size.width * size.height * 4;
    GLubyte* buffer = (GLubyte*)malloc(bufferLength);

    //Read Pixels from OpenGL
    glReadPixels(0.0f, 0.0f, size.width, size.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    //Make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL);

    //Configure image
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * size.width;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGImageAlphaLast;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    CGImageRef iref = CGImageCreate(size.width, size.height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    uint32_t* pixels = (uint32_t*)malloc(bufferLength);
    CGContextRef context = CGBitmapContextCreate(pixels, size.width, size.height, 8, size.width * 4, CGImageGetColorSpace(iref), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextTranslateCTM(context, 0.0f, size.height);
    CGContextScaleCTM(context, 1.0f, -1.0f);

    // These numbers are a little magical.
    CGContextDrawImage(context, CGRectMake(xOffset, yOffset, ((size.width - (6.0f * scale)) / scale) - (xOffset / 2), (size.height / scale) - (yOffset / 2)), iref);
    UIImage *outputImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];

    //Dealloc
    CGDataProviderRelease(provider);
    CGImageRelease(iref);
    CGContextRelease(context);
    free(buffer);
    free(pixels);

    return outputImage;
}