PDFJ WebからCGIでPDF自動作成してメールにPDF添付して送る
2011/12/20(火) 14:06 はてブ情報 はてブに登録 はてブ数

久々に自社Webサイト用でPerl-CGIでPDFを作成するツールを作成しました。
Web上でフォームに入力した内容を元にPDFを作成して、フォーム入力されたメールアドレスに作成したPDFを添付してメール送信するCGIです。
久々でいろいろ気づいた点があったので、苦労した点を備忘録として書いてみます。

Perl-CGIでPDFを作成 

PDFJ でやりました。

最近のPerlの事情はちょっと知らないので、もっといいモジュールがあるかもですが、レンタルサーバーのPerlが5.8.5でしたし、5年ほど前に使用したことあるので、PDFJを使用しました。
中島 靖 PDFJ 日本語PDFを生成するPerlモジュールからダウンロードして、PDFJフォルダとPDFJ.pmをレンタルサーバーへアップロード。
5年ほど前のPDFJを使ったCGIはMS-ACCESS2000をSQLで使ったりして、いやいやシフトJISのCGIだったのですが、PDFJ 0.7は シフトJISとEUC のみの対応でも使えたんですが、今回CGIがUTF-8ベースで、PDFJ 0.9はUTF-8対応とのことで、0.9でやることにしました。

UTF-8なので
use PDFJ 'UTF8';
#単位はポイント(1/72インチ)インチは25.4mm
my @pagesize = (595, 842); #A4サイズ
#  PDF 1.2(Acrobat3)
#  PDF 1.3(Acrobat4)
#  PDF 1.4(Acrobat5)
#  PDF 1.5(Acrobat6)
#  PDF 1.6(Acrobat7)
my $doc = PDFJ::Doc->new("1.2", @pagesize);
としました。

フォントの指定で困った。

PDFJでPDFで使用するフォントをするのですが、5年前はWindowsXPをWebサーバーにしてイントラネットでやってまして、フォントの指定は
$doc->new_font('c:\windows\fonts\msgothic.ttc:0', '90ms-RKSJ-H');
と、直接Windowsのフォントファイルを指定してやっていました。ところで、UNIX系のレンタルサーバーの場合はどうするのだろうか?。
フォントファイル指定の部分をとりあえず'GothicBBB-Medium'にしましたがうまくいかず、次に '/usr/share/fonts/truetype/kochi/kochi-gothic.ttf'とかにしましたがうまくいきません。

次にフォント指定後の'90ms-RKSJ-H'ってなんだろうとネットで調べてみるとPDFのフォントエンコーディングとのこと。
Identity-H PDF独自のCIDエンコードに準拠してコード付けされたもの。日本語
90ms-RKSJ-H WindowsでのMicrosoftのエンコード。日本語
90pv-RKSJ-H MacintoshのTrue Typeフォント標準のエンコード。日本語
83pv-RKSJ-H MacintoshのPostScriptフォント標準のエンコード。日本語
とあるがUNIX系Webサーバーはどれを使うの?とわからず、すべて試したがだめ。もしかして、フォントファイルがローカルに無いとだめなのか?と思い(以前RedHatでGDかなんかでやったことがある)フォントファイルをビットマップを削除して小さくしてレンタルサーバーにアップロードしてもうまくいきません。

結構悩みましたが インターナルエラー500がでるだけ。

埒明かないので、CGIのエラーコードを見てみようと、ローカルPCにPerlをいれて(いまさら?)CGIを実行しようと、ActivePerl から Perl 5.014002 for MSWin32 をインストール。でCGIをローカルPCで実行してみると
[PDFJ.pm:1644:die] encoding type mismatch at (eval 1) 
フォント指定の場所で encoding type mismatch て?PDFJの説明書を見直してみる。(いまさら?) すると、
和文フォントのエンコーディングの末尾の'H'は横書き、'V'は縦書き。'RKSJ'とつくものはShift-JIS用、'EUC'とつくものはEUC用、'Uni'とつくものはUnicode用。
とあるではないですか。
$doc->new_font('GothicBBB-Medium', 'UniJIS-UCS2-HW-H');
と UniJIS-UCS2-HW-H … Unicode 横書き を指定.とりあえずエラーが出ずうまくいきました。

PDFをWebブラウザで表示

生成したPDFの表示がどうなってるかしらべるには、最初はPDFJのファイル出力
#ファイル出力
$doc->print("test.pdf");
test.pdfをサーバー上に作ってFTPでダウンロードしてみていましたが、めんどくさいので
PDF MIMEのHTMLヘッダーをつけてPDFJの出力を標準出力にしてWebブラウザで表示させようと 
#PDF MIME 
print qq(Content-type: application/pdf
Content-Disposition: attachment; filename="test.pdf"
Transfer-Encoding: binary\n\n);
#PDF標準出力
$doc->print("-");
としましたがうまくいきません。前回0.7でやったときは良かったんですが、ブラウザのバージョンせいでしょうか。
attachment; を inline; とかPDFをローカルに落としてから、ファイルサイズをしれべてからファイルサイズ指定と、いろいろ試しましたがだめで、普通のHTMLヘッダ
#print qq(Content-type: text/html\n\n);
#$doc->print("-");
ですんなり表示できたんで、そのままでテストしました。

PDFJの画像(jpeg、png)の崩れ

PDFJは画像ファイル(jpeg、png)を$doc->new_image(…)でPDFの中に埋めこめれます。
ただ小さいサイズ(50*50ピクセルくらい)だとPDFで見ると下のほうが崩れてました。
何か指定の方法や、画像の編集アプリ(Win標準のペイントでしたが)のせいかも知れませんが、ためしに大きめの画像ファイルでやってみるとうまくいきました。
なので、埋め込む画像は小さかったんですが、大きめにしたらうまくいきました。

ページ上の表示位置

PDFJでは オブジェクト->show(ページ, X, Y) でテキストなどの表示位置をX,Y指定するのですが、ページの空白部分からはみ出るかもなので
#表示位置指定変数
my $pad = 50; #空白部分
my $width = $pagesize[0] - $pad * 2;
my $height = $pagesize[1] - $pad * 2;
として
オブジェクト->show($page, $width - X, $height - Y); とすれば位置指定やりやすいと思ったんですが、結局、絶対置指定してました。

PDFJでつくったPDFをメールに添付して送信

いろいろしましたが、以下のようなコードでやりました。
PDFJの出力をスカラー変数にいれて添付したのと、メールをUTF-8で送ったのがミソです。
Perl/CGI研究室 PERL-LABO ファイルの添付の研究をみてJCODEでJISコードにしてメール送信しようとしましたが、だめで、そのままUTF-8で送るようにしました。
my $filebody;
#PDFJをスカラー変数に出力します。
open my $fh, '>', \$filebody;
$doc->print($fh);
close $fh;

# 添付ファイル付きでメールを送る
# 引数 (添付するファイルパス, 添付するパス無しファイル名,

use MIME::Base64;

#Base64エンコードします
my $base64filebody = MIME::Base64::encode($filebody);
my $boundary = "B4B5O6U7N8D9A0R1Y";

#メール送信
open MAIL, "|${sendmail} -f ${mail} -t" or die "error";
#件名は base64 Unicode でエンコード済み
print MAIL qq(From:自分のアドレス\@cirlution.com
To:$相手のアドレスの変数
Reply-To:hoge\@cirlution.com
Cc:hoge\@cirlution.com
Cc:hoge2\@cirlution.com
Subject: =?utf-8?B?44K144Kk44OI44GL44KJ6KaL56mN44KC44KK?=
Content-Type: Multipart/Mixed; boundary="${boundary}"
\n);
# 本文を出力します。
print MAIL qq(--${boundary}
Content-type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

"$メール本文の変数\n);

# 添付ファイルを出力します。

my $ftitle = "test.pdf";
print MAIL qq(--${boundary}
Content-Type: application/octet-stream; name="${ftitle}"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="${ftitle}

${base64filebody}
--${boundary}--\n);
close MAIL;

名前:  非公開コメント   

E-Mail(任意/非公開):
URL(任意):
  • TB-URL  http://www.cirlution.com/blog/adiary.cgi/016/tb/