외규장각 도서 환수 모금 캠페인
BLOG main image
분류 전체보기 (45)
컴퓨팅환경 (18)
프로그래밍 (18)
놀이 (2)
잡담 (7)
«   2010/03   »
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
10,203 Visitors up to today!
Today 4 hit, Yesterday 28 hit
daisy rss
meet me at me2DAY
나눔글꼴 내려받기
tistory
2009/01/20 19:23

아주 가끔 문자열의 Bezier Path를 얻어오고 싶을 때가 있다.

여기저기 참고해서 한번 만들어 보았다.

#import <Cocoa/Cocoa.h>


@interface LayoutManager : NSLayoutManager
{
    NSBezierPath *bezierPath;
}

+ (NSBezierPath *)bezierPathWithAttributedString:(NSAttributedString *)string inRect:(NSRect)rect;

@end


@implementation LayoutManager

- (id)init
{
    self = [super init];
    if (self)
    {
        bezierPath = [[NSBezierPath bezierPath] retain];
    }
    return self;
}

- (void)dealloc
{
    [bezierPath release];
    [super dealloc];
}

- (NSBezierPath *)bezierPath
{
    return [[bezierPath retain] autorelease];
}

- (void)showPackedGlyphs:(char *)glyphs length:(NSUInteger)glyphLen glyphRange:(NSRange)glyphRange atPoint:(NSPoint)point font:(NSFont *)font color:(NSColor *)color printingAdjustment:(NSSize)printingAdjustment
{
    /*
     * 이 메소드는 LayoutManager가 글자를 그리기 위해 호출한다.
     * 여기에서 그냥 Bezier Path에다 바로 그린다.
     */
    [bezierPath moveToPoint:point];
    [bezierPath appendBezierPathWithPackedGlyphs:glyphs];
}

+ (NSBezierPath *)bezierPathWithAttributedString:(NSAttributedString *)string inRect:(NSRect)rect
{
    NSTextContainer         *textContainer;
    NSTextStorage           *textStorage;
    LayoutManager           *layoutManager;
    NSImage                 *tmpImage;
    NSBezierPath            *theBezierPath;
    NSAffineTransform       *transform;
    NSAffineTransformStruct  tfStruct;
    NSRect                   usedRect;

    /*
     * Bezier Path를 그리기 위해 LayoutManager를 구성한다.
     * 이 때, NSTextContainer는 인자로 받은 rect의 size를 사용한다.
     */
    textContainer = [[NSTextContainer alloc] initWithContainerSize:rect.size];
    textStorage   = [[NSTextStorage alloc] initWithAttributedString:string];
    layoutManager = [[LayoutManager alloc] init];

    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];

    /*
     * 화면용 폰트의 힌트를 사용하지 않게 한다.
     */
    [layoutManager setUsesScreenFonts:NO];

    /*
     * LayoutManager가 글자를 그릴 공간을 만든다.
     */
    tmpImage = [[NSImage alloc] initWithSize:NSMakeSize(10.0, 10.0)];

    /*
     * LayoutManager의 좌표계는 뒤집혀 있으므로 이미지의 좌표계를 뒤집어 준다.
     */
    [tmpImage setFlipped:YES];

    /*
     * 이미지에 글자를 그린다.
     * 실제로는 Bezier Path에 그려지므로 이 이미지에는 아무것도 그려지지 않는다.
     */
    [tmpImage lockFocus];
    [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer] atPoint:NSZeroPoint];
    [tmpImage unlockFocus];

    /*
     * 그려진 Bezier Path를 얻어온다.
     */
    theBezierPath = [layoutManager bezierPath];

    /*
     * 좌표계에서 그려진 범위를 가져온다.
     */
    usedRect = [layoutManager usedRectForTextContainer:textContainer];

    /*
     * Bezier Path에 적용할 AffineTransform을 만든다.
     * 다음의 transform을 수행하게 된다.
     *  1. 뒤집힌 좌표계를 다시 뒤집어 복구 (flip)
     *  2. 인자로 받은 rect안으로 translate (이 때, X축은 기준점, Y축은 중앙으로 정렬)
     */
    transform = [NSAffineTransform transform];
    tfStruct.m11 = 1.0;
    tfStruct.m12 = 0.0;
    tfStruct.tX  = NSMinX(rect);
    tfStruct.m21 = 0.0;
    tfStruct.m22 = -1.0;
    tfStruct.tY  = (NSHeight(rect) + NSHeight(usedRect)) / 2.0 + NSMinY(rect);
    [transform setTransformStruct:tfStruct];

    /*
     * Bezier Path에 생성한 AffineTransform을 적용한다.
     */
    [theBezierPath transformUsingAffineTransform:transform];

    /*
     * 생성한 객체들을 소멸시킨다.
     */
    [tmpImage release];
    [textStorage release];
    [textContainer release];
    [layoutManager release];

    /*
     * Bezier Path를 리턴한다.
     */
    return theBezierPath;
}

@end

만약, 인자로 넘긴 rect안에서 X축 정렬이나 Y축 정렬을 바꾸고 싶으면 AffineTransformStruct의 멤버값을 적당히 바꿔주면 되겠다. 나머지는 주석으로 충분히 설명되었으리라 믿고 추가 설명은 생략... 흐흐..

 

이 글은 스프링노트에서 작성되었습니다.