PDFlib ブロックは Adobe Acrobat と Adobe Acrobat 用の無償プラグインである PDFlib ブロックプラグインで作成することができる矩形の領域で、テキスト、イメージ、PDF ページ等を PDFlib ブロックのブロック名により配置することができます。また、PDFlib ブロックではテキストのフォントサイズや装飾等様々なオプションを指定することができます。
請求書の基になる2種類の PDF はテキストやイメージの配置位置が全く異なりますが、この PDFlib ブロックのブロック名によりテキスト等を配置することができるため、両方の請求書に対応することができます。また、新たに別のレイアウトの請求書を作る際にも、プログラムを修正することなく対応できます。
PDFlib ブロックを使用する場合の注意点として、フォントファイルの問題があります。PDFlib ブロックプラグインでは、テキストブロックに対してフォントを指定しておくことができます。しかしながら、この時に指定できるフォントはシステムにインストールされているフォントが表示されるため、PDFlib ブロックを配置したシステムと実際に PPS で PDF を作成する環境が異なる場合、指定したフォントがシステムにインストールされていない可能性があります。そのため、本デモプログラムではフォントの指定はプログラムで行い、フォントサイズの指定やフォントスタイルの指定は PDFlib ブロックで行なっています。
入力フォームの文字コードは UTF-8 とし、以下のソースコードも同じく UTF-8 で保存されるものとします。また、MS ゴシックと MS 明朝のフォントファイルがソースコードと同じ階層の resource/fonts ディレクトリにあるものとします。これらのフォントをお持ちでない場合、IPA フォントのような再配布可能なフォントファイルをご用意いただき、ソースコードを書き換えてお試しください。
PDF へフォントを埋め込むことはフォントファイルの再配布に近いため、利用規約等で PDF への埋め込みを禁止している場合があります。フォントファイルの利用条件をご確認の上、ご利用ください。
<?php
/* PDFlib ブロック配置成功判定
* PDFlib ブロックはすべてのインポート用ファイルにあるとは限らないため、
* ブロック名に該当する PDFlib ブロックがないために配置に失敗した場合には、
* エラーとせずに処理を続行した方が良い場合もあります。
* この関数では fill_xx_block() の返り値 $ret から、PDFlib ブロックへの配置の
* 正否を判定します。PDFlib ブロックへの配置が失敗 ($ret == 0) の場合でも、
* ブロック名に該当する PDFlib ブロックがなかった場合 (エラーコード 2268) は
* 処理を続行し、それ以外の場合はエラーとし、例外を送出します。
*/
function is_pdflib_block_error($pdf, $ret) {
if($ret != 0)
return $ret;
if($pdf->get_errnum() == 2268)
return $ret;
// 配置に失敗
throw new PDFlibException();
}
/* PDFlib ブロック用テキスト配置関数
* PDFlib ブロックへテキストを配置します。
* 正否の判定は is_pdflib_block_error() で行います。
*/
function fill_text_block($pdf, $pdi, $blockName, $text, $optlist) {
$ret = $pdf->fill_textblock($pdi, $blockName, $text, $optlist);
is_pdflib_block_error($pdf, $ret);
}
/* PDFlib ブロック用イメージ配置関数
* PDFlib ブロックへイメージを配置します。
* 正否の判定は is_pdflib_block_error() で行います。
*/
function fill_image_block($pdf, $pdi, $blockName, $image, $optlist) {
$ret = $pdf->fill_imageblock($pdi, $blockName, $image, $optlist);
is_pdflib_block_error($pdf, $ret);
}
/* PDFlib ブロック用テキストフロー配置関数
* PDFlib ブロックへテキストフローを配置します。
* 正否の判定は is_pdflib_block_error() で行います。
* optlist に textflowhandle を設定した場合、fill_textblock() の戻り値に
* テキストフローハンドルが返ります。このテキストフローハンドルの後処理は
* ユーザーが行う必要があるため、戻り値として呼び出し元に渡します。
*/
function fill_textflow_block($pdf, $pdi, $blockName, $text, $optlist) {
$ret = $pdf->fill_textblock($pdi, $blockName, $text, $optlist);
return is_pdflib_block_error($pdf, $ret);
}
// 請求書に記載する情報を $_POST されたデータから取得
$invoiceDate = $_POST["invoice_date"];
$orgName = $_POST["org_name"];
$stampImage = $_POST["stamp_image"];
$total2 = $_POST["total_2"];
$items = Array();
for($i = 1; $i <= 8; $i++) {
array_push(
$items,
Array(
"item" => $_POST["item_" . $i],
"count" => $_POST["count_" . $i],
"price" => $_POST["price_" . $i],
"amount" => $_POST["amount_" . $i]));
}
$total1 = $_POST["total_1"];
$memo = $_POST["memo"];
// インポート用の PDF ファイル名を指定
$importPdf = $_POST["format_pdf"] == 1 ? "invoice_1.pdf" : "invoice_2.pdf";
/* その他の変数を定義
* ライセンスキーは PDFlib ライセンス規約により、公開ディレクトリに置いては
* いけません。外部からアクセスできないディレクトリに設置してください。
* フォントファイルについても、利用規約等により配布が禁止されている場合が
* あります。使用するフォントの利用条件をご確認ください。
*/
$licensefile = "/var/pdflib/pdflib_license.txt";
$baseDir = dirname($_SERVER["SCRIPT_FILENAME"]);
$fontDir = $baseDir . "/resource/fonts";
$imageDir = $baseDir . "/images";
$templateDir = $baseDir . "/templates";
$outputPdf = "pps_demo.pdf";
try {
// PDFlib オブジェクトの生成
$pdf = new PDFlib();
/* PDFlib のパラメータの設定
* ライセンスキーを記入したライセンスファイルを licensefile で指定することで
* PDFlib を製品版としてお使いいただけるようになります。(フォーマットについ
* てはインストールディレクトリの licenses.txt をご覧ください)
*
* errorpolicy は、PDFlib の関数でエラーが起きた場合の動作を指定します。
* return では戻り値としてエラーを知らせ、exception では例外を発生させます。
* なお、デフォルトの legacy は非推奨です。
*
* SearchPath は、PDF で使用するファイルを読み込む際の、検索対象にする
* ディレクトリを指定します。
*
* stringformat は PDFlib に渡す文字列のエンコードを指定します。
*/
if(file_exists($licensefile)) {
$pdf->set_option("licensefile=$licensefile");
}
$pdf->set_option("errorpolicy=return");
$pdf->set_option("SearchPath=$fontDir");
$pdf->set_option("SearchPath=$imageDir");
$pdf->set_option("SearchPath=$templateDir");
$pdf->set_option("stringformat=utf8");
/* 文書情報の設定
* 文書のプロパティの概要に表示されるタイトルと作成者を指定します。
* その他サブタイトル、キーワード、作成日、更新日、アプリケーション等の規定
* のプロパティやカスタムプロパティを指定できます。
*/
$pdf->set_info("Title", "PDFlib Personalization Server デモプログラム (請求書作成)");
$pdf->set_info("Author", "infoTek K.K.");
/* 文書の作成
* PDF 文書の作成を開始します。begin_document() の第一引数が空文字の場合、
* PDF はメモリ上に作成され、end_document() 後に get_buffer() で取得するこ
* とができます。
*/
$pdf->begin_document("", "");
/* フォントのロード
* ページ上のテキストを出力する際に使用するフォントファイルを読み込みます。
* FontOutline でフォントファイル内のフォント名を指定し、load_font() で該当
* のフォントを使えるようにします。
* FontOutline では任意の名前をつけることもできますが、フォントが TrueType
* コレクション (.ttc) の場合は、フォント名での指定をお薦めします。
* フォントの読み込みに失敗した場合、エラーコード (PHP では 0) が返ります。
* 成功した場合はフォントハンドルが得られます。
*/
$pdf->set_option("FontOutline={MS-Gothic=msgothic.ttc}");
$msGothic = $pdf->load_font("MS-Gothic", "unicode", "embedding");
if($msGothic == 0) {
// フォントのロードに失敗
throw new PDFlibException();
}
$pdf->set_option("FontOutline={MS-Mincho=msmincho.ttc}");
$msMincho = $pdf->load_font("MS-Mincho", "unicode", "embedding");
if($msMincho == 0) {
// フォントのロードに失敗
throw new PDFlibException();
}
/* ページの作成
* ページを作成します。
* 本サンプルでは取り出したページの上に配置するので、ページサイズを入力せずに
* 作ります。
*/
$pdf->begin_page_ext(0, 0, "");
/* PDF をインポートしてページに配置
* 既存の PDF から1ページ目を取り出し、現在のページに貼り付けます。
* adjustpage キーワードにより、ページサイズは貼り付けたページのサイズと
* 同じになります。
*/
$pdi = $pdf->open_pdi_document($importPdf, "");
if($pdi == 0) {
// PDF のオープンに失敗
throw new PDFlibException();
}
$pdiPage = $pdf->open_pdi_page($pdi, 1, "");
if($pdiPage == 0) {
// ページのオープンに失敗
throw new PDFlibException();
}
$pdf->fit_pdi_page($pdiPage, 0, 0, "adjustpage");
/* PDFlib ブロックのブロック名を指定してテキストを配置
* インポートしたページ上の PDFlib ブロックにテキストを配置します。
* プログラマーは PDFlib ブロックのブロック名だけを知っていればよく、その他の
* フォントサイズ、座標、フォントスタイル等は PDFlib ブロックで指定することが
* できます。(プログラム側で設定することもできます)
* フォントについてはシステムにインストールされていればブロックプラグインで
* 指定したものが使われますが、インストールされていない場合はプログラムで指
* 定します。
*/
$optlist = "font=$msGothic";
$text = "請求書作成日時:$invoiceDate";
fill_text_block($pdf, $pdi, "invoice_date", $text, $optlist);
$optlist = "font=$msGothic";
$text = $companyName;
fill_text_block($pdf, $pdi, "org_name", $text, $optlist);
$optlist = "font=$msGothic";
$text = $total2;
fill_text_block($pdf, $pdi, "total_2", $text, $optlist);
$itemOptlist = "font=$msGothic";
$countOptlist = "font=$msGothic";
$priceOptlist = "font=$msGothic";
$amountOptlist = "font=$msGothic";
for($i = 0; $i < 10; $i++) {
$text = $items[$i]["item"];
if($text == "")
break;
fill_text_block($pdf, $pdi, "item_" . ($i + 1), $text, $itemOptlist);
$text = $items[$i]["count"];
fill_text_block($pdf, $pdi, "count_" . ($i + 1), $text, $countOptlist);
$text = $items[$i]["price"];
fill_text_block($pdf, $pdi, "price_" . ($i + 1), $text, $priceOptlist);
$text = $items[$i]["amount"];
fill_text_block($pdf, $pdi, "amount_" . ($i + 1), $text, $amountOptlist);
}
if($i > 1) {
$text = "小計";
fill_text_block($pdf, $pdi, "item_" . ($i + 1), $text, $itemOptlist);
$text = $_POST["subtotal"];
fill_text_block($pdf, $pdi, "amount_" . ($i + 1), $text, $itemOptlist);
}
if($i > 0) {
$text = "消費税";
fill_text_block($pdf, $pdi, "item_" . ($i + 2), $text, $itemOptlist);
$text = $_POST["tax"];
fill_text_block($pdf, $pdi, "amount_" . ($i + 2), $text, $itemOptlist);
}
$text = $total1;
$optlist = "font=$msGothic";
fill_text_block($pdf, $pdi, "total_1", $text, $optlist);
/* PDFlib ブロックのブロック名を指定してイメージを配置
* イメージについても PDFlib ブロックのブロック名だけでイメージを配置すること
* ができます。イメージの大きさやはめこみ方法等のパラメータは PDFlib ブロック
* に持つことができます。
*/
if($stampImage == 1) {
$optlist = "";
$image = $pdf->load_image("gif", "stamp.gif", $optlist);
$optlist = "";
fill_image_block($pdf, $pdi, "stamp_image", $image, $optlist);
$pdf->close_image($image);
}
/* PDFlib ブロックのブロック名を指定して複数行テキストを配置する
* 複数行テキストについても PDFlib ブロックのブロック名だけでテキストを配置す
* ることができます。textflowhandle オプションを与えた場合、fill_textblock()
* は有効なテキストフローハンドルを返します。また、通常のテキストフローと同
* 様に、処理後はテキストフローハンドルを破棄する必要があります。
*/
$optlist = "font=$msMincho textflowhandle=0";
$text = $memo;
$ft = fill_textflow_block($pdf, $pdi, "memo", $text, $optlist);
if($ft != 0)
$pdf->delete_textflow($ft);
// インポートしたページと PDF を閉じる
$pdf->close_pdi_page($pdiPage);
$pdf->close_pdi_document($pdi);
/* ページを閉じる
* ページ上への出力が終わったらページを閉じます。
* もし複数ページに渡る PDF を作成する場合、再度 open_page_ext() でページを
* 開きます。
*/
$pdf->end_page_ext("");
/* 文書を閉じる
* ページ全体の出力が終わったら、ドキュメントを閉じます。
* ドキュメントを閉じると、PDF が作成されます。
*/
$pdf->end_document("");
// PDF をブラウザに出力
$buf = $pdf->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=$outputPdf");
print($buf);
}
catch(PDFlibException $e) {
/* PDFlib で発生した例外の処理
* PDFlib で例外が発生した場合、PDFlibException クラスが送出されます。
* PDFlibException クラスでは、最後に実行された PDFlib の API 名、
* エラーコード、エラーの詳細を取得できます。
*/
echo($e->get_apiname() . "[" . $e->get_errnum() . "]: " . $e->get_errmsg());
}
catch(Exception $e) {
echo($e);
}
// PDFlib オブジェクトの解放
if(isset($pdf)) {
$pdf->delete();
}