iPhone SDK: Rendering a CGLayer into an image object - iphone

I am trying to add a curved border around an image downloaded and to be displayed in a UITableViewCell.
In the large view (ie one image on the screen) I have the following:
productImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:product.image]];
[productImageView setAlpha:0.4];
productImageView.frame = CGRectMake(10.0, 30.0, 128.0, 128.0);
CALayer *roundedlayer = [productImageView layer];
[roundedlayer setMasksToBounds:YES];
[roundedlayer setCornerRadius:7.0];
[roundedlayer setBorderWidth:2.0];
[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
[self addSubview:productImageView];
In the table view cell, to get it to scroll fast, an image needs to be drawn in the drawRect method of a UIView which is then added to a custom cell.
so in drawRect
- (void)drawRect:(CGRect)rect {
...
point = CGPointMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP);
//CALayer *roundedlayer = [productImageView layer];
//[roundedlayer setMasksToBounds:YES];
//[roundedlayer setCornerRadius:7.0];
//[roundedlayer setBorderWidth:2.0];
//[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
//[productImageView drawRect:CGRectMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP, IMAGE_WIDTH, IMAGE_HEIGHT)];
//
[productImageView.image drawInRect:CGRectMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP, IMAGE_WIDTH, IMAGE_HEIGHT)];
So this works well, but if I remove the comment and try to show the rounded CA layer the scrolling goes really slow.
To fix this I suppose I would have to render this image context into a different image object, and store this in an array, then set this image as something like:
productImageView.image = (UIImage*)[imageArray objectAtIndex:indexPath.row];
My question is "How do I render this layer into an image?"
TIA.

This is what I got to work well.
- (UIImage *)roundedImage:(UIImage*)originalImage
{
CGRect bounds = CGRectMake(0.0, 0.0, originalImage.size.width, originalImage.size.height);
UIImageView *imageView = [[UIImageView alloc] initWithImage:originalImage];
CALayer *layer = imageView.layer;
imageView.frame = bounds;
[layer setMasksToBounds:YES];
[layer setCornerRadius:7.0];
[layer setBorderWidth:2.0];
[layer setBorderColor:[[UIColor darkGrayColor] CGColor]];
UIGraphicsBeginImageContext(bounds.size);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[imageView release];
return anImage;
}
Then to scale the image, I found this in the lazy loading example:
#define kAppIconHeight 48
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
self.appRecord.appIcon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

You are on the right track with your own comment.
- (UIImage *)roundedImage:(UIImage*)originalImage;
{
CGRect bounds = originalImage.bounds;
CGImageRef theImage = originalImage.CGImage;
CALayer *roundedlayer = [CALayer layer];
roundedlayer.position = CGPointMake(0.0f,0.0f);
roundedlayer.bounds = bounds;
[roundedlayer setMasksToBounds:YES];
[roundedlayer setCornerRadius:7.0];
[roundedlayer setBorderWidth:2.0];
[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
roundedlayer.contents = theImage;
UIGraphicsBeginImageContext(bounds.size); // creates a new context and pushes it on the stack
CGContextBeginTransparencyLayerWithRect(UIGraphicsGetCurrentContext(), bounds, NULL);
CGContextClearRect(UIGraphicsGetCurrentContext(), bounds);
[roundedlayer drawInContext:UIGraphicsGetCurrentContext()];
UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext(); //releases new context and removes from stack
return anImage;
}
I would pre-render these and store them in your image array so they are not calculated during your drawRect, but set in your
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method.

Related

UIView layer renderInContext not drawing to image context

I'm trying to draw a view's layer to a CGGraphicsImageContext using renderInContext, however the view layer is not displaying on the resultant UIImage.
UIGraphicsBeginImageContext(scaledImage.size);
[scaledImage drawInRect:CGRectMake(0, 0, scaledImage.size.width, scaledImage.size.height)];
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *croppedImage = [UIGraphicsGetImageFromCurrentImageContext() croppedImage:CGRectMake(0, 44, 320, scaledImage.size.height - (60 + 44))];
UIGraphicsEndImageContext();
My drawRect method for the view is as follows:
-(void)drawRect:(CGRect)rect
{
CALayer *background = [[CALayer alloc] init];
background.backgroundColor = [UIColor blackColor].CGColor;
background.opacity = 0.4;
background.frame = self.bounds;
[self.layer addSublayer:background];
CATextLayer *textLayer = [[CATextLayer alloc] init];
textLayer.string = _poseName;
textLayer.fontSize = 19;
textLayer.foregroundColor = [UIColor whiteColor].CGColor;
textLayer.alignmentMode = kCAAlignmentCenter;
textLayer.frame = self.bounds;
CGSize textSize = [_poseName sizeWithFont:[UIFont fontWithName:#"Helvetica" size:19]
constrainedToSize:textLayer.bounds.size
lineBreakMode:NSLineBreakByWordWrapping];
textLayer.position = CGPointMake(160, self.bounds.size.height - textSize.height/2);
[self.layer addSublayer:textLayer];
}
The view's layers are displaying correctly when the app is running however, the view is not rendering to the graphics context as I would expect. Thank you in advance for your help!

UIImageView round corner has white background

The rounded corner has white background.
I followed other SO answers but don't know why i'm getting this whites
Bellow is the code.
UIView* testView = [[[UIView alloc] initWithFrame: self.animationView.bounds] autorelease];
UIImageView* testImageView = [[[UIImageView alloc] initWithImage:backImage] autorelease];
[testView addSubview: testImageView];
testImageView.backgroundColor = [UIColor clearColor];
CALayer* layer = [testView layer];
bool prev = layer.masksToBounds;
layer.masksToBounds = YES;
layer.cornerRadius = 30;
testView.clipsToBounds = YES;
UIImage* image = [UIImage captureView: testView];
//this image has the white regions in the four corners.
// when seen on iphone photo album
+ (UIImage*)captureView:(UIView*)view
{
CGSize size = view.bounds.size;
CGContextRef context = CreateARGBBitmapContext(size);
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
[view.layer renderInContext: context];
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage: imageRef];
CGImageRelease(imageRef);
CGContextRelease(context);
return img;
}
Add [testImageView setClipsToBounds:YES].
It might be that you have to set testImageView.opaque = NO.

rounded corner in UIImageView

I have the following code:
[avatar.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[avatar.layer setBorderWidth:2.0];
[avatar.layer setShadowOffset:CGSizeMake(-1.0, -1.0)];
[avatar.layer setCornerRadius:8];
It does give me a rounded white border surrounding the UIImage, however there is that extra tip around the 4 corners.. is there a way to cut it off?
setMasksToBounds is probably what you are looking for.
[avatar.layer setMasksToBounds:YES];
-(UIImage *)makeRoundedImage:(UIImage *) image
radius: (float) radius;
{
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = CGRectMake(0, 0, image.size.width, image.size.height);
imageLayer.contents = (id) image.CGImage;
imageLayer.masksToBounds = YES;
imageLayer.cornerRadius = radius;
UIGraphicsBeginImageContext(image.size);
[imageLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return roundedImage;
}

CALayer - backgroundColor flipped?

I'm creating a CALayer like this:
UIColor *color = [UIColor colorWithPatternImage:[UIImage imageNamed:#"MyPattern.png"]];
backgroundLayer = [[CALayer alloc] init];
[backgroundLayer setBackgroundColor:[color CGColor]];
[[self layer] addSublayer:backgroundLayer];
For some reason, the pattern is drawn upside down. I've already tried setting geometryFlipped and applying sublayer transforms, but it doesn't work.
Using [backgroundLayer setTransform:CATransform3DMakeScale(1.0, -1.0, 1.0)]; actually does work.
I would rather use this method:
CALayer *backgroundLayer = [CALayer layer];
backgroundLayer.frame = CGRectMake(50, 50, 200, 200);
UIImage *img = [UIImage imageNamed:#"MyPattern.png"];
CGImageRef imgRef = CGImageRetain(img.CGImage);
backgroundLayer.contents = (id) imgRef;
[self.layer addSublayer:backgroundLayer];
This will provide image content inside the layer and it fits automatically, so it works great for backgrounds. Im not sure why your method isnt working, sorry about that, but I thought it would be nice to provide you with this method.
Instead of using CATransform3DMakeScale you can flip image yourself:
UIImage* img = [UIImage imageNamed:#"MyPattern.png"];
img = [UIImage imageWithCGImage:img.CGImage
scale:img.scale
orientation:UIImageOrientationDownMirrored];
UIColor* color = [UIColor colorWithPatternImage:img];
…
This works fine for me.
Or you can go further and actually redraw the image.
- (UIImage*)flipImage:(UIImage*)image {
UIGraphicsBeginImageContext(image.size);
CGContextDrawImage(UIGraphicsGetCurrentContext(),CGRectMake(0.,0., image.size.width, image.size.height),image.CGImage);
UIImage* img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Details why it can be useful are in this answer.

Need help in adding a drop shadow to an image in a uiview in iOS4?

I am trying to create a drop shadow for an image. I also have an animation between views and this is the backdrop. However, when I use the following code, the image is not drawn. Anyone have any ideas?
self.frontViewBackground = [[[UIView alloc] initWithFrame:frame] autorelease];
//self.frontViewBackground.image = [UIImage imageNamed:#"whitepaper3.png"];
self.frontViewBackground.multipleTouchEnabled = YES;
[self.photoView addSubview:self.frontViewBackground];
UIImage *image = [UIImage imageNamed:#"whitepaper3.png"];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetShadow(ctx, CGSizeMake(1, -2), 3.0);
[image drawInRect:self.frontViewBackground.frame blendMode:kCGBlendModeNormal alpha:1.0];
CGContextRestoreGState(ctx);
Have you thought about using CALayer's shadow properties? For example you could do the following:
UIView *view = [[UIView alloc] initWithFrame:frame];
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowRadius = 5.0
Check out more here: http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Reference/CALayer_class/Introduction/Introduction.html#//apple_ref/occ/instp/CALayer/shadowColor