SUN OS上でのJasperReportsによるPDF作成についてのすったもんだw

ここ数日、別の部隊のヘルプをしておりました。
ヘルプの内容は、Javaによる、PDF帳票作成。
その作業内容については、ネットに残しておいたほうがいいような気配がしますので、
業務内容に触れない範囲でつらつらと書き綴っておこうと思います。

■長いけど前振りw
JavaでPDFフォーマットの帳票を作成したい。できればフリーで」
という要望があり、以前にいくつかのJavaオープンソースのツールやライブラリを調査していました。

調査対象は以下の4つ。
全て、日本語フォントを使えるという条件下で探したものです。
 Jakarta FOP
 iText
 iReport
 Eclipse BIRT

# これら以外にもあるんですが、調査対象を広げると雪達磨式に仕事が増えるので、ココまで。(^^;)

Jakarta FOPDoblogでもお世話になっている
Apache/TomcatというようなJakartaのプロジェクトの一つ。
XSL-FOというXML形式の印刷用フォーマットに従ってレイアウトを作成し、
PDF形式のファイルにコンバートするというツールとライブラリです。

iTextJavaのコード上でがりがりとレイアウトを作成していくタイプのライブラリです。

iReportGUIでPDFのレイアウトを作成しながらPDFなどのフォーマットを作ることができるツールです。
中ではJasperReportsというフリーの帳票作成ライブラリを利用しています。
JasperReportsはPDF作成時にはiTextも利用していますので、iTextとは仲良しさんです。
ちなみに、GUIインターフェースとか、操作感覚はVisualStudio5以上でくっついてくる、
CrystalReportに似ているかな。

Eclipse BIRTEclipseのBIプロジェクトの一つで、Eclipse上で動く帳票作成フレームワークです。
結構でたばっかりなので、日本語の情報が不足気味。(^^;)
しかし、デモ用の動画とかヘルプなどは結構充実していると思うので、
英語を読む気力さえあれば、何とか使いこなせるでしょう。
ちなみに、日本語フォントを使うにはFOPの日本語フォント利用の知識が必要です。

PDFツールの要望者さん達には、
「一部バグはあるものの、操作感覚を重視するのであればiReport
 操作感覚がイマイチつかみにくいがとりあえず使いそうな機能にはバグがない方がよいのであればBIRT
という形で、ご紹介をしました。

結局、要望者さん達はiReportを選択したようです。

■事の発端
「SUN(Solaris)でPDFを作成すると、文字が一部しか表示されないんです」
そう連絡を受けたのは、結構差し迫った時期になってからであった。(^^;)

なるほど、受け取ったPDFの出力結果を見ると、Windowsでの出力例とSolarisとではかなり違います。
(見てくれの違いは右の画像見てね)

PDFファイルの内部も含め調べると、以下の違いがあることが明らかになりました。
・文字列が表示されていない部分はフォントが表示されていないのではなく、
 文字情報自体が欠落しており、PDFファイルの内部に存在すらしていない。

・1行の幅がSolaris版のほうが広め

勿論、作成元になったiReportからの出力ファイルに各OSごとで差があるわけではありません。
JasperReportsが作り出すPDF作成前の中間ファイル(jasperファイル)も同じもので試してみましたが、
同様の結果がでます。

そもそも、グラフィック関係はWindowsUNIX系(X11)とでは、大層な違いがありますゆえ、
多少の違いがでるのは致し方ないところ。
しかし、文字が欠落してしまうほどの大差が出てしまうのはちょいとね。(^^;)

そんなわけで、PDF作成時にOS間の違いが出てくるものなのだとあたりをつけ、
調査を開始しました。

■対処方法
やってみたこととその結果一覧
 1) JDKのもつ font.properties アタリで何とかできないか?
  → ムリ そもそも iText が見ている日本語フォントは iTextAsian.jar にあるもので、
  プロパティファイルは無視しているっぽい
 2) iText の Phrase もしくは Paragraph クラスで何とかするか?
  → ムリ カバー範囲が多すぎ
 3) JasperReports の PDF 出力クラスの JRPdfExporter で文字列を出力しているところは?
  → OK!これでいけそう
というわけで、3)を選択しました。

具体的には、
 JRPdfExporter クラスの exportText メソッドで文字列を配置していっている
というのがわかったので、そこで1行当たりの幅を決めている部分を探せばよいということになりました。

結果としては、こんな感じ。
<変更前>
colText.setLeading(0,
       text.getLineSpacingFactor());

<変更後>
colText.setLeading(-text.getFont().getSize()/9f,
       text.getLineSpacingFactor());


えーっと…変更した箇所の式はまったくのあてずっぽうですので、
コイツで完璧というわけではありませぬ。(^^;)
いわば、野生のカンとか、目分量とか言うやつです。
ただ、ヒントにはなるかも知んないので、このまま載せておきます。(爆)

■環境
 OS:Sun ONE Web Server6.1
 JDK:1.4.2_09
 iReport:0.5.1
 JasperReports:1.0.1 (最新版ではないのは、iReportに合わせました)
 iText:1.3.1 (最新版ではないのは、iReportに合わせました)

■愚痴w
上記の当たり、JavaDocには何にも書いてないし、
ソースを見てもコメントも書いてないの。
ええ、もう、そういうのはよくあることなんだけど…。orz

せめてさぁ、leading っていう言葉が何の leading なんかハッキリしてくれよう!(涙)
って、何度も机をばんばんさせていたCAMUSだったのでした。→[leadingの意味]
というのも、なんだか、同じような機能のメソッドとか色々あるんですが、
X軸中心(横)の位置のleadingなんかY軸中心(縦)の位置のleadingなんかがさっぱりわからなくって、
やってみて初めて何が起こるかがわかる状況下での調査でした…。

ああ、ちかれた。

あ、そうそう。そふてくちゃんvにもTB。→[TBセンター&リンク集:言語:Java]

【'05/09/15 追記】
じいやさまから、当記事のコメントにてleadingについてご教示いただきました。
活版印刷で行間を空けるときに活字の間に詰め込む鉛(lead)から来た用語で、アクセント記号などのための内部leadingとテキスト行間の外部leadingがあります。外部leadingを普通、leadingと呼んでいるように思います。
なるほど!謎がかなり解けました。
じいやさま、ありがとうございます。

ちょびっと解説すると、JasperReportsでは文字列をこんな形で描画整形しているようです。
 1) Phraseという文字列の箱を作成
 2) Chunkという文字列(単行)の塊を作成
 3) ChunkをPhraseに加える(ココでは、Chunkは横に並んでいるはず)
 4) 文字列全てをカバーできるまで、2)と3)を順に繰り返す
 5) ColumnTextでPhrase内のChunkを縦に並ぶよう整形
 6) ColumnTextでPhrase内の文字列間隔を整形

上記でleadingを設定できるチャンスは、1)・5)・6) の3回でした。
1)で設定したものは、Chunk同士の間の設定と思われX軸方向のみに文字列がずれました
5)は無視されました。6)があったからと思いますが。(^^;)
6)でようやく、Y軸方向…要は縦方向の幅の変更が見られました。

…イメージとしてはそんな感じかも…。
実際は、直接iText側のコード見てみないとわかりませんが…。(今はその気力が…)