2011年4月9日土曜日

FPDFのCellを利用した均等割付の方法

FPDFで均等割付をしたかったのですが、色々調べてもFPDFでの均等割付の指定方法が見つからなかったので、仕方なく自分で作ってみました。
最初空白を文字と文字の間に挟むことで、均等割付をしているように見せかけようしたのですが、それだとどうしても文字と文字の間隔がいびつになってしまいました。
そこで、文字をそれぞれ1つのCellに入れて、Cellの幅を調整するようにしたところ、わりとキレイに割付をすることができました。
以下でその方法を簡単に説明します。
※基本的に等幅フォントの利用を前提にしています。
  1. 割付する幅を取得する。
    均等割付をするということは、「揃えたい文字列の幅」があるはずなので、まずはそれを設定します。
    幅を取得するにはFPDFには、GetStringWidth()という関数を利用します。
    GetStringWidth()は引数に文字列を渡すと、PDF出力時の文字列の幅をミリ単位で返してくれます。
    この関数に揃えたい文字列の中で一番文字数が多い文字列を指定します(「ああああああ」など適当な文字列でもいいでしょう)。
    $total_length = $pdf -> GetStringWidth("あああああああああ");
    
  2. 1文字分の長さを取得する。
    同じくGetStringWidth()を利用して1文字分の長さを取得します。
    $char_length = $pdf -> GetStringWidth("あ");
    
  3. 1文字ずつ、セルに設定していく。
    最後の一文字は幅が余って見えないように文字の長さぴったりにします。その他の文字は文字数と割付する幅にあわせてセルの幅を算出し、一文字ずつセルに設定していきます。
    //最後の文字以外の文字幅を算出する(最後の文字幅は1文字分ピッタリにするため、算出不要)
      $char_num   = mb_strlen($str) - 1;
      $cell_length = ($total_length - $char_length) / $char_num;
      
      // 1文字づつセルに入れていく
      for ($i = 0; $i < $char_num; $i++) {
        $pdf->Cell($cell_length, $height, mb_substr($str, $i, 1), 0, 0);
      }
      $pdf->Cell($char_length, $height, mb_substr($str, $char_num, 1), 0, 0);
    
完成版のソースはこちら
/**
 * セル幅を利用した文字数幅での均等割付を行う
 *
 * @param  object $pdf     帳票オブジェクト
 * @param  int    $height  高さ
 * @param  string $str     割付する文字列
 * @param  string $str_len 最大文字幅での文字列
 * @return object          
 */

function equal_cell_space($pdf, $height, $str, $str_len) {

  // 最大文字幅と1文字分の文字幅を取得する
  list($total_width, $char_width) = cell_width($pdf, $str_len);

  if ("{$str}" == ""
      or mb_strlen($str) == 1) {
    $pdf->Cell($total_width, $height, $str, 0, 0);
    return $pdf;
  }
  
  //最後の文字以外の文字幅を算出する(最後の文字幅は1文字分ピッタリにするため、算出不要)
  $char_num   = mb_strlen($str) - 1;
  $cell_width = ($total_width - $char_width) / $char_num;
  
  // 1文字づつセルに入れていく
  for ($i = 0; $i < $char_num; $i++) {
    $pdf->Cell($cell_width, $height, mb_substr($str, $i, 1), 0, 0);
  }
  $pdf->Cell($char_width, $height, mb_substr($str, $char_num, 1), 0, 0);
  
  return $pdf;
}
/**
 * 指定した文字列の文字幅と1文字分の文字幅を算出する
 *
 * @param  object $pdf     FPDFオブジェクト
 * @param  string $str_len 
 * @return array           array(文字列の文字幅,1文字分の文字幅)
 */

function cell_width($pdf, $str_len) {

  $total_length = $pdf->GetStringWidth($str_len);
  $char_length  = $pdf->GetStringWidth(mb_substr($str_len, 0, 1));
  
  //-- 長さを適当に丸める
 // 長さが整数でない場合、小数点以下で切り上げる(ちょっと長めにするため)
  $total_length = (((int)$total_length) < $total_length) ? (int)($total_length + 1) : (int)$total_length;
 // 1文字分の長さは四捨五入にする。
  $_char_length = round($char_length, 1);
 // 四捨五入によって、元々の文字の長さより算出結果が短くならないようにする。
  $char_length  = ($char_length > $_char_length) ? ($_char_length + 0.1 ) : $_char_length;
  
  return array($total_length, $char_length);
}

※追伸 >- この投稿が役にたったと思った方は、上か下の広告をクリックしていただけるとうれいいです。

1 件のコメント:

  1. 始めまして。
    ありがとうございます。記事参考にさせて頂きました。

    私の場合はFPDI/TCPDFを使用していたのですが、全角文字列を出力し
    ていて最大文字幅が1文字変わると既存印刷物のある部分の長さに
    合わせられなかったため、$total_widthはmmで直指定するように変更し、
    1文字幅は出力文字列から1文字取ってcell_widthを使用しない方向で
    調整し、あとはマルチバイトの場合mb系の関数の引数にUTF-8などを
    指定してやると考えていた通りの出力にできました。

    TCPDFのMultiCellの両端揃え'J'が全然効かないのでかなり困りましたが、
    本記事で思った通りの出力が得られるようになりました。
    どうもありがとうございましたm(_ _)m

    広告もクリックさせて頂きました!w(・∀・)/

    返信削除