How do you stroke the _outside_ of an NSAttributedString?

[亡魂溺海] 提交于 2019-12-17 22:19:35

问题


I've been using NSStrokeWidthAttributeName on NSAttributedString objects to put an outline around text as it's drawn. The problem is that the stroke is inside the fill area of the text. When the text is small (e.g. 1 pixel thick), the stroking makes the text hard to read. What I really want is a stroke on the outside. Is there any way to do that?

I've tried an NSShadow with no offset and a blur, but it's too blurry and hard to see. If there was a way to increase the size of the shadow without any blur, that would work too.


回答1:


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:

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.



来源:https://stackoverflow.com/questions/4467597/how-do-you-stroke-the-outside-of-an-nsattributedstring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!