2011-06-03 16 views
5

¿Cómo se dibuja una forma borrosa en Cocoa? Piense en una sombra con un blurRadius que acompaña a un camino lleno, pero sin una forma de camino en primer plano de bordes afilados.Cómo dibujar una forma borrosa?

Lo que probé es utilizar una ruta rellena con una sombra y establecer el color de relleno en transparente (alfa 0.0). Pero eso hace que la sombra sea invisible también, ya que aparentemente toma en cuenta el alfa de "objetos" de proyección de sombras.

Respuesta

5

Esto es realmente bastante complicado. Luché con esto durante un tiempo hasta que me ocurrió con esta categoría en NSShadow:

@implementation NSShadow (Extras) 

//draw a shadow using a bezier path but do not draw the bezier path 
- (void)drawUsingBezierPath:(NSBezierPath*) path alpha:(CGFloat) alpha 
{ 
    [NSGraphicsContext saveGraphicsState]; 
    //get the bounds of the path 
    NSRect bounds = [path bounds]; 

    //create a rectangle that outsets the size of the path bounds by the blur radius amount 
    CGFloat blurRadius = [self shadowBlurRadius]; 
    NSRect shadowBounds = NSInsetRect(bounds, -blurRadius, -blurRadius); 

    //create an image to hold the shadow 
    NSImage* shadowImage = [[NSImage alloc] initWithSize:shadowBounds.size]; 

    //make a copy of the shadow and set its offset so that when the path is drawn, the shadow is drawn in the middle of the image 
    NSShadow* aShadow = [self copy]; 
    [aShadow setShadowOffset:NSMakeSize(0, -NSHeight(shadowBounds))]; 

    //lock focus on the image 
    [shadowImage lockFocus]; 

    //we want to draw the path directly above the shadow image and offset the shadow so it is drawn in the image rect 
    //to do this we must translate the drawing into the correct location 
    NSAffineTransform* transform=[NSAffineTransform transform]; 
    //first get it to the zero point 
    [transform translateXBy:-shadowBounds.origin.x yBy:-shadowBounds.origin.y]; 

    //now translate it by the height of the image so that it draws outside the image bounds 
    [transform translateXBy:0.0 yBy:NSHeight(shadowBounds)]; 
    NSBezierPath* translatedPath = [transform transformBezierPath:path]; 

    //apply the shadow 
    [aShadow set]; 

    //fill the path with an arbitrary black color 
    [[NSColor blackColor] set]; 
    [translatedPath fill]; 
    [aShadow release]; 
    [shadowImage unlockFocus]; 

    //draw the image at the correct location relative to the original path 
    NSPoint imageOrigin = bounds.origin; 
    imageOrigin.x = (imageOrigin.x - blurRadius) + [self shadowOffset].width; 
    imageOrigin.y = (imageOrigin.y - blurRadius) - [self shadowOffset].height; 

    [shadowImage drawAtPoint:imageOrigin fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:alpha]; 
    [shadowImage release]; 
    [NSGraphicsContext restoreGraphicsState]; 
} 

@end 
2

me encontré con una aplicación que hace exactamente lo que quería decir en línea. Escrito por Sean Patrick O'Brien. Es una categoría de NSBezierPath, así:

@interface NSBezierPath (MCAdditions) 

- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius; 

@end 

@implementation NSBezierPath (MCAdditions) 

- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius 
{ 
    NSRect bounds = NSInsetRect(self.bounds, -radius, -radius); 
    NSShadow *shadow = [[NSShadow alloc] init]; 
    shadow.shadowOffset = NSMakeSize(0, bounds.size.height); 
    shadow.shadowBlurRadius = radius; 
    shadow.shadowColor = color; 
    NSBezierPath *path = [self copy]; 
    NSAffineTransform *transform = [NSAffineTransform transform]; 
    if ([[NSGraphicsContext currentContext] isFlipped]) 
     [transform translateXBy:0 yBy:bounds.size.height]; 
    else 
     [transform translateXBy:0 yBy:-bounds.size.height]; 
    [path transformUsingAffineTransform:transform]; 

    [NSGraphicsContext saveGraphicsState]; 

    [shadow set]; 
    [[NSColor blackColor] set]; 
    NSRectClip(bounds); 
    [path fill]; 

    [NSGraphicsContext restoreGraphicsState]; 

    [path release]; 
    [shadow release]; 
} 

@end 

Este código se puede descargar desde este blog post. No lo encontré por separado como código en cualquier lugar en línea.

Cuestiones relacionadas