Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
tutorials:rendering_objects_into_a_uiimage [2012/02/22 14:15]
daniel
tutorials:rendering_objects_into_a_uiimage [2013/03/05 10:19] (current)
Line 1: Line 1:
 +====== How to render objects into an image ======
  
 +For %appstore_link?​447308117(Kabaam)%,​ Holger needed to render Sparrow objects into a JPG file.
 +
 +In order to accomplish that the whole display tree has to be rendered to an exportable image. That's why he extended the SPRenderTexture to allow rendering it to an UIImage. ​
 +
 +<code objc>
 +@interface SPRenderTexture (RenderToImage)
 +  - (UIImage*)renderToImage;​
 +@end
 +</​code>​
 +
 +And here is the magical part. In short, it makes use of the bundleDrawCalls method on the SPRenderTexture to get to the current GL context. It then allocates memory for the resulting image and reads the pixels from the GL context into the allocated array. After that we can feed that array to a CGDataProvider,​ a CGImageRef and then to an UIImage. All that’s left to do is tidy up some memory, which is unfortuantely very C-ish in this case: We have to register a releaseRawImageDataBufferCallback with the CGDataProvider in order to release the allocated array when everything is over. Check it out:
 +
 +<code objc>
 +@implementation SPRenderTexture (RenderToImage)
 +
 +void releaseRawImageDataBufferCallback(void *info, const void *data, size_t size)
 +{
 +  free((void*)data);​
 +}
 +
 +- (UIImage*)renderToImage
 +{
 +  __block UIImage *image = nil;
 +
 +  [self bundleDrawCalls:​^() ​
 +  {
 +    float scale = [SPStage contentScaleFactor];​
 +    int width = scale * self.width;
 +    int height = scale * self.height;​
 +    int nrOfColorComponents = 4; //RGBA
 +    int bitsPerColorComponent = 8;
 +    int rawImageDataLength = width * height * nrOfColorComponents;​
 +    GLenum pixelDataFormat = GL_RGBA;
 +    GLenum pixelDataType = GL_UNSIGNED_BYTE;​
 +    BOOL interpolateAndSmoothPixels = NO;
 +    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;​
 +    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;​
 +
 +    CGDataProviderRef dataProviderRef;​
 +    CGColorSpaceRef colorSpaceRef;​
 +    CGImageRef imageRef;
 +
 +    @try 
 +    {
 +      GLubyte *rawImageDataBuffer = (GLubyte *) malloc(rawImageDataLength);​
 +
 +      glReadPixels(0,​ 0, width, height, pixelDataFormat,​ pixelDataType,​ rawImageDataBuffer);​
 +
 +      dataProviderRef = CGDataProviderCreateWithData(NULL,​ rawImageDataBuffer,​ rawImageDataLength,​ releaseRawImageDataBufferCallback);​
 +      colorSpaceRef = CGColorSpaceCreateDeviceRGB();​
 +      imageRef = CGImageCreate(width,​ height, bitsPerColorComponent,​ bitsPerColorComponent * nrOfColorComponents,​ width * nrOfColorComponents,​ colorSpaceRef,​ bitmapInfo, dataProviderRef,​ NULL, interpolateAndSmoothPixels,​ renderingIntent);​
 +      image = [UIImage imageWithCGImage:​imageRef scale:scale orientation:​UIImageOrientationUp];​
 +    }
 +    @finally ​
 +    {
 +      CGDataProviderRelease(dataProviderRef);​
 +      CGColorSpaceRelease(colorSpaceRef);​
 +      CGImageRelease(imageRef);​
 +    }
 +  }];
 +
 +  return image;
 +}
 +
 +@end
 +</​code>​
 +
 +With this extension, you can render any object into a UIImage -- you just have to render it into a normal ''​SPRenderTexture''​ and then call the "​renderToImage"​ method on the render texture.
  tutorials/rendering_objects_into_a_uiimage.txt · Last modified: 2013/03/05 10:19 (external edit)
 
Powered by DokuWiki