2011-06-03 6 views
5

Comment puis-je dessiner une forme floue dans Cocoa? Pensez à une ombre avec un blurRadius accompagnant un chemin rempli, mais sans forme de contour en avant-plan. Ce que j'ai essayé est d'utiliser un chemin rempli avec une ombre et de définir la couleur de remplissage à transparent (alpha 0.0). Mais cela rend également l'ombre invisible, car elle prend apparemment en compte l'ombre qui projette l'alpha de l'objet.Comment dessiner une forme floue?

Répondre

5

Ceci est en réalité raisonnablement difficile. Je me suis battu avec pendant un certain temps jusqu'à ce que je suis venu avec cette catégorie sur 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

Je trouve une application qui fait exactement ce que je voulais dire en ligne. Écrit par Sean Patrick O'Brien. Il est une catégorie sur NSBezierPath, comme ceci:

@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 

Ce code est téléchargeable à partir de ce blog post. Je ne l'ai pas trouvé séparément comme code n'importe où en ligne.

Questions connexes