ひとつ前の記事
Xcodeプログラミング入門 - 3/20 01:10
ひとつ先の記事
ココア図書館 #02 - 縁取り付きの文字列を描画する その2 - 3/25 01:16
3月22日(月)
ココア図書館 #01 - 縁取り付きの文字列を描画する
CV:斎藤千和で人里離れた山の奥にある小さなサイト。そこにはゆかり姫ラブな管理人と、女医ハック狂いの管理人と、Cocoa の勉強を始めた管理人がいるのです(←なんか失敗っぽい)。
というわけで、Cocoa による HackENT の開発を通して、もしかしたら誰かの役に立つかもしれなかったり、再利用できそうなものをまとめていく『ココア図書館』です。
第一回目の今回はカラオケには必須な縁取り文字の書き方です。
ちょっと気を引くために、こんなネタを選んでみました。
こんな感じに縁取りされた文字を書くのは結構難儀なんですよ。
-(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