0

I need to read content of CAEAGLLayer, which has various widths and heights (based on background image size). on iPad emulator everything is okay, but on device I have crashes or weird horizontal lines instead of content. Crashes not happens on width, for example, from 537 to 544 pixels

I'm using following code

- (UIImage*)image
{
        // Get the size of the backing CAEAGLLayer
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

    NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight;
    NSInteger dataLength = width * height * 4;
    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));

        // Read pixel data from the framebuffer
    glPixelStorei(GL_PACK_ALIGNMENT, 4);
    glReadPixels(x, y, width, height, 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(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
                                    ref, NULL, true, kCGRenderingIntentDefault);

        // OpenGL ES measures data in PIXELS
        // Create a graphics context with the target size measured in POINTS
    NSInteger widthInPoints, heightInPoints;
        // if (NULL != UIGraphicsBeginImageContextWithOptions) {
        // // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
        // // Set the scale parameter to your OpenGL ES view's contentScaleFactor
        // // so that you get a high-resolution snapshot when its value is greater than 1.0
        // CGFloat scale = eaglview.contentScaleFactor;
        // widthInPoints = width / scale;
        // heightInPoints = height / scale;
        // UIGraphicsBeginImageContextWithOptions(CGSizeMake( widthInPoints, heightInPoints), NO, scale);
        // }
        // else {
        // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
    widthInPoints = width;
    heightInPoints = height;
    UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
        // }

    CGContextRef cgcontext = UIGraphicsGetCurrentContext();

        // UIKit coordinate system is upside down to GL/Quartz coordinate system
        // Flip the CGImage by rendering it to the flipped bitmap context
        // The size of the destination area is measured in POINTS
    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);

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

    UIGraphicsEndImageContext();

        // Clean up
    free(data);
    CFRelease(ref);
    CFRelease(colorspace);
    CGImageRelease(iref);

    return image1;
}
Vladimir
  • 94
  • 6

2 Answers2

4

The view you are reading from, or your drawable area, must be a multiple of 32 (possibly 16, but I haven't tested this yet). Maybe you can try resizing your draw area to a multiple of 32? I had the horizontal line issue previously and resizing the section I was reading from 400x300 to 384x288 fixed everything.

Beaker
  • 1,633
  • 13
  • 22
  • Forgot to add that this only seems to apply to glReadPixels. – Beaker Sep 20 '10 at 09:09
  • Thank you for answer! It is not an option for me - I'm using background image with variable width, so drawable area should be equal to this image. It is a very weird problem. Why 537 works? – Vladimir Sep 20 '10 at 11:31
  • Looks like, that multiple of 24 works (RGBA, 4*8?). Maximum buffer width may be 1088. Now, it is solved my problem, Thank you, Ginamin! – Vladimir Sep 20 '10 at 12:11
  • No worries! I had considered that any multiple of 2 would work. However, when I tried this it still biffed at 400x300. I'm not exactly sure why this happens... – Beaker Sep 21 '10 at 02:15
  • just found, that 816 does not working. So only 32 multiplier works. And occasional 24/16. For OpenGL (not iOS), I found, that this problem is linked with buffer alignment. But iOS does not have additional alignment parameters, provided by other platforms – Vladimir Sep 23 '10 at 18:48
  • Yes, I also tried a 24 last night (800x600) and I couldn't get it running. Good note on the buffer alignment. Thanks! – Beaker Sep 24 '10 at 02:28
0

In my case works any width multiplied by 4!

Heorhiy
  • 190
  • 2
  • 14
  • did you tested it closely? It may work with some width, but stable only on 32x. Another problem, at least on iPad, width cannot exceed 1024 in lansdscape and 768 in portrait – Vladimir Dec 16 '10 at 07:26