2

Hi I am trying out drawing app and have a problem when it comes to saving the image that is drawn. Right now I'm very early in learning this but I have added code from: How to get UIImage from EAGLView? to save the image that was drawn.

I have created a new app, then displayed a viewController that I created. In IB I have added a view which is the PaintingView, and an imageView lies behind it.

The only modification I have done to the PaintingView so far is to change the background to clear and set the background to clear so that I can display an image behind it. The drawing works great, my only problem is saving.

- (void)saveImageFromGLView:(UIView *)glView {

    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
        {
            /// This IS being activated with code 0
            NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
    }


    int s = 1;
    UIScreen* screen = [ UIScreen mainScreen ];
    if ( [ screen respondsToSelector:@selector(scale) ] )
        s = (int) [ screen scale ];

    const int w = self.frame.size.width;
    const int h = self.frame.size.height;
    const NSInteger myDataLength = w * h * 4 * s * s;
    // allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, w*s, h*s, 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 < h*s; y++)
    {
        memcpy( buffer2 + (h*s - 1 - y) * w * 4 * s, buffer + (y * 4 * w * s), w * 4 * s );
    }
    free(buffer); // work with the flipped buffer, so get rid of the original one.

    // make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
    // prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * w * s;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    // make the cgimage
    CGImageRef imageRef = CGImageCreate(w*s, h*s, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
    // then make the uiimage from that
    UIImage *myImage = [ UIImage imageWithCGImage:imageRef scale:s orientation:UIImageOrientationUp ];
    UIImageWriteToSavedPhotosAlbum( myImage, nil, nil, nil );
    CGImageRelease( imageRef );
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpaceRef);
    free(buffer2);    

}

Adding the above code to the Sample app works fine, the problem is doing it in my new app. The only difference I can tell is that I have not included PaintingWindow - would that be the problem?

It's as if the saveImage method isn't seeing the data for drawings.

Community
  • 1
  • 1
Brodie
  • 3,526
  • 8
  • 42
  • 61
  • The method seems fine, if you havent changed anything from the original code (which i suppose must be from brad larson cuz hes always working with this stuff) the only thing i can think about is that you are calling this when the frame buffer has been cleared. are you making a call to clear the frame buffer? Have you tried this without setting the background to clear as well does it work? – Pochi Mar 27 '12 at 04:51
  • Good idea - I hadn't tried that but sadly there was no change. Just a solid black png. The only place where the buffer is deleted is in a method called destroyFrameBuffer. That is only ever called once, when the view is first loaded. I afree that it sounds like the buffer has been cleared. Would there be a good way to NSLog the contents/content size of the buffer to tell? – Brodie Mar 27 '12 at 05:06
  • Actually - I just added an NSLOG statement to the top of the saveImage method and it looks like there is a problem with the buffer - I updated the question to reflect this – Brodie Mar 27 '12 at 05:09
  • first try using this method in a place where you are sure the frame buffer is intact, (even if its in the rendering method, just add a breakpoint so it doesnt crash by trying to save a ton of times). I just saw that you have (UIView *)glView as aparameter which means you might be trying to call it from somewhere else (altho here it does nothing). – Pochi Mar 27 '12 at 05:13
  • Additionally, I have moved this if statement rhroughout the entire drawing process and the ONLY time it fails is in this saveImage method. – Brodie Mar 27 '12 at 05:18
  • @Luis - you're right. I am calling it from the drawingViewController - is that the issue? – Brodie Mar 27 '12 at 05:20
  • Where exactly are you calling this method? Outside of the rendering loop? because the rendering loop usually has a clear buffer command somewhere around, it should be at the begining of the rendering so that this method works. like i told you, set a breakpoint and put this inside the rendering loop, and tell me if it works please – Pochi Mar 27 '12 at 05:22
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/9344/discussion-between-luis-oscar-and-brodie) – Pochi Mar 27 '12 at 05:23

3 Answers3

4

The save method should be called within the scope of the OpenGL context. To solve this you can move your method within the same rendering .m file and call this function from outside.

Also you need to consider OpenGL clear color.

(detail explanation in comments, lol)

Pochi
  • 13,391
  • 3
  • 64
  • 104
  • Thanks again - To summarize for anyone with this issue, I was calling the save method from the main drawing viewController instead of the rendering layer itself. When I changed this, it still appeared to not be working because I had changed the openGL background color to be clear, which in OpenGL is black. – Brodie Mar 27 '12 at 05:59
1

I found that changing the CGBitmapInfo into:

CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;

Results in a transparent background.

hotdogsoup.nl
  • 1,078
  • 1
  • 9
  • 22
0

Ah, you have to do this at the beginning.

[EAGLContext setCurrentContext:drawContext];
Jeffrey Sun
  • 7,789
  • 1
  • 24
  • 17