Desire for wealth

Last-Modified: Tuesday, 27-Jun-2023 21:06:34 JST / PV : 23679522 / Owner : Nihondo

だめちゅんにっき

ひとつ前の記事

Xcodeプログラミング入門 - 3/20 01:10

ひとつ先の記事

ココア図書館 #02 - 縁取り付きの文字列を描画する その2 - 3/25 01:16

3月22日(月)

ココア図書館 #01 - 縁取り付きの文字列を描画する

ココア図書館CV:斎藤千和で人里離れた山の奥にある小さなサイト。そこにはゆかり姫ラブな管理人と、女医ハック狂いの管理人と、Cocoa の勉強を始めた管理人がいるのです(←なんか失敗っぽい)。

というわけで、Cocoa による HackENT の開発を通して、もしかしたら誰かの役に立つかもしれなかったり、再利用できそうなものをまとめていく『ココア図書館』です。

第一回目の今回はカラオケには必須な縁取り文字の書き方です。

ちょっと気を引くために、こんなネタを選んでみました。

縁取り文字の例1 縁取り文字の例2
こんな感じに縁取りされた文字を書くのは結構難儀なんですよ。

#01 - 縁取り付きの文字列を描画する
-(void) writeBorderString: (NSString *) string
                  AtPoint: (NSPoint) point
            withAttribute: (NSMutableDictionary *) fontAttribute
       andBorderAttribute: (NSMutableDictionary *) fontBorderAttribute
              borderWidth: (float) width
/*
    string:描画する文字列
    point:描画開始位置
    fontAttribute:塗りつぶしの属性(NSFontAttributeName、NSForegroundColorAttributeNameのみ)
    fontBorderAttribute:縁取りの属性(NSForegroundColorAttributeNameのみ)
    width:縁取りの幅
*/
{
    NSBezierPath *path = [[NSBezierPath bezierPath] autorelease];
    NSTextStorage *textStorage = [[[NSTextStorage alloc] initWithString:string
                                                             attributes:fontAttribute] autorelease];
    NSLayoutManager *layoutManager = [[[NSLayoutManager alloc] init] autorelease];
    NSTextContainer *textContainer = [[[NSTextContainer alloc] init] autorelease];
    NSRange range;
    float x = point.x;
    float y = point.y;
    unsigned glyphLength;
    
    /* NSLayoutManager(グリフのレイアウトおよび描画、生成)の準備 */
    [layoutManager addTextContainer:textContainer];
    /* NSTextStorage(文字列を保持している)に、レイアウトを適用する */
    [textStorage addLayoutManager:layoutManager];
    /* NSTextContainer(テキストの描画範囲) */
    range = [layoutManager glyphRangeForTextContainer:textContainer];
    
    /* グリフ番号の配列を作成 */
    NSGlyph glyph[range.length];
    glyphLength = [layoutManager getGlyphs:glyph range:range];
    
    /* 縁取りの描画 */
    /* ベジェパスの開始位置を設定 */
    /*(descender:g,j,p,q,yなどベースラインより下に伸びている部分を補正する) */
    [path moveToPoint:NSMakePoint(x,y-[[fontAttribute objectForKey:NSFontAttributeName] descender])];
    /* 縁取りの太さを設定 */
    [path setLineWidth:borderWidth];
    /* 縁取りの角の丸め */
    [path setLineJoinStyle:NSRoundLineJoinStyle];
    /* 縁取りの色を設定 */
    [[fontBorderAttribute objectForKey:NSForegroundColorAttributeName] set];
    /* 得たグリフ番号の配列からベジェパスを作成 */
    [path appendBezierPathWithGlyphs:glyph count:glyphLength
                                          inFont:[fontAttribute objectForKey:NSFontAttributeName]];
    /* ベジェパスを描画 */
    [path stroke];
    
    /* 中身の塗りつぶし */
    /* ベジェパスの開始位置を再度設定(ペン位置を戻す) */
    [path moveToPoint:NSMakePoint(x,y-[[fontAttribute objectForKey:NSFontAttributeName] descender])];
    /* 塗りつぶしの色を設定 */
    [[fontAttribute objectForKey:NSForegroundColorAttributeName] set];
    /* ベジェパス内を塗りつぶし */
    [path fill];
}

キャッチーなネタを選んだら内容が重たくなってしまいました。NSTextStorage に属性付き文字列を格納して、NSLayoutManager でその文字列をグリフ(文字の輪郭とでも言ったらいいのでしょうかね)に変換してレイアウトして、NSTextContainer で描画範囲を確定します。

グリフ番号の配列をもとにしてグリフを得るのですが、最初 NSTextStorage のフォント属性と、描画したいグリフのフォント属性を間違えて設定していたために随分苦労しちゃった。フォントが違えばグリフ番号が違うのも当たり前みたいですね。

さて、この関数ですけど、こんな感じで使います。
    [theImage lockFocus];

    /* フォント種類とサイズを指定 */
    [fontAttribute setObject:[NSFont fontWithName:@"Osaka" size:fontSize] forKey:NSFontAttributeName];
    /* フォントの塗りつぶし色を指定 */
    [fontAttribute setObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName];

    /* フォントの縁取り色を指定 */
    [fontBorderAttribute setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];

    [self writeBorderString:string AtPoint:NSMakePoint(0,0)
              withAttribute:fontAttribute andBorderAttribute:fontBorderAttribute borderWidth:10.0];

    [theImage unlockFocus];

フォント属性を中身と縁とで分けて設定します。なんかこの辺の使い方は設計ミスった気もするなぁ。

そんなわけでいつまで続くかはめちゃめちゃ不安ですが、とりあえず『ココア図書館』スタートさせます。

今後は、今回みたいなまとまったものじゃなくて、うちの覚え書きみたいなものになっていくと思っていますが、共有できるものはどんどん共有していきたいものですね。とりあえず次回も文字描画がらみかなぁ?

2004/3/22 01:14

このエントリーをはてなブックマークに追加

最近の記事

サンスイのBluetoothラジカセで超A&Gを聴いて昭和感を出す - 11/28 18:03

ゆかりはゆかり かわりはいないの - 9/28 00:30

超時空要塞マクロス 初のオケコン「超時空管弦楽」で涙腺決壊 - 9/18 00:30

東富士演習場で聴く「戦車道行進曲!パンツァーフォー!」は格別 - 8/29 02:28

GPD PocketにOS Xの画面を表示してみたけど年齢的にRetina化が必須 - 8/20 23:51

Nintendo Switchおでかけセットを模索(GPD Pocket/Winでも) - 8/13 19:18

エロマンガ先生 BD 2巻特典CDの耳かき音声が期待以上のものだった - 8/ 7 01:08

iPhoneの非純正リモートプレイアプリでドラクエXIする - 7/30 11:42

「道-MEN 北海道を喰いにきた乙女」はみよしのファンとゆかりんファンは読むべき - 7/23 23:54

スプラトゥーン2の付録めあてでコロコロコミックを30数年ぶりに買った話 - 7/15 23:00

さらに以前の記事へ