I Have bad performance on using shadow effect - iphone

I put some image views on scroll view.
And when I drag this scroll view, I didn't have any problems.
But after I applied shadow effect to these image views, dragging this scroll view has bad performance.
I used shadowOpacity, shadowRadius and shadowOffset methods.
ex:
[ [ anImageView layer ] shadowOpacity: 1.0 ];
If using shadow effect causes bad performance seriously, I will draw shadow of the images directly.
If there are some tips about this issues, please let me know them.
I want to use shadow effect on iOS programically, because I have the worst drawing skill.
Thank you for your reading.

See CALayer.shouldRasterize (iOS 3.2+, but so is shadowOffset/etc):
When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content. Shadow effects and any filters in the filters property are rasterized and included in the bitmap.
You probably also want to set rasterizationScale appropriately.

While using the reasterized layer indeed increases the performance you will get better (nicer) results using the shadowpath proerty as #wayne-hartman suggests.
Check http://nachbaur.com/blog/fun-shadow-effects-using-custom-calayer-shadowpaths on how to use the CALayer shadow path.

Whenever you work with shadows its better to use a bezier path as the background. This will help you set the shadowPath, which will drastically improve performance. Rasterize will improve performance, but setShadowPath will improve 5x more than just setting rasterize.
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 100, 100) cornerRadius:10];
[self.layer setShadowColor:[UIColor blackColor].CGColor];
[self.layer setShadowOpacity:1.0f];
[self.layer setShadowRadius:10.0f];
[self.layer setShadowPath:[path CGPath]];

I've had exactly the same problem. Drawing the shadow is a fairly costly multi-pass operation, so I can kind of understand it and I think the shadow is drawn continuously as you scroll. The only work-around I've found is to render the shadow manually into an image and display that image behind the images in the scroll. This seems to work well.

Related

colorWithPatternImage and colorWithPatternImage.CGColor Flip

I have an pattern image(red texture with shadow on bottom).
When I use this code
view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"myPattern.png"]];
it's OK, and shadow is in bottom. But when I use
view.layer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"subscribe-pattern.png"]].CGColor;
it's a trouble. Image becomes fliped (shadow is on top). Can you tell me, how I can fix this problem? I need to have unflipped image using second method.
As bobnoble mentions in his comment, Core Graphics and iOS have flipped origins. iOS starts at the top left corner of the screen, and Core Graphics starts at the bottom left.
By accessing the layer property of a view you're dropping down to the Core Graphics level. If you must drop down to that level, you have to start working upside-down. An easy fix is to pre-flip your pattern. Just save it from your graphics editor upside-down. If you need to use the same image at both the UI and CG levels, you can always save two versions.
In code you can flip and translate the CG layer before drawing the upside-down image, then return the layer to its previous state for further drawing. It's kind of complex, but well covered by many Core Graphics tutorials.

Quartz shadows not drawing correctly

So, I've got this image for my app that looks like this:
Now this is nice and all, but I'm trying to reduce my dependency on images and instead try to draw this dynamically.
Okay, so I found this image built into UIColor: (scrollViewTexturedBackgroundColor)
Looks kinda light, but sweet. We're getting there.
So now, I override drawRect in a UIView subclass to darken that a bit.
-(void)drawRect:(CGRect)rect {
[[UIColor colorWithWhite:0.0 alpha:0.4] setFill];
UIRectFillUsingBlendMode(rect , kCGBlendModeDarken);
}
Hey, it's not perfect but it's close enough. I can always tweak the blending mode & color later. Now comes the hard part. I can't figure out how to get the shadows to draw correctly. For example, I tried to set my shadow like this:
CGContextSetShadowWithColor(ctx, CGSizeMake(0, 6), 5, [[UIColor blackColor]CGColor]);
However, the shadow doesn't display. Also, I tried saving the graphics state, applying the shadow, then restoring it, but when I did that the shadow appeared but with the color in reverse (probably due to the blending mode I set). Obviously that's not what I'd hoped.
Any ideas?
The shadow is rendered with something that is drawn. You cannot draw just a shadow without actual object which drops it. If you find a way to do it, please let me know.
I see on the first picture you use inner shadow effect. To have a similar result you need to draw a path that drops a shadow around the area.
On the picture the red path is a bezier path with stroke of 10px. I have left a thing gap between the picture and the path to show that the path is bigger than the background picture.
To generate such a path you can use a bezier path with rect. Inset the the background picture rect by negative value that equals a half of the stroke width.
If the actual context is bigger then the picture, clip it with the picture rect before drawing the path.

Does Quartz for iPhone draw non visible portions of a view?

I am wondering which is the best way, in terms of speed and efficiency, to draw a frame around an image on iPhone, especially when I have to draw lots of these images:
1) Drawing the image and then the frame around
or
2) Drawing a rect, filling it with a color and then drawing the image within that rect leaving some offset pixel to mimic the frame
Does Quartz draw everything that it is told to or is it smart enough to draw only what is really visible?
My feeling is that the first approach is better because there is actually less drawing done. Is it really so?
Thanks
P.
Quartz drawing will only take place within the bounds of the view, if you are doing custom drawing in -drawRect:.
That said, I think that you will see the best performance if you simply create UIImageViews for each image, then use the borderWidth, borderColor, and possibly cornerRadius properties on your view's layer to set a border. For example:
imageView.layer.cornerRadius = 10.0f;
imageView.layer.borderWidth = 3.0f;
imageView.layer.borderColor = [[UIColor blackColor] CGColor];
will place a 3-pixel-wide black border around your view, and give it a 10 pixel radius at the corners.
If performance is a problem, you should try to minimize the number of operations you perform on the graphics context, especially the ones that have no visible components.
In your particular case, I think you need to test both options on an iPhone (ist gen if possible) and benchmark them. Maybe it's easier to just fill the whole rectangle rather than calculate which pixels are part of the frame and which aren't?
It depends on the graphics chip.

The antialias of rotated CGImage/CGlayer seems jaggy, UIImageView's is not

I need to mask a "texture" image with a rotated greyscale image.
I found out, that I have to do it with CGImages or CGlayers (if there is a simplier way using UIImageViews only, please let me know about it).
My problem is simple:
The antialias of any
rotation-transformed CG stuff is quiet
jaggy...
... but the antialias of a rotation-transformed UIImageView is kinda perfect. How can I produce that beautiful antialiased rotations?
I've uploaded a "proof" involving actual iPhone Simulator screenshots, to see what am I talkin' about: http://gotoandplay.freeblog.hu/files/Proof.png
I've tried to use CGImages, CGLayers, UIImageViews "captured" with renderInContext, I've tried to CGContextSetInterpolationQuality to high, and also tried to set CGContextSetAllowsAntialiasing - CGContextSetShouldAntialias, but every case returned the same jaggy result.
I'm planning to learn using OpenGL next year, but this development should released using CoreGraphics only. Please let me know how to get a perfectly rendered rotated image, I just can't accept it's impossible.
To add 1px transparent border to your image use this
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContext( imageRect.size );
[image drawInRect:CGRectMake(1,1,image.size.width-2,image.size.height-2)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Have you tried adding a clear, 1 pixel border around your image? I've heard of that recommended as a trick to avoid aliasing, by giving CoreGraphics some room to work with when blending the edges.
I am having a similar problem, looks like I'm going to move it over to OpenGL ES as well. I can't nail down an effective solution that doesn't hurt performance.
For reference of future CoreGraphics explorers, putting a 1-pixel transparent border did make for a noticeable improvement in my experiments, but it appears that as Eonil mentioned, you end up with multiple stages of antialiasing/smoothing/interpolation working against each other. IE: CGLayer does some interpolation for it's rotation, then context it's being drawn to will do some interpolation/antialiasing, so on so forth until it ends up looking pretty rough.
I actually ended up with better results by disabling interpolation and antialiasing on the destination context, though it was still obviously jaggy (less artifacts overall though). I was able to achieve the best overall appearance by enabling interpolation and antialiasing when constructing the CGLayer, and disabling it for the destination context when re-drawing it. This approach, obviously, is fraught with other problems.

iPhone Animation: how to anti-alias?

I was looking at some animations in my iPhone app and felt like it was kind of ugly. And then I undertsood it: it just doesn't animate through subpixel states.
So, in case I use usual +beginAnimations/+commitAnimations, moving some stuff just a few pixels look "jumpy". How can I avoid it? Are there any flags to make it animate through float coords or whatever?
Just to give you an idea of what I have and what I'm looking for, please refer to the picture:
alt text http://www.ptoing.net/subpixel_aa.gif
Thanks in advance,
Anton
That's funny, but I found that UIImageView animate its content using aniti-aliasing, while edges of the view are not anti-aliased (hard). It seems to be because UIView itself should maintain the same bounds, while subpixel rendering might add to the bound a bit.
So, I ended up just putting an image with some transparent space around the picture, and it all went smooth.
Just don't let UIView cut its contents for you :)
You can try deriving the item you're animating from a custom UIView that overrides its drawRect method and sets anti-aliasing on for it then lets the parent draw into it. Something along the lines of:
- (void) drawRect:(CGRect)area
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetShouldAntialias(context, true);
CGContextSetAllowsAntialiasing(context, true);
[super drawRect:area];
// We have to turn it back off since it's not saved in graphic state.
CGContextSetAllowsAntialiasing(context, false);
CGContextRestoreGState(context);
}
On the other hand, it might be too late in the rendering pipeline by the time you get here, so you may have to end up rolling your own animation scheme that lets you have full control over pixel-positioning.
Per Jeeva's comment above, you can make UIView edges render with Anti-aliasing by settings the following option in the info.plist to YES.
Renders with edge antialiasing
Here is the link Jeeva pointed to:
http://www.techpaa.com/2012/06/avoiding-view-edge-antialiasing.html