TLFを使ってルビ振りに挑戦する


みなさん、Flashのテキストエンジンを利用する為のフレームワーク「TextLayoutFramework」使ってますか?
今回は、このTLFを使ってFlash上でルビを振る実験をしたのでご紹介します。
素材となる文字列は、ルビタグを含むHTMLの文字列です。
これをTLF用に変換して、TextFlowに流し込み、ルビを貼り付けることになります。
尚、今回の実験では細かい組版ルールは、取りあえず置いておきます(^^;)

生成するTextFlowの行間をルビ込みで設定しておく

lineHeight プロパティでルビを入れる隙間を設定しておきます。

var textLayoutFormat:TextLayoutFormat = new TextLayoutFormat();
textLayoutFormat.fontSize = FONT_SIZE;
textLayoutFormat.lineHeight = FONT_SIZE + RUBY_FONT_SIZE;

HTMLルビ文字列を、TextLayoutFormt形式に変換する
+ルビ用配列にルビ部分を入れて分離する

例)【変換前】

<ruby><rb>吾輩</rb><rp>(</rp><rt>わがはい</rt><rp>)</rp></ruby>は猫である。名前はまだ無い。<br/>
どこで生れたかとんと<ruby><rb>見当</rb><rp>(</rp><rt>けんとう</rt><rp>)</rp></ruby>がつかぬ。

例)【変換後】
*spanのidの末尾番号は、ルビ用配列のインデックスと同期

<TextFlow xmlns=”http://ns.adobe.com/textLayout/2008″>
<p>
<span id=”rubyTarget_0″>吾輩</span>
は猫である。名前はまだ無い。
<br/>
どこで生れたかとんと
<span id=”rubyTarget_1″>見当</span>
がつかぬ。
</p>
</TextFlow>

例)【分離後:ルビ用配列】
わがはい,けんとう

該当IDのspanElementの位置にルビを貼って行く

  1. 該当IDのSpanElement取得(*rubyIDはid=”rubyTarget_1″のこと)
  2. var span:SpanElement = SpanElement(textFlow.getElementByID(rubyID));

  3. 該当IDのSpanElementがテキストフロー内で何文字目か(0からスタート)
  4. var position:int = span.getAbsoluteStart();

  5. 該当IDのSpanElementが含まれる行
  6. var textFlowLine:TextFlowLine = textFlow.flowComposer.findLineAtPosition(position);

  7. 該当行の表示オブジェクトを取得
  8. var textLine:TextLine = textFlowLine.getTextLine(true);

  9. 該当IDのSpanElementの開始/終了位置のAtomが、行内で何番目かを取得
    (Atomとは、グラフィックエレメントと文字(結合された文字のグループを含む)の両方、
    テキスト行を構成する分割できないエンティティについて言及する用語)
  10. var startIndex:Number = textLine.getAtomIndexAtCharIndex(position);
    var lastIndex:Number = textLine.getAtomIndexAtCharIndex(position + span.textLength – 1);

  11. 行内での該当IDの開始/終了位置するAtomの領域を取得
  12. var startbox:Rectangle = textLine.getAtomBounds(startIndex);
    var lastbox:Rectangle = textLine.getAtomBounds(lastIndex);

  13. ルビ振り対象域を取得
  14. var rubyArea:Rectangle = new Rectangle(startbox.x, textFlowLine.getBounds().y , lastbox.x + lastbox.width – startbox.x , startbox.height);

ルビ用TextFieldを貼り付ける

上記で取得したルビ振り対象の文字列に合わせて、ルビ文字用TextFieldを貼る
(*1.2はルビ文字と対象文字のスペース調整)

var rubyText:TextField = new TextField();
rubyText.x = rubyArea.x;
rubyText.y = rubyArea.y – RUBY_FONT_SIZE * 1.2;

まとめ

試行錯誤した結果、以上の手順でFlash上のテキストにルビを振ることができました。
が、もっとすんなりルビの位置を取得できるんじゃないかと思ったり…
また、もっと組版を意識する必要もあるでしょうし、
ルビ振り対象文字列に対して、ルビ文字が物凄く長い場合の対処や、
ルビ振り対象文字列が泣き別れてた場合、ルビ振りをどうするか、
など、まだまだ実用化には問題点が山積みです。

参考

Adobeのフォーラムでルビ振りの質問があり、ここをベースに今回の実験を行いました。
How to get the coordinate of FlowLeafElement