简体   繁体   中英

Getting an openGL image - runs in simulator, crashes on iPad

The purpose of this function is to return a UIImage from an openGL image. The reason it's being converted to a CG image is so openGL and UIKit elements can be rendered on top of each other, which is taken care of in another function.

The strange thing is, when the app is run in the simulator, everything works fine. However, after testing the app on multiple different iPads, when the drawGlToImage method is called on self , the app crashes with a EXC_BAD_ACCESS code=1 error. Does anyone know what I'm doing here that would cause this? I've read that UIGraphicsBeginImageContext() used to have thread safety issues, but it seems like that was fixed in 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();
}

When a button is pressed, a method that is called makes this assignment, which causes the app to crash.

UIImage *glImage = [self drawGlToImage];

I am not sure in which phase you are calling this method. But before calling any OpenGL functions you need to set the right OpenGL context. In the Xcode template it is this line

[EAGLContext setCurrentContext:self.context];

Here's the code used to solve it

- (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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM