Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding shadow to layer causes degraded retina appearance

I've got a problem with CALayer shadows. Here's how I'm making my view:

UIImage *screenshot = [SomeClass getScreenshot:mainView.view]; //full screen snap
CGFloat scale = [SomeClass getScreenScale]; // 1 or 2 for retina
CGFloat width = mainView.view.frame.size.width;
CGRect r1 = CGRectMake(0, 0, width*scale, 300*scale);     
CGRect u1 = CGRectMake(0, 0, width, 300);
CGImageRef ref1 = CGImageCreateWithImageInRect([screenshot CGImage], r1);
l1 = [[UIButton alloc] initWithFrame:u1];
UIImage *img1 = [UIImage imageWithCGImage:ref1];
[l1 setBackgroundImage:img1 forState:UIControlStateNormal];
[l1 setAdjustsImageWhenHighlighted:NO];
CGImageRelease(ref1);
[mainView.view addSubview:l1];

Okay, so that works just fine. The image added is retina resolution. However, as soon as I add a shadow to the layer it jumps to standard resolution, making the button appear fuzzy.

l1.layer.shadowOffset = CGSizeMake(0, 0);
l1.layer.shadowRadius = 20;
l1.layer.shadowColor = [UIColor blackColor].CGColor;
l1.layer.shadowOpacity = 0.8f;
l1.layer.shouldRasterize = YES;

Is there any reason why adding a shadow would cause this problem?

like image 783
sudo rm -rf Avatar asked Jun 04 '11 08:06

sudo rm -rf


1 Answers

I cannot really tell, why it happens, but I assume it is caused by the UIImage creation. You created a large(retina size 600 * 600 pixels) CGImageRef and from that the UIImage. But the UIImage is not aware, that it is a retina image (it now has 600 * 600 points, it should have 300 * 300 points with scale factor 2 which again will result in 600 * 600 pixels).

Please try to create your UIImage using imageWithCGImage:scale:orientation:. This will make the UIImage aware of retina-scale and the layer operations may work out ok.

So your line would be:

UIImage *img1 = [UIImage imageWithCGImage:ref1 
    scale: scale 
    orientation: UIImageOrientationUp];

Edit (see my comment below): The issue is caused by l1.layer.shouldRasterize = YES. You need to specify l1.layer.rasterizationScale = scale as well and the image renders as expected.

like image 111
marcus Avatar answered Nov 11 '22 08:11

marcus