iOS: Antialiasing fail (PNG in CALayer)

2019-03-30 20:33发布

I'm attempting to draw this image on screen:

src_image

This is the code:

        CALayer* dullLayer = [CALayer layer];
        {                
            dullLayer.frame = CGRectMake(0,0,BUTTON_SIZE,BUTTON_SIZE);

            dullLayer.position = CGPointFromPoint2D( btnCenter );

            dullLayer.opacity = topQuadrant ? 1.0 : 0.5;


            [wheelLayer addSublayer: dullLayer];
        }


        UIImage* test = [UIImage imageNamed: @"OuterButton_Dull.png"];

        dullLayer.contents = (id) [test CGImage];

This is what I get:

render_fail

What gives? Why are the edges so jagged? Contrast this with the Roman numeral images that have been composited to screen in exactly the same way.

I have tried

            dullLayer.edgeAntialiasingMask = 0x0f; // binary 1111

to no avail.

EDIT: http://lists.apple.com/archives/cocoa-dev/2008/Feb/msg02070.html

3条回答
爷、活的狠高调
2楼-- · 2019-03-30 20:50

I just did a post on this: http://kellenstyler.com/?p=1360

There are a few things you can do if you add the images via code along with a few tricks that will allow you to clean it up a little more.

See if anything in the following code helps:

UIImage * img =[UIImage imageWithData:[NSData dataWithContentsOfFile:[[[NSBundle mainBundle ] resourcePath ] stringByAppendingPathComponent:@"AliasImage.png" ] ] ];
CGRect imageRect = CGRectMake( 0 , 0 , img.size.width + 4 , img.size.height + 4 );
UIGraphicsBeginImageContext( imageRect.size );
[img drawInRect:CGRectMake( imageRect.origin.x + 2 , imageRect.origin.y + 2 , imageRect.size.width - 4 , imageRect.size.height - 4 ) ];
CGContextSetInterpolationQuality( UIGraphicsGetCurrentContext() , kCGInterpolationHigh );
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[aliasImage setImage:img ];

aliasImage.transform = CGAffineTransformScale(aliasImage.transform , 0.45 , 0.45 );
aliasImage.layer.shouldRasterize = YES;
aliasImage.layer.rasterizationScale = 0.45;
aliasImage.layer.edgeAntialiasingMask = kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge;
aliasImage.clipsToBounds = NO;
aliasImage.layer.masksToBounds = NO;
查看更多
迷人小祖宗
3楼-- · 2019-03-30 20:57

If the result image that you posted is the same size as it appears on the screen then you are simply using too large an image. A PNG image is not a vector image, so scaling it down will always give some aliasing; the further you scale down the worse it gets. Antialiasing will have limited effect in such cases.

The fact that you don't see it for the numeral images is partly because it doesn't contain any fine, high contrast, lines like the other image does and partly perhaps because you are using smaller images for them.

If you have the original image as a vector image, try scaling that down to the right size before converting it to PNG. If you need a higher resolution version somewhere else in your app, consider creating multiple PNGs, each at different resolutions.

If you don't have the original image as a vector image, you should try finding a replacement. There are a couple of good sources for free clip art files on the web, such as http://www.openclipart.org/ or http://www.clker.com/.

查看更多
看我几分像从前
4楼-- · 2019-03-30 20:57

Desmond has nailed it.

It seems that anti-aliasing in Apple's frameworks only operates on neighbouring pixels. so if you reduce an image by 4x, pixel 0,0 is going to be averaged against pixel 2,0 ie pixel 1,0 is completely discarded. so if you have sharp edges, this isn't going to hack it.

The solution is to repeatedly reduce the image by 50% until it is < 2x the desired size.

Here is what happens if I progressively reduce the original 600 x 600 image, halving it each time, and displaying the result into a 256 x 256 CALayer:

progressive_reduction

The third image has actually scaled down to below the target size. Strangely, a further diminution (which automatically gets up-sized 75 -> 256 in order to be displayed) actually looks best of all.

So actually in this case the solution was to reduce it until it is actually smaller than the desired size, and then let Apple's graphical framework expand it as necessary.

查看更多
登录 后发表回答