ホーム > PDF Tools 一覧 > PDF Tools ライト > PDF Easy Parse > C++サンプル > インダイレクトオブジェクト

PDF Easy Parse C++ インダイレクトオブジェクトを取得するサンプル

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)のあるフォルダーに配置してください。


5.インダイレクト オブジェクト - Indirect Object

PDFでは、ラベルの付いたオブジェクトを「インダイレクト オブジェクト」といいます。 このオブジェクトは、2つの数字で構成された識別子で参照されます。 2つの数字は、オブジェクト番号とその世代番号の組み合わせです。この2つの数字の組み合わせによって、ただひとつのインダイレクトオブジェクトを参照できます。


5.1 インダイレクト オブジェクト情報を取得

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;
    }

    //オブジェクトの総数
    long    nObjs;
    printf( "\nオブジェクトの総数=%d\n", nObjs = PEPNumOfObjects( hPep ) );

    //全オブジェクトの番号、世代、オフセット値
    TPEPObjectsOffset   *offset;
    TPEPIndirectObject  *obj;
    TPEPStreamDecoded   *decoded;

    PEPGetObjectsOffset( hPep, &offset );

    for (long i = 0; i < nObjs; i++){
        printf("\nオブジェクト %d %d %c (%d)\t", offset[i].obj, offset[i].gen, offset[i].cUsed, offset[i].offset);
        switch (offset[i].cUsed){
        case 'f':
            printf("\tフリー\n");
            break;
        case 'n':
            switch (PEPGetIndirectObject(hPep, offset[i].obj, offset[i].gen, &obj)){ //パース済みのオブジェクトを取得
            case 1:
                printf(" not opened\n");
                break;
            case 2:
                printf(" ありません\n");
                break;
            case 0:
                printf("\t型: %s", (obj->object.type < 0 || obj->object.type > 9) ? PEPObjectTypeStr(EPEPUnknown) : PEPObjectTypeStr(obj->object.type));
                if(obj->bParsed)
                    printf("(Streamを持つ)\n");
                else
                    printf("\n");
                if( obj->bLengthIsValid ){
                    //"stream"を除いたオブジェクトのサイズが有効であれば、...
                    char    *objBuf;
                    long    pos;

                    objBuf = new char [ obj->lObjectLength ];
                    pos = (long)offset[i].offset + obj->lNumberLength + obj->lSpanLength;
                    PEPPdfSeek(hPep, pos);
                    PEPReadCurrentPdfData(hPep, objBuf, (size_t)obj->lObjectLength);
                    char *str = PEPBinaryToString(hPep, objBuf, obj->lObjectLength);
                    printf("内容: (位置=%d,サイズ=%d)\n%s", pos, obj->lObjectLength, str);
                    delete objBuf;
                }
                if(PEPGetStreamDecoded(hPep, offset[i].obj, offset[i].gen, NULL)){
                    TPEPStreamDecoded    *decoded;
                    if(PEPGetStreamDecoded(hPep, offset[i].obj, offset[i].gen, &decoded)){
                        char *str = PEPBinaryToString(hPep, decoded->buf, decoded->len);
                        printf("ストリーム:(デコード済)\n%s", str);
                    }
                }
                break;
            }
            break;
        case 's':
        {
            TPEPIndirectObject    *obj;

            printf("ストリーム\nパース済:");
            if ( !PEPGetIndirectObject(hPep, offset[i].obj, 0, &obj) ){
                char    *s;

                printf("\t型: %s", (obj->object.type < 0 || obj->object.type > 9) ? PEPObjectTypeStr(EPEPUnknown) : PEPObjectTypeStr(obj->object.type));
                PEPObjectToString(hPep, &obj->object, &s);
                printf("(ObjectStream内)\n%s\n", s);
                TPEPStreamDecoded    *decoded;
                if( PEPGetObjectStreamDecoded(hPep, offset[i].obj, &decoded) ){
                    s = PEPBinaryToString(hPep, decoded->buf, decoded->len);
                    printf("デコードされたObjectStream: (位置=%d,サイズ=%d)\n%s", obj->lObjectOffset, obj->lObjectLength, s);
                }else
                    printf("デコードされたObjectStreamが見つかりませんでした。\n");
            }else{
                printf(" オブジェクトが見つかりませんでした。\n");
            }
            break;
        } //case 's':
        } //switch (offset[i].cUsed)
    }

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

    return 0;
}
PEPInitialize() 初期化します。
引数に以下を指定します。
第一引数ライセンスキー
第二引数(省略可)処理の内容をログするファイルのパス
第三引数(省略可)記録されるログのレベル
1以上の値を設定します。レベルは以下のとおりです。ここで指定された値より大きな値のレベルのログが記録されます。
ログレベル
1重要なエラー
2~4エラー
5~9警告
10以上インフォメーション
PEPOpen() PDF文書を開きます。
引数に以下を指定します。
第一引数ハンドル
第二引数PDFファイルのパス
PEPNumOfObjects() PDFに含まれるオブジェクトの総数が戻ります。
引数にハンドルを指定します。
PEPGetObjectsOffset() PDFに含まれるオブジェクトの総数が戻ります。
引数に以下を指定します。
第一引数ハンドル
第二引数クロスリファレンス情報が格納されるTPEPObjectsOffset型のポインター
PEPGetIndirectObject() 指定のインダイレクトオブジェクトが戻ります。
引数に以下を指定します。
第一引数ハンドル
第二引数オブジェクト番号
第三引数世代番号
第四引数結果を格納するTPEPIndirectObject型のポインター
PEPObjectTypeStr() オブジェクトのタイプを表す文字列(「ディクショナリ」など)に変換
既定では日本語ですが、英文に変換する場合はPEPObjectTypeStrJ()を使います。
PEPPdfSeek() ファイルの現在位置を指定の位置に移動
引数に以下を指定します。
第一引数ハンドル
第二引数移動するオフセット位置
PEPReadCurrentPdfData() ファイルの現在位置からデータの読み出し
現在の位置から指定バイト数のデータを読み出します。
引数に以下を指定します。
第一引数ハンドル
第二引数結果の格納先
第三引数読み出すバイト数
PEPBinaryToString() バイナリーデータを読みやすいように16進数と文字列に変換します。
結果が文字列(char*)で戻ります。引数に以下を指定します。
第一引数ハンドル
第二引数変換するバイナリーデータが格納されたアドレス
第三引数変換するバイト数
PEPGetStreamDecoded() ストリーム部分を取り出す。
streamとendstreamで示された部分を戻します。その部分が圧縮されていれば伸張します。
引数に以下を指定します。関数の戻り値は、ストリームのバイト数です。
第一引数ハンドル
第二引数ストリームを持つインダイレクト オブジェクトの番号
第三引数ストリームを持つインダイレクト オブジェクトの世代番号
第四引数ストリームを格納するTPEPStreamDecoded型のポインター
NULLを指定すると、ストリーム自体は戻りません。ストリームの大きさを取得する場合に使用します。
PEPObjectToString() ストリームオブジェクトを文字列に変換します。
圧縮されていれば伸張します。この関数は、PDFを圧縮しないで(伸張したデータで)作成する場合などにも利用します。
引数に以下を指定します。
第一引数ハンドル
第二引数変換するオブジェクト(TPEPObject型)のポインター
第三引数変換された文字列(char*)

5.2 出力結果

このサンプルを使ってPDF文書("HelloWorld.pdf")を解析した結果(一部省略)です。

オブジェクトの総数=8

オブジェクト 0 65535 f (0)              フリー

...中略...

オブジェクト 3 0 n (117)                型: ディクショナリ(Streamを持つ)
内容: (位置=126,サイズ=37)
0000  3C 3C 20 2F 46 69 6C 74 65 72 20 2F 46 6C 61 74  << /Filter /Flat
0010  65 44 65 63 6F 64 65 20 2F 4C 65 6E 67 74 68 20  eDecode /Length
0020  37 32 20 3E 3E                                   72 >>
ストリーム:(デコード済)
0000  42 54 0A 31 20 30 20 30 20 31 20 31 30 30 20 36  BT.1 0 0 1 100 6
0010  30 30 20 54 6D 0A 2F 53 46 31 20 35 30 20 54 66  00 Tm./SF1 50 Tf
0020  0A 30 20 54 73 20 30 20 54 72 20 30 20 54 63 20  .0 Ts 0 Tr 0 Tc
0030  30 20 54 77 0A 28 48 65 6C 6C 6F 2C 20 57 6F 72  0 Tw.(Hello, Wor
0040  6C 64 2E 29 20 54 6A 0A 45 54 0A                 ld.) Tj.ET.

オブジェクト 4 0 n (266)                型: ディクショナリ
内容: (位置=275,サイズ=91)
0000  3C 3C 2F 54 79 70 65 20 2F 50 61 67 65 20 2F 50  <</Type /Page /P
0010  61 72 65 6E 74 20 35 20 30 20 52 0D 0A 2F 4D 65  arent 5 0 R../Me
0020  64 69 61 42 6F 78 20 5B 30 20 30 20 35 39 35 20  diaBox [0 0 595
0030  38 34 32 20 5D 0D 0A 2F 52 65 73 6F 75 72 63 65  842 ]../Resource
0040  73 20 32 20 30 20 52 20 2F 43 6F 6E 74 65 6E 74  s 2 0 R /Content
0050  73 20 33 20 30 20 52 0D 0A 3E 3E                 s 3 0 R..>>

オブジェクト 5 0 n (544)                型: ディクショナリ
内容: (位置=553,サイズ=47)
0000  3C 3C 0D 0A 2F 54 79 70 65 20 2F 50 61 67 65 73  <<../Type /Pages
0010  0D 0A 2F 4B 69 64 73 20 5B 20 34 20 30 20 52 20  ../Kids [ 4 0 R
0020  5D 0D 0A 2F 43 6F 75 6E 74 20 31 0D 0A 3E 3E     ]../Count 1..>>

...中略...

オブジェクト 7 0 n (610)                型: ディクショナリ
内容: (位置=619,サイズ=36)
0000  3C 3C 0D 0A 2F 54 79 70 65 20 2F 43 61 74 61 6C  <<../Type /Catal
0010  6F 67 0D 0A 2F 50 61 67 65 73 20 35 20 30 20 52  og../Pages 5 0 R
0020  0D 0A 3E 3E                                      ..>>

解析したPDF文書は、8個のインダイレクトオブジェクトを含んでいてそれらのオブジェクトは、以下の意味を持ちます。

オブジェクト内容
0未使用のオブジェクト
3オブジェクトの型はディクショナリで、オフセット117から開始
ストリームを持ち、そのデータはFlaleDecodeで圧縮されていて、72バイトの長さである。
(ストリームは、伸張して表示されています。この内容の意味は、以下を参照してください。)
4オブジェクトの型はディクショナリで、オフセット266から開始
ページ情報が記されており、ページの内容はオブジェクト3である。
5オブジェクトの型はディクショナリで、オフセット544から開始
このPDFの総ページ数は1で、そのページ情報はオブジェクト4にある。
7オブジェクトの型はディクショナリで、オフセット610から開始
Catarogディクショナリでページ ツリーがオブジェクト5である。

オブジェクト3 のストリームに記された内容
以下のコードが記されており、「Hello, World.」を表示させるためのPostScript文です。

BT
1 0 0 1 100 600 Tm
/SF1 50 Tf
0 Ts 0 Tr 0 Tc 0 Tw
(Hello, World.) Tj
ET

PostScript文の詳細は、PDF構文(構造)テキストを参照してください。

以下は、オブジェクトストリームを含んだPDF文書("HelloWorld-strm.pdf")を解析した結果(抜粋)です。
オブジェクト2、3、10がオブジェクト ストリームで、それらには、インダイレクトオブジェクト5、6、13が含まれています。

オブジェクトの総数=15

オブジェクト 0 0 f (0)          フリー

...中略...

オブジェクト 2 0 n (4456)               型: ディクショナリ(Streamを持つ)
内容: (位置=4464,サイズ=57)
0000  3C 3C 2F 46 69 6C 74 65 72 2F 46 6C 61 74 65 44  <</Filter/FlateD
0010  65 63 6F 64 65 2F 46 69 72 73 74 20 34 2F 4C 65  ecode/First 4/Le
0020  6E 67 74 68 20 34 38 2F 4E 20 31 2F 54 79 70 65  ngth 48/N 1/Type
0030  2F 4F 62 6A 53 74 6D 3E 3E                       /ObjStm>>
ストリーム:(デコード済)
0000  35 20 30 20 3C 3C 2F 43 6F 75 6E 74 20 31 2F 4B  5 0 <</Count 1/K
0010  69 64 73 5B 39 20 30 20 52 5D 2F 54 79 70 65 2F  ids[9 0 R]/Type/
0020  50 61 67 65 73 3E 3E                             Pages>>

オブジェクト 3 0 n (4596)               型: ディクショナリ(Streamを持つ)
内容: (位置=4604,サイズ=58)
0000  3C 3C 2F 46 69 6C 74 65 72 2F 46 6C 61 74 65 44  <</Filter/FlateD
0010  65 63 6F 64 65 2F 46 69 72 73 74 20 34 2F 4C 65  ecode/First 4/Le
0020  6E 67 74 68 20 31 30 31 2F 4E 20 31 2F 54 79 70  ngth 101/N 1/Typ
0030  65 2F 4F 62 6A 53 74 6D 3E 3E                    e/ObjStm>>
ストリーム:(デコード済)
0000  36 20 30 20 3C 3C 2F 43 72 65 61 74 69 6F 6E 44  6 0 <</CreationD
0010  61 74 65 28 44 3A 32 30 31 34 30 32 30 34 31 35  ate(D:2014020415
0020  35 38 33 31 2B 30 39 27 30 30 27 29 2F 4D 6F 64  5831+09'00')/Mod
0030  44 61 74 65 28 44 3A 32 30 31 34 30 32 30 34 31  Date(D:201402041
0040  35 35 38 33 31 2B 30 39 27 30 30 27 29 2F 50 72  55831+09'00')/Pr
0050  6F 64 75 63 65 72 28 50 44 46 20 50 54 20 34 2E  oducer(PDF PT 4.
0060  31 30 20 5C 28 70 64 66 2D 74 6F 6F 6C 73 2E 63  10 \(pdf-tools.c
0070  6F 6D 5C 29 29 3E 3E                             om\))>>

...中略...

オブジェクト 5 2 s (0)  ストリーム
パース済:       型: ディクショナリ(ObjectStream内)
 << /Count 1 /Kids [  9 0 R ] /Type /Pages >>
デコードされたObjectStream: (位置=4,サイズ=35)
0000  3C 3C 2F 43 6F 75 6E 74 20 31 2F 4B 69 64 73 5B  <</Count 1/Kids[
0010  39 20 30 20 52 5D 2F 54 79 70 65 2F 50 61 67 65  9 0 R]/Type/Page
0020  73 3E 3E                                         s>>

オブジェクト 6 3 s (0)  ストリーム
パース済:       型: ディクショナリ(ObjectStream内)
 << /CreationDate ((D:20140204155831+09'00) /ModDate ((D:20140204155831+09'00) /
Producer ((PDF PT 4.10 \(pdf-tools.com\) >>
デコードされたObjectStream: (位置=4,サイズ=115)

...中略...

オブジェクト 10 0 n (795)               型: ディクショナリ(Streamを持つ)
内容: (位置=804,サイズ=57)
0000  3C 3C 2F 46 69 6C 74 65 72 2F 46 6C 61 74 65 44  <</Filter/FlateD
0010  65 63 6F 64 65 2F 46 69 72 73 74 20 35 2F 4C 65  ecode/First 5/Le
0020  6E 67 74 68 20 37 33 2F 4E 20 31 2F 54 79 70 65  ngth 73/N 1/Type
0030  2F 4F 62 6A 53 74 6D 3E 3E                       /ObjStm>>
ストリーム:(デコード済)
0000  31 33 20 30 20 3C 3C 2F 42 61 73 65 46 6F 6E 74  13 0 <</BaseFont
0010  2F 48 65 6C 76 65 74 69 63 61 2F 45 6E 63 6F 64  /Helvetica/Encod
0020  69 6E 67 2F 57 69 6E 41 6E 73 69 45 6E 63 6F 64  ing/WinAnsiEncod
0030  69 6E 67 2F 53 75 62 74 79 70 65 2F 54 79 70 65  ing/Subtype/Type
0040  31 2F 54 79 70 65 2F 46 6F 6E 74 3E 3E           1/Type/Font>>

オブジェクト 11 0 n (961)               型: ディクショナリ(Streamを持つ)
内容: (位置=970,サイズ=33)
0000  3C 3C 2F 46 69 6C 74 65 72 2F 46 6C 61 74 65 44  <</Filter/FlateD
0010  65 63 6F 64 65 2F 4C 65 6E 67 74 68 20 35 36 3E  ecode/Length 56>
0020  3E                                               >
ストリーム:(デコード済)
0000  42 54 20 2F 54 31 5F 30 20 35 30 20 54 66 20 31  BT /T1_0 50 Tf 1
0010  30 30 20 36 30 30 20 54 64 20 28 48 65 6C 6C 6F  00 600 Td (Hello
0020  2C 20 57 6F 72 6C 64 2E 29 54 6A 20 45 54 20     , World.)Tj ET

...中略...

オブジェクト 13 10 s (0)        ストリーム
パース済:       型: ディクショナリ(ObjectStream内)
 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font
>>
デコードされたObjectStream: (位置=5,サイズ=72)
...後略...

この結果の内以下は、

オブジェクト 5 2 s (0)

インダイレクト オブジェクト5が、インダイレクト オブジェクト2の先頭(0番目)にあることを示しています。またオブジェクト5で記された「パース済」のディクショナリは、オブジェクト2のストリームを解析(パース)した結果です。
同様に、オブジェクト6はオブジェクト3のストリームを、オブジェクト13はオブジェクト10のストリームを解析(パース)して得られます。

オブジェクト ストリームであるオブジェクト2のディクショナリの意味は、以下のとおりです。

キー意味
FilterFlateDecodeFlateDecodeフィルターで圧縮
First4最初のオブジェクトは、オフセット4から開始
Length48Streamのサイズは48バイト
N1格納されたオブジェクト数は1
TypeObjStmこのオブジェクトは、オブジェクトストリーム

ここで記されたLengthは圧縮されたデータの長さですが、Firstは伸張されたデータのオフセット位置です。

( クロスリファレンス情報取得 )前のサンプル<<<

サンプル コード

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

   PepSamples_2_0_2.zip

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


ご質問・お問い合わせ

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