■ことのはじめ
Core Graphics の機能だけで日本語の文字列を描画する方法については、既に先人の方々が調べて記事にまとめてくださっていたので、そちらを見ていただければ大丈夫です。
http://iphone-dev.g.hatena.ne.jp/ktakayama/20100129
http://d.hatena.ne.jp/r_kurain/20100316
基本的にはこちらで紹介されている方法に従って進めていけば困ることはありません。ただし、描画した文字が上下反対になることがありますので、
CGContextSetTextMatrix
を使う箇所を調整したりする必要があるかも。で、最大の問題になるのがこれらの記事で紹介されている
CGFontGetGlyphsForUnichars
と呼ばれる関数です。この関数を使えば楽に日本語文字列を文字化けすることなく描画することができるのですが、あろうことかこの関数はプライベートAPIであり、使うとリジェクトされてしまうらしいです。ということで別の作戦をとらなければなりません。上記の記事にいろいろな対処方法が載っているのですが、私は一番単純に
http://www.mexircus.com/codes/GlyphDrawing.mm
というライブラリを自分のアプリに組み込む方法を試してみることにしました。この方法を使えば、
CGFontGetGlyphsForUnichars
でまず作って動くようにしてから、 CMFontGetGlyphsForUnichars
と書き換えるだけでそのまま動作するので楽です。問題はこのライブラリ、mmファイルしか用意されていないのでそのままではうまく使えません。適当にヘッダファイルを用意してやる必要があります。
■と言うわけで書いたもの
と言うわけで
GlyphDrawing.h
を書いてみました。http://gist.github.com/466297
ライセンスは元の
GlyphDrawing.mm
に準じますが、 GlyphDrawing.mm
のライセンスが不明なので、不安ならばまず作者さん (http://mexircus.com/blog/) に一言聞いてみるのがいいと思います。■使い方
- http://gist.github.com/466297 と http://www.mexircus.com/codes/GlyphDrawing.mm をダウンロードします。
GlyphDrawing.mm
のインポートを以下のように書き換えます://#import <Foundation/Foundation.h>
#import "GlyphDrawing.h"GlyphDrawing.h
とGlyphDrawing.mm
をプロジェクトに追加してビルドします。CGFontGetGlyphsForUnichars
の代わりにCMFontGetGlyphsForUnichars
を呼びだせばOKです。
■実際に使ったコードの例
NSString *message = @"本日は快晴なり";
// フォントを設定
// ついでにmessageのサイズも取得
// ただしsizeWithFontは UIGraphics の機能なので、本当に Core Graphics だけで描画したいならここで使ってはいけません
UIFont *font = [UIFont fontWithName:@"HiraKakuProN-W6" size:32.0];
CGRect messageRect = [message sizeWithFont:font];
CGFontRef fontRef = CGFontCreateWithFontName((CFStringRef)font.fontName);
CGContextSetFont(c, fontRef);
CGContextSetFontSize(c, font.pointSize);
// Glyphを作成
size_t length = [message length];
CGGlyph glyphs[length];
UniChar chars[length];
[message getCharacters:chars range:NSMakeRange(0, length)];
CMFontGetGlyphsForUnichars(fontRef, chars, glyphs, length);
// 文字列が上下反対になるのを防止する
CGAffineTransform transform = CGAffineTransformMakeScale(1.0, -1.0);
CGContextSetTextMatrix(c, transform);
CGContextTranslateCTM(c, 0, messageRect.size.height/2);
// 描画
CGFloat x = 100.0f;
CGFloat y = 100.0f;
CGContextShowGlyphsAtPoint(c, x, y, glyphs, length);