描画 ジオメトリ PDF は PostScript と同じジオメトリを使用します。ページの左下隅を基準とし、 デフォルトではポイント数 (1 インチの 1/72) で場所を指定します。 ページの大きさはページオブジェクトから取得できます。 getWidth(); $height = $pdfPage->getHeight(); ]]> PDF には、色を表現するためのさまざまな方法があります。Zend_Pdf では、 グレイスケール、RGB および CMYK 色空間をサポートしています。 Zend_Pdf_Color オブジェクトが要求される箇所では、 これらのどれでも使用できます。それぞれの色空間に対応する機能を提供するのが Zend_Pdf_Color_GrayScaleZend_Pdf_Color_Rgb および Zend_Pdf_Color_Cmyk クラスです。 HTML 形式の色指定も Zend_Pdf_Color_Html クラスで使用できます。 図形の描画 描画操作は、PDF のページに対して行われます。 基本図形のセットが Zend_Pdf_Page クラスで提供されています。 テキストの描画 テキストに対する描画操作も、PDF のページに対して行われます。 ベースラインの x 座標および y 座標を指定することで、 ページ内の任意の場所にテキストを 1 行描画できます。 現在のフォント、フォントサイズおよびページの塗りつぶしの色を使用して、描画操作が行われます (詳細は、以下を参照ください)。 ページ上への文字列の描画 drawText('Hello world!', 72, 720); ... ]]> フォントの色を設定 setFillColor(Zend_Pdf_Color_Html::color('#990000')) ->drawText('Hello world (in red)!', 72, 720); .... ]]> デフォルトでは、現在のロケールのエンコーディングによって テキストの文字列が解釈されます。異なるエンコーディングを使用している場合 (例えば、ディスク上のファイルから UTF-8 の文字列を読み込んだり レガシーなデータベースから MacRoman の文字列を取得したりなど) は、 描画の際に文字エンコーディングを指定できます。 そうすることで、Zend_Pdf が変換処理を行います。PHPiconv() 関数がサポートしているエンコーディングなら、すべて入力として使用することが可能です。 UTF-8 でエンコードされた文字列をページに描画する drawText($unicodeString, 72, 720, 'UTF-8'); ... ]]> フォントの使用 Zend_Pdf_Page::drawText() は、 現在設定されているフォントおよびフォントサイズを使用します。 これは Zend_Pdf_Page::setFont() メソッドで設定できます。 PDF ドキュメントは、PostScript Type 1 フォントおよび TrueType フォントだけでなく、 PDF 用の特別な形式である Type 3 フォントや複合フォントもサポートしています。 すべての PDF ビューアには、以下の 14 種類の標準 Type 1 フォントが組み込まれています。 その内容は Courier (4 種類)、Helvetica (4 種類)、Times (4 種類)、Symbol そして Zapf Dingbats です。 現在 Zend_Pdf は、標準の 14 種類の PDF フォントだけでなく 独自の TrueType フォントもサポートしています。フォントオブジェクトを取得するには、 2 種類のファクトリーメソッドのいずれかを使用します。使用するメソッドは、 標準の 14 種類の PDF フォントの場合は Zend_Pdf_Font::fontWithName($fontName)、 独自のフォントの場合は Zend_Pdf_Font::fontWithPath($filePath) です。 標準フォントの作成 setFont($font, 36); ... ]]> 14 種類の標準フォント名を表す定数は、Zend_Pdf_Font クラスで定義されています。 Zend_Pdf_Font::FONT_COURIER Zend_Pdf_Font::FONT_COURIER_BOLD Zend_Pdf_Font::FONT_COURIER_ITALIC Zend_Pdf_Font::FONT_COURIER_BOLD_ITALIC Zend_Pdf_Font::FONT_TIMES Zend_Pdf_Font::FONT_TIMES_BOLD Zend_Pdf_Font::FONT_TIMES_ITALIC Zend_Pdf_Font::FONT_TIMES_BOLD_ITALIC Zend_Pdf_Font::FONT_HELVETICA Zend_Pdf_Font::FONT_HELVETICA_BOLD Zend_Pdf_Font::FONT_HELVETICA_ITALIC Zend_Pdf_Font::FONT_HELVETICA_BOLD_ITALIC Zend_Pdf_Font::FONT_SYMBOL Zend_Pdf_Font::FONT_ZAPFDINGBATS 任意の TrueType フォント (通常は '.ttf' という拡張子です) も使用できますし、 TrueType アウトラインを含む OpenType フォント (拡張子は '.otf') を使用することも可能です。現在はまだサポートしていませんが、将来は Mac OS X の .dfont ファイルや Microsoft TrueType Collection (拡張子 '.ttc') ファイルもサポートする予定です。 TrueType フォントを使用するには、フォントへのフルパスを指定しなければなりません。 何らかの理由でフォントが読み込めなかった場合、あるいはそれが TrueType フォントでなかった場合は、ファクトリーメソッドが例外をスローします。 TrueType フォントの作成 setFont($goodDogCoolFont, 36); ... ]]> デフォルトでは、独自のフォントは PDF ドキュメントに埋め込まれます。 そのため、閲覧者のシステムにそのフォントがインストールされていなくても、 ページをきちんと閲覧できるようになります。ファイルの大きさが気になる場合は、 ファクトリーメソッドのオプションで「フォントを埋め込まない」ことを指定できます。 TrueType を作成するが、PDF ドキュメントには埋め込まない setFont($goodDogCoolFont, 36); ... ]]> PDF ファイルにフォントが埋め込まれていないけれども 閲覧者のシステムにはそのフォントがインストールされている場合は、ドキュメントは通常通りに閲覧できます。 もし適切なフォントがインストールされていないは、PDF 閲覧アプリケーションが適切な代替フォントを選択します。 中には、PDF ドキュメントへの埋め込みを禁止するようなライセンスを使用しているフォントもあります。 これをあなどってはいけません。もし埋め込めないフォントを利用しようとすると、 ファクトリーメソッドは例外をスローします。 このようなフォントを使用することも可能ですが、そのためには、 上で説明した「埋め込まない」フラグを使用するか、あるいは例外を抑制しなければなりません。 埋め込みが禁止されているフォントで、例外をスローさせないようにする 利用者にフォントを選択させる場合などは、この抑制方法を使用することをお勧めします。 PDF ドキュメントに埋め込めるフォントなら埋め込むでしょうし、 埋め込めないフォントは埋め込まないでしょう。 フォントのサイズは比較的大きく、中には 10 メガバイトに達するものもあります。 デフォルトでは埋め込みフォントは Flate 圧縮され、平均して 50% ほどサイズを節約できます。 何らかの理由でフォントを圧縮したくない場合は、以下のオプションで圧縮を無効にできます。 埋め込みフォントを圧縮しない 最後に、必要に応じていくつかの埋め込みオプションをビット OR 演算子で連結することもできます。 フォントの埋め込みオプションを組み合わせる 標準 PDF フォントの制限 標準 PDF フォントは、いくつかのシングルバイトエンコーディング (詳細は PDF Reference, Sixth Edition, version 1.7 の Appendix D を参照ください) を内部的に使用しています。 これらは、ほぼ Latin1 文字セットと同じものです (Symbol フォントと ZapfDingbats フォントは例外です)。 Zend_Pdf は、標準フォントでのテキストの描画時に CP1252 (WinLatin1) を使用します。 他のエンコーディングでもテキストは描画できますが、 現在のロケールと異なる場合はそれを指定する必要があります。 実際に描画されるのは WinLatin1 の文字のみです。 フォント埋め込みオプションの使用 setFont($font, 36) ->drawText('Euro sign - €', 72, 720, 'UTF-8') ->drawText('Text with umlauts - à è ì', 72, 650, 'UTF-8'); ... ]]> フォントの抽出 Zend_Pdf モジュールを使用すると、読み込んだドキュメントからフォントを抽出できるようになります。 これは、ドキュメントをインクリメンタルに更新する際に便利です。 この機能がなければ、ドキュメントを更新するたびにフォントをアタッチしたり ドキュメントに埋め込んだりしなければならなくなります。 Zend_Pdf オブジェクトおよび Zend_Pdf_Page オブジェクトには、 ドキュメントやページ内のすべてのフォントを抽出するためのメソッドが用意されています。 読み込んだドキュメントからのフォントの抽出 extractFonts(); $pdf->pages[] = ($page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4)); $yPosition = 700; foreach ($fontList as $font) { $page->setFont($font, 15); $fontName = $font->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, 'en', 'UTF-8'); $page->drawText($fontName . ': The quick brown fox jumps over the lazy dog', 100, $yPosition, 'UTF-8'); $yPosition -= 30; } ... // ドキュメントの最初のページで用いられているフォントを取得します $firstPage = reset($pdf->pages); $firstPageFonts = $firstPage->extractFonts(); ... ]]> フォント名の指定による、読み込んだドキュメントからのフォントの抽出 pages[] = ($page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4)); $font = Zend_Pdf_Font::fontWithPath($fontPath); $page->setFont($font, $fontSize); $page->drawText($text, $x, $y); ... // フォント名をどこかに保存しておきます... $fontName = $font->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, 'en', 'UTF-8'); ... $pdf->save($docPath); ... ]]> pages[] = ($page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4)); /* $srcPage->extractFont($fontName) としてもかまいません */ $font = $pdf->extractFont($fontName); $page->setFont($font, $fontSize); $page->drawText($text, $x, $y); ... $pdf->save($docPath, true /* インクリメンタル更新モード */); ... ]]> フォントの抽出はどこででもできますが、次のような制限があります。 抽出したフォントは、そのフォントの抽出元と同じドキュメント内でしか使用できません。 埋め込まれたフォントプログラムは実際には抽出されません。 つまり、抽出されたフォントは元のフォントメトリクス (テキストの幅の計算に使用するもの) と同じものになりません。 extractFont($fontName); $originalFont = Zend_Pdf_Font::fontWithPath($fontPath); $page->setFont($font /* 描画用に抽出したフォント */, $fontSize); $xPosition = $x; for ($charIndex = 0; $charIndex < strlen($text); $charIndex++) { $page->drawText($text[$charIndex], xPosition, $y); // テキストの幅の計算には元のフォントを使用します $width = $originalFont->widthForGlyph( $originalFont->glyphNumberForCharacter($text[$charIndex]) ); $xPosition += $width/$originalFont->getUnitsPerEm()*$fontSize; } ... ]]> 画像の描画 Zend_Pdf_Page クラスの drawImage() メソッドで、 画像の描画を行います。 画像オブジェクトは、Zend_Pdf_Image::imageWithPath($filePath) メソッドで作成しなければなりません (現在は JPG、PNG および TIFF 画像をサポートしています)。 画像の描画 drawImage($image, 100, 100, 400, 300); ... ]]> 重要! JPEG のサポートには PHP の GD 拡張モジュールを必要とします。 重要! PNG でアルファチャネルを使用した画像を扱うには、ZLIB 拡張モジュールを必要とします。 詳細な情報は、PHP のドキュメント (http://www.php.net/manual/ja/ref.image.php), (http://www.php.net/manual/ja/ref.zlib.php) を参照ください。 直線の描画スタイル 直線の描画スタイルは、線幅と線の色、そして破線のパターンで定義されます。 これらはすべて、Zend_Pdf_Page クラスのメソッドで設定します。 塗りつぶしのスタイル Zend_Pdf_Page::drawRectangle()Zend_Pdf_Page::drawPolygon()Zend_Pdf_Page::drawCircle() および Zend_Pdf_Page::drawEllipse() メソッドは、オプションのパラメータとして $fillType を受け取ります。これは以下のいずれかの値となります。 Zend_Pdf_Page::SHAPE_DRAW_STROKE - 図形の輪郭を描画します Zend_Pdf_Page::SHAPE_DRAW_FILL - 図形を塗りつぶすだけです Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - 輪郭を描画し、塗りつぶします (デフォルトの挙動です) Zend_Pdf_Page::drawPolygon() メソッドには、さらにパラメータ $fillMethod を指定できます。 Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING (デフォルトの挙動) PDF リファレンス によると、これは以下のように定義されています。
nonzero winding number ルールは、ある点がパスの内側にあるかどうかを 判断するため、その点からどこかの方向に放射線を引いて その線がパスを構成する線と交わる場所を調べます。 0 からカウントをはじめ、放射線の左から右にパスの線が横切った場合に +1、放射線の右から左に横切った場合に -1 します。 すべての交点について調べた後、もし結果が 0 ならその点はパスの外側です。 0 でなければ内側です。 注意: この方式では、放射線とパスの線が同一になった場合や 放射線がパスの線の接線となった場合のことを指定していません。 放射線は任意の方向に伸ばせるので、このような状況にならないような放射線が選ばれます。 単純な凸状のパスの場合、この方式で判断した内側・外側は、 直感的に予想できるのと同じ結果になります。 ただ、パスを構成する線自身が交わっているなどの複雑なパスの場合は、 興味深い結果となります。この例を、(PDF リファレンスの) 図 4.10 に示します。 5 本の直線を互いに交差させて作成した星型の場合、このルールでは 星型で囲まれるすべての部分をパスの内側として扱います。真ん中の 五角形も内側となります。2 つの同心円からなるパスの場合、 2 つの円が同じ方向に描画された際には両方の円に囲まれている部分が 内側となります。2 つの円が反対方向に描画された際には、2 つの円からなる 「ドーナツ型」の部分が内側となります。このルールの場合は、 「ドーナツの穴」の部分は外側という扱いになります。
Zend_Pdf_Const::FILLMETHOD_EVENODD PDF リファレンス によると、これは以下のように定義されています。
nonzero winding number ルールに対するもうひとつのルールが even-odd ルールです。 このルールでは、ある点が「内側である」かどうかを判断する材料として、 その点からどこかの方向に放射線を引いてその線がパスを構成する線と何回交わるか ということを用います。交わる回数が奇数だった場合、その点は内側です。 交わる回数が偶数だった場合、その点は外側です。単純なパスの場合は、 これは nonzero winding number ルールと同じ結果になります。 しかし、複雑な図形の場合は異なる結果となります。 複雑なパスに対して even-odd ルールを適用した場合の例を (PDF リファレンスの) 図 4.11 に示します。このルールの場合、5 本の交差する直線からなる星型では、 三角形の部分のみが内側として扱われます。真ん中の五角形は、内側とはみなされません。 2 つの同心円の場合、2 つの円からなる「ドーナツ型」の部分のみが内側として扱われます。 これは、円の描画された方向に依存しません。
線形変換 回転 描画操作を適用する前に、PDF のページを回転させることができます。 それには Zend_Pdf_Page::rotate() メソッドを使用します。 ZF 1.8 以降で使用できる拡大/縮小 倍率の変更は Zend_Pdf_Page::scale() メソッドで行います。 ZF 1.8 以降で使用できる移動 座標系の移動は Zend_Pdf_Page::translate() メソッドで行います。 ZF 1.8 以降で使用できる傾斜 ページを傾けるには Zend_Pdf_Page::skew() メソッドを使用します。 グラフィックの状態の保存/復元 好きな時点でのグラフィックの状態 (現在のフォント、フォントサイズ、線の色、塗りつぶしの色、線の形式、 ページの回転、クリップ領域) を保存/復元できます。 保存操作はグラフィックの状態をスタックに保存し、復元の際にはそこから取り出されます。 Zend_Pdf_Page クラスには、これらの操作を行うための 2 つのメソッドがあります。 描画領域のクリッピング PDF および Zend_Pdf モジュールは、描画領域のクリッピングに対応しています。 描画演算子が影響を及ぼす範囲を、このクリップ領域内に制限します。 クリップ領域の初期値は、ページ全体です。 Zend_Pdf_Page クラスでは、 クリッピングに関連するいくつかのメソッドを提供しています。 スタイル Zend_Pdf_Style クラスがスタイルに関する機能を提供します。 スタイルは、グラフィックの状態に関する複数の設定を保存し、 PDF のページに 1 回の操作でそれを適用するために使用されます。 Zend_Pdf_Style クラスでは、 さまざまなグラフィックの状態を設定あるいは取得するためのメソッドが提供されています。 透明度 Zend_Pdf モジュールは、透明度の処理に対応しています。 透明度を設定するには Zend_Pdf_Page::setAlpha() メソッドを使用します。