iText 5 Chunk と iText 8 Text クラスの比較

2016 年に iText 7 がリリースされましたが、iText 5 は今でも非常に人気のある PDF ライブラリです。使いやすさと機能は依然として競争力がありますが、この記事では、iText 5 の高レベルのテキストおよびコンテンツ機能に注目し、iText 7 および 8 の改訂された API と比較します。特に新しい実装の場合、iText 8 がはるかに優れたオプションである理由がわかります。

はじめに

この記事では、 iText 5 の Chunk クラスと iText 7 で導入された Text クラスを比較しながら、iText Core の高レベルなテキストおよびコンテンツ機能に焦点を当てます。一見すると、これらのクラスはほぼ同じことを行いますが、後で説明するように、iText Core バージョン 7 および 8 の Text クラスははるかに柔軟で拡張性があります。

iText PDF ライブラリは、2000 年に初めて公開されて以来、非常に人気が高く、機能豊富な PDF SDK に成長しました。現在 iText は Apryse 製品の一部であり、2023年初めに iText Core バージョン 8 をリリースするなど、その機能の開発と拡張を続けています。他の PDF ライブラリと比較して、iText が開発者に提供する主な利点の 1 つは、高レベル API です。この API により、PDF 開発の低レベルの詳細と複雑さの多くを抽象化することで、PDF の作成と操作のプロセスが簡素化されます。

しかし、2016 年に iText 7 がリリースされたことで、API を書き直し、一般的なタスクの抽象化とカプセル化を改善し、PDF の生成と操作をより直感的で開発者に優しいものにしました。つまり、iText Core の主要な高レベル API 関数には、iText 5 以前のバージョンと比べて大きな違いがあります。

iText のレイアウトを理解する

先に進む前に、iText 7 以降のバージョンの基本的な違いの 1 つは、コア ライブラリが複数の個別のモジュールに分割されているということを理解することが重要です。これらのモジュールは、テキスト操作、レイアウト、署名などの特定の機能を処理します。このモジュール化により、開発者は必要なモジュールのみを含めることができるため、プロジェクト内のライブラリの全体的なサイズが縮小され、保守性が向上します。

PDF 形式では、「指定された位置に文字を描画」や「(x1,y1) から (x2, y2) に線を描画」などの低レベルの操作しか許可されないため、レイアウト モジュールには、要素の計算と配置、および PDF 構文で必要な複雑な描画操作の構築の手間を軽減する iText のレンダリング エンジンのロジックが含まれています。

レイアウト モジュールについては、ここで説明する以上に多くの機能があります。そのため、レンダリング エンジン、プロパティ コンテナー、レイアウト オブジェクトなどの概念について詳しく知るには、レイアウト モジュールのドキュメント ( Java / .NET) を読むことをお勧めします。簡単に言うと、レイアウト モジュールは、抽象要素 (ParagraphTableList など) を変換し、ページ上で配置および配置する役割を担っています。

Chunk と Text の違いとは?

iText 5 API ドキュメントChunk は、次のように説明されています。

ドキュメントに追加できるテキストの最小単位を表す重要な部分です。

ほとんどの要素は、1 つ以上の Chunks に分割できます。チャンクは、特定の Font を持つ String です。その他のすべてのレイアウト パラメータは、このテキスト チャンクが追加されるオブジェクトで定義する必要があります。

比較すると、iText 8 (および 7) の Text クラスは次のように定義されます。

Text は、任意の長さのテキストです。 リーフ要素として、特定のレイアウト属性を持つことができるコンテンツの最小部分です。

詳細については、Text クラスの Java および .NET API ドキュメントを参照してください。

リーフ要素とは?

「リーフ要素」という用語は、ドキュメント オブジェクト モデル (DOM) 階層内の特定の種類の要素を指します。PDF 形式は、本来、コンテンツをそのような方法で表現するものではないため、これは、PDF の作成と操作に必要な複雑な PDF 構文の抽象化を提供することで iText が真価を発揮する領域の 1 つです。iText の DOM は、PDF ドキュメントの論理構造をツリーのような構造として表現し、要素が階層的に編成されます。

このコンテキストでは、「リーフ要素」とは、子要素を持たない要素のことです。これは、ドキュメント構造内でそれ以上ネストまたは細分化されないスタンドアロン要素です。リーフ要素は通常、他の要素を含めることを意図していないテキスト、画像、グラフィック図形などの基本的なコンテンツ要素を表します。

たとえば、Paragraph 要素のコンテキストでは、段落内のテキスト コンテンツ (「Hello, World!」など) は、段落内の最小の分割できないコンテンツ単位であるため、リーフ要素と見なされます。同様に、ネストされた要素のない単一の画像を表す Image 要素もリーフ要素になります。

リーフ要素は、PDF ドキュメントのコンテンツの重要な構成要素です。コンテンツの構造と構成を提供するコンテナ要素 (非リーフ要素) とは対照的に、リーフ要素はページ上にレンダリングする必要がある実際のデータを表します。

iText 5 で Chunk を使用する方法

iText 5 の Chunk クラスは、PDF ドキュメント内に個別のスタイル化されたテキスト ユニットを作成するために設計されました。フォント、色、下線、ハイフネーションなどのさまざまな書式設定オプションが用意されています。開発者は、Chunk インスタンスにメソッドを連鎖させることでテキストの外観をカスタマイズし、各チャンクのスタイルを詳細に制御できます。ただし、多数のメソッドを連鎖させると、特に複雑なドキュメントではコードが過度に冗長になる可能性があります。

以下は、iText 5 で Chunk クラスを使用する方法を示す簡単な Java の例です。カスタム フォントと書式を使用して、一連の異なるチャンクを定義します。

import com.itextpdf.text.*;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.FileOutputStream;
import java.io.IOException;

public class ChunkExample {

    /**
     * The resulting PDF file.
     */
    public static final String RESULT = "./src/main/resources/resultChunk.pdf";

    public static void main(String[] args) throws IOException, DocumentException {
        new ChunkExample().createPdf(RESULT);
    }

    /**
     * Creates a PDF document.
     *
     * @param filename the path to the new PDF document
     * @throws DocumentException
     * @throws IOException
     */
    public void createPdf(String filename) throws IOException, DocumentException {
        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream(filename)).setInitialLeading(16);
        document.open();
        Font font = new Font(FontFamily.HELVETICA, 6, Font.BOLD, BaseColor.WHITE);

        document.add(new Chunk("Default text chunk \n\n"));
        Chunk chunk = new Chunk("Text chunk with some properties", font);
        chunk.setBackground(new BaseColor(8, 73, 117), 1f, 0.5f, 1f, 1.5f)
                .setTextRise(6)
                .setUnderline(new BaseColor(249, 157, 37), 2, 0, 3, 0, PdfContentByte.LINE_CAP_BUTT)
                .setWordSpacing(10)
                .setHorizontalScaling(2)
                .append(" and appended text");
        document.add(chunk);
        document.add(Chunk.createWhitespace("Create whitespace"));
        document.add(Chunk.NEWLINE);

        document.close();
    }
}

次のような PDF が生成されます。

図 1: Chunk の例の結果

青い背景のテキストには、その一部(「ed テキスト」)が実質的に見えないという問題があることに気付くでしょう。ただし、これは現時点ではそれほど重要ではなく、単にその機能のデモンストレーションです。

新しい Text クラスの使い方

それに比べて、Text クラスはより合理的で柔軟なアプローチを提供することで、テキスト操作に革命を起こします。 これにより、開発者は Chunk のようなプロパティを使用して、よりクリーンな構文と改善された読みやすさでスタイル設定されたテキストを作成できます。 同じインスタンスでメソッドを連鎖させる代わりに、開発者は Text オブジェクトを作成し、プロパティを個別に適用できるため、よりシンプルで保守しやすいコードになります。

次の Java の例は、iText 7/8 の Text クラスの機能の一部を示しています。

import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvasConstants;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.text.pdf.PdfContentByte;

import java.io.IOException;

public class TextExample {

    /**
     * The resulting PDF file.
     */
    public static final String RESULT = "./src/main/resources/resultText.pdf";

    public static void main(String[] args) throws IOException {
        new TextExample().createPdf(RESULT);
    }

    /**
     * Creates a PDF document.
     *
     * @param filename the path to the new PDF document
     */
    public void createPdf(String filename) throws IOException {
        Document document = new Document(new PdfDocument(new PdfWriter(filename)));

        PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD);
        Paragraph paragraph = new Paragraph();

        paragraph.add(new Text("Default text chunk \n\n"));
        Text chunk = new Text("Text chunk with some properties").setFont(font).setFontSize(6).setFontColor(ColorConstants.WHITE);
        chunk.setBackgroundColor(new DeviceRgb(8, 73, 117), 1f, 0.5f, 1f, 1.5f)
                .setTextRise(6)
                .setUnderline(new DeviceRgb(249, 157, 37), 2, 0, 3, 0, PdfContentByte.LINE_CAP_BUTT)
                .setWordSpacing(10)
                .setHorizontalScaling(2)
                .setText(chunk.getText() + " and appended text");
        paragraph.add(chunk);
        document.add(paragraph);

        Paragraph anotherParagraph = new Paragraph();
        Text text = new Text("More customized text example").setFont(font).setFontSize(20).setFontColor(ColorConstants.WHITE)
                .setBorder(new SolidBorder(new DeviceRgb(8, 73, 117), 3))
                .setLineThrough()
                .setTextRenderingMode(PdfCanvasConstants.TextRenderingMode.FILL_STROKE)
                .setStrokeColor(new DeviceRgb(249, 157, 37));
        anotherParagraph.add(text);
        document.add(anotherParagraph);

        document.close();
    }
}

次のような PDF が生成されます。

図 2: Text の例の結果

結果は最初のものとかなり似ていますが、今回は「見えない」テキストがないことに気がつくでしょう。青い背景がすべてのテキストに対して正しくレンダリングされています。ただし、コード レベルでは、フォントやテキストの色などのスタイルが Text オブジェクトのチェーン メソッドを直接使用して設定され、最初の例と比較してコードが合理化されている点が主な違いです。

ただし、2 番目の例では、iText Core バージョン 7 および 8 で、ベース方向、境界線、斜体、太字、取り消し線、ストロークの色設定などの追加のテキスト スタイルと構成が有効になっていることも示されています。2 番目の段落では、Text 要素のカスタム レンダラーを作成し、PDF ドキュメントに描画する方法を定義できる setNextRenderer メソッドを使用します。このメソッドを使用すると、テキスト要素の外観と動作をほぼあらゆる方法でカスタマイズできるため、PDF 内のテキスト コンテンツを細かく制御できます。これは、iText 5 の Chunk クラスでは不可能でした。

RUPS による詳細な検査

違いをより視覚的に表現するには、RUPS で 2 つの PDF を比較します。iText の研究チームが開発した RUPS は、iText の PDF デバッグに特化したツールで、PDF の内部構造を表示し、開発者が PDF の構文、オブジェクト、およびそのプロパティを検査して分析できるようにします。iText は、開発中に RUPS を頻繁に使用し、お客様が特定のドキュメントの問題を診断するのを支援しています。バグのある PDF や不正な PDF を処理する必要がある場合、RUPS は開発者ツールボックスに不可欠な要素です。RUPS は iText Core の新しいリリースで定期的に更新され、オープンソースでもあり、GitHub で入手できます。

図 3: iText 5 で生成された PDF の非圧縮コンテンツ ストリームのビュー

RUPS で resultChunk.pdf を見ると、PDF 構文が左上のペインの階層的な PDF オブジェクト ツリー ビューにどのように表示されるかがわかります。このビューを使用すると、オブジェクトをドリルダウンして、オブジェクト ID、タイプ、その他の関連情報などのプロパティを調べることができます。右側のペインには、相互参照 (XREF) テーブルやフォーム フィールドなどの便利な情報を表示できますが、この例ではプレーン テキスト ビューが選択されています。

しかし、もっと興味深いのは、右下のビューです。これは、ページのすべての PDF ページ記述コマンドを含む PDF コンテンツ ストリームのデコードされた生データを示しています。ここでは、テキスト ブロックの開始を定義する BT で始まる部分、テキスト配置座標 (Td)、テキスト チャンクのフォント設定 (/F1 12 Tf) に注目します。テキスト ブロックは 1 つしかないため、すべてのフォントまたはスタイルの変更は、テキスト ブロックの終了 (ET) の前に連鎖する必要があります。

ここで、 iText Core バージョン 8.0.1 の最新リリースで生成された PDF の同等のビューと比較してみましょう。

図 4: resultText.pdf の非圧縮コンテンツ ストリーム

この PDF では、単一のテキスト ブロックではなく、独自のレイアウトとスタイルを持つ複数のブロックがあります。実際、わかりやすくするために、RUPS の 2 つの非圧縮コンテンツ ストリームを並べて比較してみましょう。

図 5: 2 つの PDF ドキュメントを並べて比較した図

2 つのコンテンツ ストリームを見るとわかるように、結果として PDF 構造ははるかに論理的でわかりやすくなり、コードもよりクリーンで保守しやすくなります。

まとめ

Chunk および Text クラスはどちらも PDF ドキュメントでスタイル設定されたテキストを作成するためのメカニズムを提供しますが、iText 7 の開発中に教訓が得られました。 Chunk クラスは包括的なテキスト操作機能を提供しましたが、冗長で複雑なコードになることがよくありました。ただし、Text クラスを導入したとき、テキスト スタイルを設定および適用する方法を合理化したいと考えました。 さらに、iText Core の新しいカスタム レンダラーにより、より高度なカスタマイズが可能になりました。

もちろん、iText 5 に対する使いやすさと動作の改善は、その Text クラスに限定されるものではなく、iText 8 では PDF 2.0 暗号化方式のサポート、最新のデジタル署名拡張機能、組み込みの FIPS 140-2 機能などを提供します。また、iText 8 は iText 5 と同じデュアル ライセンス (AGPL と商用) を保持しています。そのため、オープン ソース開発者コミュニティは、数百万ドル規模の企業とまったく同じ iText Core 機能を利用できます。

本製品に関するご質問、ご不明な点はエクセルソフトまでお気軽にお問い合わせください。

iText 製品の詳細は、弊社 Web サイトをご確認ください。

記事参照:
© 2024 Apryse
Comparing the iText 5 Chunk and iText 8 Text Classes

タイトルとURLをコピーしました