georgemp
georgemp

Reputation: 788

NSBezierPath with rounded rect does not have smooth corners

I'd like to create a rounded rect similar to the one around the labels (while editing) in AddressBook. I am trying to use a bezierPath with a rounded rect and then stroking it to do this. But, the end result doesn't have very smooth edges.

Address Book label

AddressBook label

Address Book label zoomed in pixie

AddressBook label zoomed in pixie

My label

My label

My label zoomed in pixie

My label zoomed in pixie

It looks like the curves in the addressbook version are more aggressively mixed towards the background white color. In Pixie, the pixel I have my cursor on has a sRGB value of (0.98, 0.98, 0.98), wheras in my version it is (0.86, 0.86, 0.86) resulting in a bit of jagged edge. My code to draw the rect is

override func drawWithFrame(cellFrame: NSRect, inView controlView: NSView) {
    if let context = NSGraphicsContext.currentContext() {
        context.saveGraphicsState()
        let borderColor = NSColor.init(SRGBRed: 0.75, green: 0.75, blue: 0.75, alpha: 1)
        let outline = NSBezierPath.init(roundedRect: cellFrame, xRadius: 4, yRadius: 4)
        outline.lineWidth = 4
        borderColor.setStroke()
        outline.stroke()

        drawInteriorWithFrame(cellFrame, inView: controlView)
        context.restoreGraphicsState()
    }
}

I have tried playing around with different compositing types, line widths and xy radiuses for the round rect - without much success. I would appreciate some guidance on this. Thanks

Upvotes: 0

Views: 879

Answers (1)

georgemp
georgemp

Reputation: 788

I believe this article here explains the issue. When we stroke a rect, Coregraphics draws the outline along the middle of the edge of the rectangle we provide. If the rect is 1 pixel wide, then half the stroke line will lie outside the rectangle, while the other half will lie on the inside. As we can't draw half a pixel, Coregraphics mixes the two colors (on the inside and outside) to draw the line. So, to draw a single pixel line, we need to modify the outline rect

CGRect rectFor1PxStroke(CGRect rect) 
{
    return CGRectMake(rect.origin.x + 0.5, rect.origin.y + 0.5, rect.size.width - 1, rect.size.height - 1);
}  

A couple of other options are also provided in the referenced article. But, with my initial testing, the above solution seems to work fine - along with setting the linewidth = 1 and x-y radiuses of the curve to 2

Upvotes: 2

Related Questions