10

Background

I am using Erica Saduns Cookbook example from Chapter 8, Example 14 — Resize and Rotate to obviously resize and rotate a UIImageView.

VIew hierarchy

1.) striped background view.

2.) the interactive view which can be resize and rotate.

3.) an overlay image with a transparent portion. this view starts its y axis at 128 and is 768x768.

4.) above and below 3, are 2 views 128 in height.

******See Photo example below****

Issue

Currently, I can save the entire view's layer to the photo library using [[[self view] layer] renderInContext:, and #2's transformations are correct. However, I need a way to save a 768x768 (lime green in photo example) frame that only includes #2 and #3, including #2's transformations. If I use [[#2 layer] renderInContext:, I get the original image, and no transformations. (see screenshot below for # reference.

Code

CGSize deviceSpec;
if ( IDIOM == IPAD ) { deviceSpec =CGSizeMake(768,768); } else { deviceSpec =CGSizeMake(320,480); }
if (  scale > 1.5  ) {
    UIGraphicsBeginImageContextWithOptions(deviceSpec, NO, scale);
} else {
    UIGraphicsBeginImageContext( deviceSpec );
}        

    CGContextRef ctx = UIGraphicsGetCurrentContext();      

    [[stripedBg layer] renderInContext:ctx];  //#1    

        CGContextSaveGState(ctx);

            CGContextConcatCTM(ctx, [[interactiveImage layer] affineTransform]);

            //CGContextTranslateCTM(ctx, interactiveImage.frame.origin.x,interactiveImage.frame.origin.y-128);

            [[interactiveImage layer] renderInContext:ctx]; // #2

        CGContextRestoreGState(ctx);

    [[overlayImage layer] renderInContext:ctx]; // #3

    UIImage * draft = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

Photo Example

I only need the portion of the image that is outlined in LIME GREEN, while preserving the transformations by the user.

enter image description here

WrightsCS
  • 50,551
  • 22
  • 134
  • 186

1 Answers1

18

If I understand you correctly, the issue is that you want to render just layer #2, but layer #2 has transforms that aren't preserved when rendering just that layer? You can apply those transforms to the graphics context's CTM (current transformation matrix) before you render the layer into that context. Something like this should work:

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextConcatCTM(ctx, [layer2 affineTransform]);
[layer2 renderInContext:ctx];
CGContextRestoreGState(ctx);

Note, the calls to CGContextSaveGState() and CGContextRestoreGState() are only necessary if you want to draw more stuff into the context after you draw the layer. You can omit them if the layer is all you want.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • I need to be able to include #2 and #3 only, which are 2 different `UIImageView`'s. – WrightsCS Sep 07 '11 at 22:02
  • @WrightsCS: Is #3 not a subview of #2? If not, you could just render #3 into the context after you've rendered #2. You'll have to apply your own affine transform to set the origin of the context as expected for each layer though. – Lily Ballard Sep 07 '11 at 22:04
  • each layer is a subview of the main view, none are subviews of the others. – WrightsCS Sep 07 '11 at 22:10
  • 1
    @WrightsCS: You can use the CTM again. Just use `CGContextTranslateCTM(view.frame.origin.x, view.frame.origin.y)` to adjust the CTM before drawing the view (in the case of layer 2, apply its `affineTransform` to the CTM after doing the translation). You can then draw layer #2, followed by layer #3 (each with their own translation). Note that you will want to save and restore the GState around the translations/rendering. – Lily Ballard Sep 07 '11 at 22:14
  • So how will I calculate the **x** and **y** of #2 if it transformed, cause those should change with each rotation / resize, am I understanding that correctly? – WrightsCS Sep 07 '11 at 22:17
  • @WrightsCS: The frame of a view is expressed in its parent's coordinate system. They are un-transformed, so to speak. So if you translate the CTM by the view's origin, and then concat the view's own transform on afterwards, drawing should be correct. Of course, in your case, you probably want to subtract 128 from the Y coordinate of both your views, because I assume your context is sized to fit just the green portion. You can accomplish this just by doing a translation of -128 on the Y axis before you start processing your views. – Lily Ballard Sep 07 '11 at 22:19
  • @KevinBallard can you please have a look at this question, a poor soul needs some help: http://stackoverflow.com/ – Abduliam Rehmanius Jul 27 '13 at 23:31
  • You saved my day! I had to make UIImage from UIView that is scaled using CGAffineTransformMakeScale. Adding CGContextConcatCTM(ctx, [layer2 affineTransform]); does the trick :) – Josip B. Nov 29 '13 at 14:34
  • Doesn't maintain all of the layers transform like m34 (perspective) – jjxtra May 17 '14 at 18:58