How do you stroke the _outside_ of an NSAttributedString?

后端 未结 1 385
渐次进展
渐次进展 2020-12-13 11:23

I\'ve been using NSStrokeWidthAttributeName on NSAttributedString objects to put an outline around text as it\'s drawn. The problem is that the str

1条回答
  •  感情败类
    2020-12-13 11:48

    While there may be other ways, one way to accomplish this is to first draw the string with only a stroke, then draw the string with only a fill, directly overtop of what was previously drawn. (Adobe InDesign actually has this built-in, where it will appear to only apply the stroke to the outside of letter, which helps with readability).

    This is just an example view that shows how to accomplish this (inspired by http://developer.apple.com/library/mac/#qa/qa2008/qa1531.html):

    First set up the attributes:

    @implementation MDInDesignTextView
    
    static NSMutableDictionary *regularAttributes = nil;
    static NSMutableDictionary *indesignBackgroundAttributes = nil;
    static NSMutableDictionary *indesignForegroundAttributes = nil;
    
    - (void)drawRect:(NSRect)frame {
        NSString *string = @"Got stroke?";
        if (regularAttributes == nil) {
            regularAttributes = [[NSMutableDictionary
        dictionaryWithObjectsAndKeys:
            [NSFont systemFontOfSize:64.0],NSFontAttributeName,
            [NSColor whiteColor],NSForegroundColorAttributeName,
            [NSNumber numberWithFloat:-5.0],NSStrokeWidthAttributeName,
            [NSColor blackColor],NSStrokeColorAttributeName, nil] retain];
        }
    
        if (indesignBackgroundAttributes == nil) {
            indesignBackgroundAttributes = [[NSMutableDictionary
            dictionaryWithObjectsAndKeys:
            [NSFont systemFontOfSize:64.0],NSFontAttributeName,
            [NSNumber numberWithFloat:-5.0],NSStrokeWidthAttributeName,
            [NSColor blackColor],NSStrokeColorAttributeName, nil] retain];
        }
    
        if (indesignForegroundAttributes == nil) {
            indesignForegroundAttributes = [[NSMutableDictionary
            dictionaryWithObjectsAndKeys:
            [NSFont systemFontOfSize:64.0],NSFontAttributeName,
            [NSColor whiteColor],NSForegroundColorAttributeName, nil] retain];
        }
    
        [[NSColor grayColor] set];
        [NSBezierPath fillRect:frame];
    
        // draw top string
        [string drawAtPoint:
            NSMakePoint(frame.origin.x + 200.0, frame.origin.y + 200.0)
            withAttributes:regularAttributes];
    
        // draw bottom string in two passes
        [string drawAtPoint:
            NSMakePoint(frame.origin.x + 200.0, frame.origin.y + 140.0)
            withAttributes:indesignBackgroundAttributes];
        [string drawAtPoint:
            NSMakePoint(frame.origin.x + 200.0, frame.origin.y + 140.0)
            withAttributes:indesignForegroundAttributes];
    }
    
    @end
    

    This produces the following output:

    alt text

    alt text

    Now, it's not perfect, since the glyphs will sometimes fall on fractional boundaries, but, it certainly looks better than the default.

    If performance is an issue, you could always look into dropping down to a slightly lower level, such as CoreGraphics or CoreText.

    0 讨论(0)
提交回复
热议问题