chrism
chrism

Reputation: 561

Drawing 1 pixel wide paths in iOS

I am drawing a path in my drawRect implementation on a UIView with:

CGContextSetLineWidth(context, 0.5);
CGContextStrokePath(context);

With anti-aliasing on on my CGContext, I can't seem to draw 1 px lines.

on

I tried turning antialiasing off with:

CGContextSetShouldAntialias(context, NO);

but then my corners look terrible:

off

How do I keep antialiasing on but stop this sub-pixel bluring of 1 pixel lines?

Upvotes: 13

Views: 7771

Answers (4)

Raphael
Raphael

Reputation: 3886

The only solution that worked for me was this:

override func drawRect(rect: CGRect) {

    let context = UIGraphicsGetCurrentContext()

    CGContextSetLineWidth(context, 0.5)

    CGContextMoveToPoint(context, 0.0, 0.25)
    CGContextAddLineToPoint(context, rect.size.width, 0.25)

    CGContextSetStrokeColorWithColor(context, UIColor.blackColor().CGColor)
    CGContextStrokePath(context)
}

Upvotes: 0

Sound Blaster
Sound Blaster

Reputation: 4919

You can translate all context via:

CGContextSaveGState(context);
CGFloat translation = 0.5f / [[UIScreen mainScreen] scale];
CGContextTranslateCTM(context, translation, translation);
... your drawing here ...
CGContextRestoreGState(context);

That's all!

Upvotes: 0

Chengjiong
Chengjiong

Reputation: 1292

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];

    CGFloat inset = 0.5 / [[UIScreen mainScreen] scale];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    // draw
    CGContextSetLineWidth(context, inset);
    CGContextSetStrokeColorWithColor(context, _lineColor.CGColor);
    CGContextMoveToPoint(context, inset, 0);
    CGContextAddLineToPoint(context, inset, CGRectGetHeight(rect));
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
}

Upvotes: 10

Codo
Codo

Reputation: 78825

When you draw a line in iOS, you specify the coordinates of a infinitely narrow line. The drawn line will then extend to both side of that line by half the stroke width.

If your infinitely narrow line has integer coordinates and is horizontal or vertical, the drawn line will be two pixels wide and gray instead of one pixel wide and black (with anti-aliasing). Without anti-aliasing, the line will be slightly moved but the corners look ugly.

To solve it, use coordinates in the middle of a pixel (e.g. 200.5 / 170.5) and turn anti-aliasing on.

Upvotes: 24

Related Questions