Skip navigation.
 
mlRe: turning off anti-aliasing
FROM : Scott Thompson
DATE : Wed Jul 05 15:21:10 2006

On Jul 5, 2006, at 1:21 AM, Rob Ross wrote:

>  am drawing some simple path shapes (circles, squares, sine wave, 
> etc), and I wanted to draw a cartesian coordinate grid behind them. 
> But my grid lines were coming out "fuzzy". I was stroking them as 1-
> unit wide, but as I resized the Window containing the view, they 
> would "smear" and every other pixel growth of the window, 
> vertically or horizontally, I would see the grid lines change from 
> one to two pixels in width. After doing some research I thought the 
> problem was due to antialiasing. (Another mystery to me is why, 
> although the scale factor is 1,1, when I change the size of my 
> window by a single pixel, the new window size as reported by bounds 
> has increased by .5 of a pixel.)


This is probably the case.  In my book I call it the half-pixel line 
problem.

When Quartz sets up a context on a bitmap (like the screen) it aligns 
user space so that the whole number coordinate values correspond to 
the lower, left edges of pixels.  If you draw a one point wide line, 
then, it actually overlaps over two pixels (half a pixel on either 
side of the boundary).  One way to "fix" this is to offset your 
coordinate system by 0.5, 0.5 before drawing.  While this technique 
works today, it may not work as well when we have scaleable UI and 
high density monitors.  You'll have to decide whether or not it's a 
valid tradeoff for your application.

How are you drawing your grid lines?

> I tried turning off antialiasing before drawing the grid via 
> [nsGraphicsContextInstance setShouldAntialias:NO] but that didn't 
> seem to do anything at all. What is this purpose of this method?


It should disable antialiasing as part of the current graphics state.

I wrote the following drawRect into a custom view:

- (void)drawRect:(NSRect)rect {
   NSRect leftRect, rightRect;

   NSDivideRect([self bounds], &leftRect, &rightRect, [self 
bounds].size.width / 2.0, NSMinXEdge);
   [[NSColor redColor] set];

   leftRect = NSInsetRect(leftRect, 5, 5);
   rightRect = NSInsetRect(rightRect, 5, 5);
   
   [[NSGraphicsContext currentContext] saveGraphicsState];
   [[NSGraphicsContext currentContext] setShouldAntialias: NO];

   NSBezierPath *oval1Path = [NSBezierPath bezierPathWithOvalInRect: 
leftRect];
   [oval1Path stroke];

   [[NSGraphicsContext currentContext] restoreGraphicsState];

   NSBezierPath *oval2Path = [NSBezierPath bezierPathWithOvalInRect: 
rightRect];
   [oval2Path stroke];
}

And it does what I expect, the left oval is not antialiased, the 
right one is. I can't imagine why it doesn't work for you.  You might 
need to be very careful about your saves and restores.

> But I found a method in Quartz 2D (or Core Graphics? - not sure 
> what the proper term is ) that seems to do the trick, so before 
> drawing my grid lines I call this method:


Quartz 2D refers to the 2D, PDF-derived drawing library that is a 
part of Core Graphics.  Core Graphics, in turn, describes the entire 
Mac OS X graphics system that is shared by applications.  In addition 
to Quartz 2D, Core Graphics contains the window compositor, routines 
for managing the display(s), routines for interacting with the window 
server (sending mocked-up events and the like) and similar tools.

If you want to be very specific about just the drawing library you 
can use the term "Quartz 2D", however, in casual conversation, when 
the context is understood, the term "Core Graphics" is often 
substituted.

:-)

> - (void)setAntialiasing:(BOOL)flag
> {
>     NSGraphicsContext *nsctx = [NSGraphicsContext currentContext];
>     CGContextRef      context = (CGContextRef)[nsctx graphicsPort];    
>     
>     [nsctx setShouldAntialias:flag];
>     CGContextSetAllowsAntialiasing(context,flag);
> }
>
> with YES, and after I draw the grids I call it with NO.


This is a very "heavy handed" mechanism for achieving the same effect 
you should be getting from setShouldAntialias. 
CGContextSetAllowsAntialiasing turns of the context's ability to 
antialias (irrespective of the graphics state).  In other words, if 
you call CGContextSetAllowsAntialiasing then you won't get 
antialiasing (or font smoothing) in that context until you turn it 
back on.

> My question is, is there a pure Cocoa way of doing this without 
> using the CGContextSetAllowsAntialiasing method? Or is this the way 
> I should be doing it? And why doesn't "setShouldAntialias:NO" by 
> itself work?


So far as I know, it should. :-(

Scott

Related mailsAuthorDate
mlturning off anti-aliasing Rob Ross Jul 5, 08:21
mlRe: turning off anti-aliasing Scott Thompson Jul 5, 15:21
mlRe: turning off anti-aliasing Rob Ross Jul 6, 04:36