views:

992

answers:

3

I am able to create a UIImage from a Core Animation layer using the following code:

- (UIImage*)contentsImage;
{
   UIGraphicsBeginImageContext([self bounds].size);
   [self renderInContext:UIGraphicsGetCurrentContext()];
   UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return image;
}

This code is in my CALayer derived class. The issue I am running into is that I have two CAShapeLayers that are child layers of my layer that do not get rendered to the resulting image. If I add standard CALayers as children they get rendered fine. The Apple docs say:

Renders the receiver and its sublayers into the specified context.

It also says that it's been available since iPhone OS 2.0. Wondering if there is something I'm missing or if I should file a radar.

Any ideas what might keep the child CAShapeLayers from getting drawn to the image?

Thanks.

A: 

Don't know if its relevant to you but there is a note in the CALayer documentation for renderInContext that says :

**Important**: The Mac OS X v10.5 implementation of this method does not
support the entire Core Animation composition model. QCCompositionLayer, 
CAOpenGLLayer, and QTMovieLayer layers are not rendered. Additionally,
layers that use 3D transforms are not rendered, nor are layers that specify 
backgroundFilters, filters, compositingFilter, or a mask values. 
Future versions of Mac OS X may add support for rendering these layers
and properties.

Anyways, I ran into a similar problem when using the UIView drawRect function in conjunction with drawing in an image context. The overall UIView that contained subviews would not draw its subviews if I called drawRect (which makes sense now actually since it says in the documentation if you call drawRect you are responsible for filling that entire area regardless of super and subview implementations). I solved my problem by just called drawRect on all my subviews, passing them their own frames.

So I would suggest maybe switching away from renderInContext and use CALayer's drawInContext instead? You'll need to override the method since it doesn't do anything by default. Your subclasses will also need to move the contexts to their appropriate frames. Also to be safe you might want to check that none of the code you add affects normal rendering of these layers.

kiyoshi
It's strange because I'm not using any of the fields specified in that notice. The issue is I want to render the layers as an image and then re-use the image as just adding the layer to the layer tree creates a noticeable degradation in performance compared to using an image. I'm using it in a table cell so I need to make it more efficient, but I want to draw the image on the fly as having a graphic artist create a new image every time we need a new skin isn't desirable. I suppose there are other non-CA ways to do that. Thanks for the feedback.
Matt Long
A: 

I filed a radar on this. I can't see any reason in the docs that it shouldn't work.I will respond back here if/when Apple replies to the radar.

Matt Long
I've found that nothing actually renders besides the shape itself. I think that's the way it's designed, but the documentation is just weak. On a side note, you might find this interesting: http://tumbljack.com/post/179975074/complex-interpolation-with-cashapelayer-free
Joe Ricioppo
+2  A: 

The CALayer machinery calls renderInContext to create its bitmapped contents property. But in a CAShapeLayer, the path property is not actually rendered to its contents as seen by this note in the header:

The shape as a whole is composited between the layer's contents and its first sublayer.

It stands to reason that renderInContext won't actually render the CAShapeLayer path onto your context. I haven't actually tried this out for myself however.

Cheers

Glen Low, Pixelglow Software

http://instaviz.com

Glen Low
Interesting. Wonder what Apple will come back with on the radar I filed--if this is intended behavior. I'm not sure what it even means that its composited between the contents and the first sublayer. How? I guess that would explain it though. Doesn't seem that its even part of the contents if I'm reading that right.
Matt Long