[iOS 8] CTRubyAnnotationRef を使って文字にルビを付ける

CTRubyAnnotationRef

iOS 8 の Core Text フレームワークに CTRubyAnnotationRef という文字にルビを付けるためのクラスが登場しました。下図のように、テキストにふりがなを付けるといったようなことが実装できます。

ruby-annotation

文字にルビを付けてみよう

Core Text を使って描画する場合は、次のように記述します。

@import CoreText; 

// 読み
CFStringRef writing = (__bridge CFStringRef)@"安西先生";

// ふりがなの配列
CFStringRef furigana[kCTRubyPositionCount] = {
    (__bridge CFStringRef) @"あんざいせんせい", NULL, NULL, NULL
};
 
// ルビ
CTRubyAnnotationRef ruby = CTRubyAnnotationCreate(kCTRubyAlignmentAuto, kCTRubyOverhangAuto, 0.5, furigana);

まず furigana[kCTRubyPositionCount] でふりがなの配列を生成しています。あとは CTRubyAnnotationCreateCTRubyAnnotationRef を生成します。

描画処理を含めると次のような感じになります。上記で生成した CTRubyAnnotationRefCFAttributedStringRef に設定する CFDictionaryRef に、kCTRubyAnnotationAttributeName というキーでセットします。

- (void)drawRect:(CGRect)rect {
    
    CFStringRef writing = (__bridge CFStringRef)@"安西先生";

    CFStringRef furigana[kCTRubyPositionCount] = {
        (__bridge CFStringRef) @"あんざいせんせい", NULL, NULL, NULL
    };

    CTRubyAnnotationRef ruby = CTRubyAnnotationCreate(kCTRubyAlignmentAuto, kCTRubyOverhangAuto, 0.5, furigana);
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    
    CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
    transform = CGAffineTransformTranslate(transform, 0, - self.bounds.size.height);
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);
    CGContextTranslateCTM(ctx, 0, ([self bounds]).size.height );
    CGContextScaleCTM(ctx, 1.0, -1.0);
    
    CFAttributedStringRef writingAttributedString = [self attributedString:writing ruby:ruby];
    CTLineRef writingLine = CTLineCreateWithAttributedString(writingAttributedString);
    CGContextSetTextPosition(context, 100.0, 300.0);
    CTLineDraw(writingLine, context);
    
    CFRelease(writingLine);
}

- (CFAttributedStringRef)attributedString:(CFStringRef)string ruby:(CTRubyAnnotationRef)ruby
{
    // Font style
    CTFontRef font = CTFontCreateWithName(CFSTR("Verdana"), 28, NULL);
    
    // Font color
    CGColorRef fontColor = [UIColor redColor].CGColor;
    
    // Paragraph
    CTTextAlignment alignment = kCTRightTextAlignment;
    
    CTParagraphStyleSetting settings[] = {
        {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment}
    };
    
    CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
    
    // Create an attributed string
    CFStringRef keys[] = { kCTFontAttributeName , kCTParagraphStyleAttributeName, kCTForegroundColorAttributeName, kCTRubyAnnotationAttributeName};
    CFTypeRef values[] = { font, paragraphStyle, fontColor, ruby};
    
    CFDictionaryRef attr = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values,
                                              sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFAttributedStringRef attributes = CFAttributedStringCreate(NULL, string, attr);
    CFRelease(attr);
    
    return attributes;
}

実行すると次のように文字の上にルビ(ふりがな)が表示されます。

ruby-annotation

まとめ

地味に便利な機能ですよね。使いドコロとしては、例えば

  • 子供向けアプリに、説明文にふりがなをつける
  • 読みと書きが異なる単語を表現する(歌詞など)
  • 英語の発音をカタカナで分かりやすくする

などといったようなときに使えそうですね!