Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

disable anti-aliasing for UIBezierPath

I need to render UIBezierPaths without anti-aliasing and then save them as PNG to retain the full pixel representations (for example, not let JPEG muck the image up). I've tried calling the CG functions below just before stroking the UIBezierPaths, but it seems none have any effect on the resultant rendered image. The paths are still rendered with anti-aliasing (i.e. smoothed).

CGContextSetShouldAntialias(c, NO);
CGContextSetAllowsAntialiasing(c, NO);
CGContextSetInterpolationQuality(c, kCGInterpolationNone);

Any hits would be greatly appreciated.

like image 953
alonjr Avatar asked Mar 14 '13 18:03

alonjr


2 Answers

When I use those options, it turns off antialiasing. On the left is with the default options. On the right, with your options.

enter image description here

This is easy to control if you're using a UIView subclass. This is my drawRect:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetShouldAntialias(context, NO);

    [[UIColor redColor] setStroke];
    UIBezierPath *path = [self myPath];
    [path stroke];
}

And to capture the screen, from How to take a screenshot programmatically

- (void)captureScreen
{
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
    else
        UIGraphicsBeginImageContext(self.window.bounds.size);
    [self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData *data = UIImagePNGRepresentation(image);
    [data writeToFile:[self screenShotFilename] atomically:YES];
}

If you're using a CAShapeLayer, then I don't think you can control the antialiasing on screen, because as the documentation says:

The shape will be drawn antialiased, and whenever possible it will be mapped into screen space before being rasterized to preserve resolution independence. However, certain kinds of image processing operations, such as CoreImage filters, applied to the layer or its ancestors may force rasterization in a local coordinate space.

But, regardless of the antialiasing on screen, if you want to have your snapshot of the screen not be antialiased, you can insert your CGContextSetShouldAntialias into the captureScreen routine:

- (void)captureScreen
{
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
    else
        UIGraphicsBeginImageContext(self.window.bounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetShouldAntialias(context, NO);
    [self.window.layer renderInContext:context];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData * data = UIImagePNGRepresentation(image);
    [data writeToFile:[self screenShotFilename] atomically:YES];
}
like image 148
Rob Avatar answered Oct 07 '22 20:10

Rob


Where are you getting c from? Are you certain that c refers to the same thing as UIGraphicsGetCurrentContext() in the drawing cycle that you use [UIBezierPath stroke]? It's difficult to tell from the above sample.

If you want to be certain that you're drawing to the same context that you're configuring, fetch the CGPath from the UIBezierPath, and draw it directly:

- (void)drawRect:(CGRect)rect {
  CGContextRef context = UIGraphicGetCurrentContext();
  CGPathRef path = [self.bezier CGPath];
  CGContextSetShouldAntialias(context, NO);
  CGContextAddPath(context, path);
  CGContextStrokePath(context);
}
like image 37
Rob Napier Avatar answered Oct 07 '22 18:10

Rob Napier