ホーム > PDF Tools 一覧 > PDF Tools ライト > PDF Easy Parse > C++サンプル > Trailer情報

PDF Easy Parse C++ PDF文書のTrailer情報を取得するサンプル

PDF Easy Parse は、PDF構造の解析専用ツール(ライブラリ)です。このPDF Easy Parseライブラリを使えばPDF文書を解析したり、必要な部分を取り出したりする機能を目的のアプリケーションに追加できます。

PDF Easy Parse 購入(価格)


ダウンロード:
PDF Easy Parse無償体験版は、以下からダウンロードしてください。利用許諾契約書をご確認のうえダウンロードしてください。ダウンロードしますと、利用許諾契約書に同意したものとみなします。
評価用ライセンスキーも必ずダウンロードしてください。


他のC++サンプルはこちらです。


インストール

無償体験版をダウンロードして解凍すると以下のようなフォルダーができます。

docライブラリの簡単な説明書
includeヘッダー
liblibおよびDLL
sample/CC言語用サンプル
sample/C++C++言語用サンプル

lib/PdfEasyParse.libを作成するアプリケーションにリンクしてください。lib/PdfEasyParse.dllをアプリケーションの実行ファイル(.exe)のあるフォルダーに配置してください。


3.PDF文書のトレイラー情報

PDF文書のトレイラーには、そのPDFを構成する基礎となる情報が格納されています。
詳細は「2.4 トレイラー(Trailer)」を参照してください。

トレイラーは、ファイルのTrailer部に記載される場合と、インダイレクト オブジェクトに記載される場合(「8.クロス・リファレンス ストリーム(Cross Reference Stream)」を参照)があります。前者の例後者の例でそれぞれの内容を確認してください。
PDF Easy Parseライブラリは、上記のいずれの場合でも容易に読み出すことができます。


3.1 PDF文書のトレイラー情報を取得

PDF Easy Parseを使うことによって、そのPDF文書から取り出したすべてのトレイラー情報を構造体にして戻します。
PDFのトレイラーは順に解析され、それぞれの要素と同名のメンバーにその値が格納されますので利用は容易です。

#include "PEParse.h"

#pragma comment(lib,"PdfEasyParse.lib")

int main(int argc, char* argv[])
{
    TPEPHandle  *hPep;
    int         ret = 0;

    //初期化
    hPep = PEPInitialize( "ライセンスキー" );
    if (!hPep){
        fprintf(stderr,"初期化できません。\n");
        return 100;
    }

    //オープン
    if(!PEPOpen( hPep, "HelloWorld.pdf" )){
        fprintf(stderr, "Open Error\n");
        ret = 2;
        goto end_proc;
    }

    //すべてのトレイラー情報
    int            nOfTrailers;
    TPEPTrailer    *trailers;

    nOfTrailers = PEPGetTrailers(hPep, &trailers);    //トレイラー情報配列を取得
    for (int i=0; i<nOfTrailers; i++){
        printf("\nTrailer.%d 解析内容:(オフセット:%d)\n", i, trailers[i].lTrailerOffset);
        if (trailers[i].me.objNum!=0 || trailers[i].me.genNum!=0)    //トレイラー情報がインダイレクトオブジェクトの場合
                                        printf( "Reference: %d %d\n", trailers[i].me.objNum, trailers[i].me.genNum );
        printf("Trailer Level: %d\n", trailers[i].nTrailerLevel);
        printf("Update Level : %d\n", trailers[i].nUpdateLevel);
        if (trailers[i].size)           printf( "Size:    %d\n", trailers[i].size );
        if (trailers[i].prev)           printf( "Prev:    %d\n", trailers[i].prev );
        if (trailers[i].root.objNum)    printf( "Root:    %d %d R\n", trailers[i].root.objNum, trailers[i].root.genNum );
        if (trailers[i].info.objNum)    printf( "Info:    %d %d R\n", trailers[i].info.objNum, trailers[i].info.genNum );
        if (trailers[i].type)           printf( "Type:    /%s\n", trailers[i].type );
        if (trailers[i].nW >=3)         printf( "W:       [ %d %d %d ] 要素数:%d\n", trailers[i].W[0], trailers[i].W[1], trailers[i].W[2], trailers[i].nW );
        if (trailers[i].length)         printf( "Length:  %d\n", trailers[i].length );
        if (trailers[i].ID[0].len>0 && trailers[i].ID[1].len>0){
            printf( "ID:      [");
            for (int j = 0; j < 2; j++) printf("%s", trailers[i].ID[j].buf);
            printf("]\n");
        }
        if (trailers[i].nIndex > 0){
            printf( "Index:   [ ");
            for (int j = 0; j < trailers[i].nIndex; j++) printf("%d ", trailers[i].index[j]);
            printf("] 要素数:%d\n", trailers[i].nIndex);
        }
        if (trailers[i].xrefStm > 0)    printf( "XRefStm: %d\n", trailers[i].xrefStm );
    }

end_proc:
    //後始末
    PEPDestroy( hPep );

    return 0;
}
PEPInitialize() 初期化します。
引数に以下を指定します。
第一引数ライセンスキー
第二引数(省略可)処理の内容をログするファイルのパス
第三引数(省略可)記録されるログのレベル
1以上の値を設定します。レベルは以下のとおりです。ここで指定された値より大きな値のレベルのログが記録されます。
ログレベル
1重要なエラー
2~4エラー
5~9警告
10以上インフォメーション
PEPOpen() PDF文書を開きます。
引数に以下を指定します。
第一引数ハンドル
第二引数PDFファイルのパス
PEPGetTrailer() PDFのトレイラー情報を取得
PDFのトレイラー情報が格納された構造体(TPEPTrailer)のポインターを取得します。
引数に以下を指定します。
第一引数ハンドル
第二引数解析したトレイラー情報を格納する構造体のポインター
PEPDestroy() ハンドルや利用したメモリが開放されます。

3.1.1 結果

結果は、以下のように表示されます。

Trailer.0 解析内容:(オフセット:845)
Size:    8
Root:    7 0 R
Info:    6 0 R
ID:      [<1775615b6d180ff72f4473d56aaa72bf><1775615b6d180ff72f4473d56aaa72bf>]

上記は、PDF文書にトレイラーがひとつだけ含まれている場合の結果です。
トレイラーは、ディクショナリでその要素は以下の意味です。含むことのできる全トレイラー要素はこちらを参照してください。

要素意味
Sizeクロスリファレンス・テーブルの要素数
RootCatarogディクショナリ(上記の例では、"obj 7 0"を参照します。)
InfoPDF文書の情報ディクショナリ(上記の例では、"obj 6 0"を参照します。)
IDPDF文書のユニークな識別子

なおトレイラーは、PDFが更新された場合や、リニアライズ(Web用に最適化された)PDFの場合などに複数記載されます。
以下に複数のトレイラーを持つPDFを解析した結果を示します。

Trailer.0 解析内容:(オフセット:12394)
Size:    22
Prev:    116
Root:    9 0 R
Info:    7 0 R
ID:      [<9c586eecd5310b3d85076c775b385e8e><58f2131b93a65d4b9521e34bf7625656>]

Trailer.1 解析内容:(オフセット:296)
Size:    16
Prev:    6200
Root:    9 0 R
Info:    7 0 R
ID:      [<9c586eecd5310b3d85076c775b385e8e><a9f116575c000045914416695c7afd90>]

Trailer.2 解析内容:(オフセット:6380)
Size:    8
ID:      [<9c586eecd5310b3d85076c775b385e8e><a9f116575c000045914416695c7afd90>]

上で解析されたPDF文書は、リニアライズされたPDFをさらに1回更新したものです。
最新のトレイラーは、Trailer.0で、Traile.1とTrailer.2は、更新前のトレイラーです。なお、Traile.1とTrailer.2はIDが同じなので同じPDF文書のものであることがわかります。Trailer.2は、リニアライズされたPDFで最初のページをすばやく表示するために使われるトレイラーです。


3.2 PDF文書のトレイラー生(Raw)データを取得

PDF文書には、その終端近くにtrailerstartxref%%EOFがこの順で記載されているものと、trailerの記載が無くstartxrefと%%EOFの2つだけがこの順で記載されたものがあります。

前者の場合はキーワード「trailer」をPDFファイルの終端から検索してトレイラー情報を取り出すことができます。しかし、後者の場合はstartxrefで示されたオフセット位置にあるインダイレクトオブジェクトを取り出して更に、先頭のオブジェクト番号と世代番号などを読み飛ばした後にトレイラー情報を取り出さなければなりません。

またトレイラーは、PDFの形式や更新によって複数存在する場合があります。複数のトレイラーがある場合、古いトレーラの情報はそれと重複する新しいトレイラーの情報で上書きされなければなりません。

PDF Easy Parseは、いずれの形式でもすべてのトレイラーのオフセット値とその長さ(バイト数)を取得できます。このオフセット値と長さを使って、PDFファイルから生の(未処理の)トレイラー情報を読み出すことができます。

#include "PEParse.h"

#pragma comment(lib,"PdfEasyParse.lib")

int main(int argc, char* argv[])
{
    TPEPHandle  *hPep;
    int         ret = 0;

    //初期化
    hPep = PEPInitialize( "ライセンスキー" );
    if (!hPep){
        fprintf(stderr,"初期化できません。\n");
        return 100;
    }

    //オープン
    if(!PEPOpen( hPep, "HelloWorld.pdf" )){
        fprintf(stderr, "Open Error\n");
        ret = 2;
        goto end_proc;
    }

    //すべてのトレイラーを取得(Rawデータ)
    char    buf[1024];
    int nOfTrailers = PEPGetTrailers(hPep, NULL);    //トレイラー数のみを取得
    for( int i = 0; i < nOfTrailers; i++ ){
        size_t  len = PEPnthTrailerSize( hPep, i );
        long    ofs = PEPnthTrailerOffset( hPep, i );
        PEPReadPdfData( hPep, buf, ofs, len );
        buf[len] = NULL;
        printf( "\nTrailer.%dth (Rawデータ):(オフセット:%d)\n\"%s\"\n", i, ofs, buf );
    }

end_proc:
    //後始末
    PEPDestroy( hPep );

    return 0;
}
PEPGetTrailers() PDFに含まれるトレイラーの総数を戻す。
この関数呼び出しで第二引数にNULLを指定すると、解析した結果を戻しません。
PEPTrailerSize() トレイラーのサイズ(バイト数)
PEPTrailerOffset() トレイラーが記載されているオフセット位置
"<<"で開始するディクショナリの位置を戻します。
PEPReadPdfData() PDFから連続するバイトデータをPDF文書に記載されているまま読み出します。
以下の引数を指定します。
第一引数ハンドル
第二引数読み取ったデータを格納するバッファ
第三引数読み出し開始のオフセット
第四引数読み出すバイト数

3.2.1 結果

以下のような結果になります。

Trailer.0th (Rawデータ):(オフセット:845)
"<<
/Size 8
/Info 6 0 R
/Root 7 0 R
/ID [<1775615b6d180ff72f4473d56aaa72bf><1775615b6d180ff72f4473d56aaa72bf>]
>>"

また、PDFに複数のトレイラーが含まれていた場合は、以下のような結果になります。
解析したPDFは、リニアライズド(Web用に最適化)PDFを1回更新したものです。

Trailer.0th (Rawデータ):(オフセット:12394)
"<</Size 22/Root 9 0 R/Info 7 0 R/ID[<9C586EECD5310B3D85076C775B385E8E><58F2131B
93A65D4B9521E34BF7625656>]/Prev 116>>"

Trailer.1th (Rawデータ):(オフセット:296)
"<</Size 16/Root 9 0 R/Info 7 0 R/ID[<9C586EECD5310B3D85076C775B385E8E><A9F11657
5C000045914416695C7AFD90>]/Prev 6200>>"

Trailer.2th (Rawデータ):(オフセット:6380)
"<</Size 8/ID[<9C586EECD5310B3D85076C775B385E8E><A9F116575C000045914416695C7AFD9
0>]>>"
終端の位置取得 )前のサンプル<<<>>>次のサンプル( PDF XRe クロスリファレンス情報

サンプル コード

サンプルのコードは、以下からダウンロードしてください。

   PepSamples_2_0_2.zip

なお、サンプルコードを実行させるためには、PDF Easy Parseライブラリが必要です。別途ダウンロードしてください。


ご質問・お問い合わせ

メールで support@TrustSS.co.jp 宛てにお願いします。
または、質問のページからお送りいただくようお願いします。なお、ご質問・ご要望は、匿名でも送信できます。