PDF アプリケーション サンプル
PDFファイルを開き、それを構文解析するサンプルアプリケーションを公開します。
ここで示すアプリケーションは、PDF構文を説明するためのものですので、すべてのPDFファイルを構文解析できるものではありません。
このサンプルは、PDF Toolsとは無関係です。PDF構文を説明するための簡単なサンプルアプリケーションの一部です。
このサンプルは、PDF Toolsとは無関係です。PDF構文を説明するための簡単なサンプルアプリケーションの一部です。
1.PDFファイル構造 - PDFファイルを開く
1.2 PDFファイルを開く
以下では、PDFファイルを開き、それを内部バッファに読み取ります。
このコードは、PDFファイルを読み取るOpen(wchar_t *fn)メソッドの一部です。
メソッドの引数で与えられたファイル名のPDFを開きデータを内部の領域(BLOB data)に格納します。
dataはグローバルな変数で、サンプル メソッドからアクセスできます。
このコードは、PDFファイルを読み取るOpen(wchar_t *fn)メソッドの一部です。
int fd;
struct _stat stat;
//Clear
if(data.cbSize){ Cleanup(); Init(); } //dataを初期化します。
if(_wsopen_s(&fd, fn, _O_BINARY|_O_RDONLY, _SH_DENYNO, _S_IREAD|_S_IWRITE)) return -1;
_fstat(fd, &stat);
//すべて読み取る
data.pBlobData = new BYTE [(data.cbSize = stat.st_size)];
if(_read(fd, data.pBlobData, data.cbSize)<(int)data.cbSize) return -2;
_close(fd);
Cleanup()およびInit()は、PDFデータを格納するdataを初期化するために別途定義されたメソッドです。メソッドの引数で与えられたファイル名のPDFを開きデータを内部の領域(BLOB data)に格納します。
dataはグローバルな変数で、サンプル メソッドからアクセスできます。
1.2 ヘッダー
ヘッダー部に記載されたPDFバージョンを確認します。このサンプルでは、「PDF1.5~1.7」を対象としています。
WHITE_SPACEは以下のように宣言されていて、PDFのホワイトスペースを選別します。
int offs;
//PDFのバージョンチェック
if(strncmp((char*)data.pBlobData, "%PDF-1.", 7)) return -3;
if(!strchr("4567",(int)data.pBlobData[7])) return -4;
headerOffs = 0; headerLen = 8;
if(!strchr(WHITE_SPACE,(int)data.pBlobData[8])){
while((unsigned)headerLen<data.cbSize) headerLen++;
return -4;
}
PDFのバージョンはファイルの先頭に記載されており、"%"で開始する8文字で構成されています。WHITE_SPACEは以下のように宣言されていて、PDFのホワイトスペースを選別します。
#define WHITE_SPACE "\011\012\014\015\040" //HorizontalTab, LineFeed, FormFeed, CarriageReturn, Space
1.3 トレイラー
トレイラー部に記載された「trailer」とクロスリファレンステーブルの位置を取得します。
ParseXRef( )は、クロスリファレンステーブルの構文解析をするメソッドです。
ParseTrailer( )は、trailer部を構文解析をするメソッドです。
//"startxref"をデータの終わりから検索する offs = data.cbSize - 9; while(strncmp((char*)(data.pBlobData+offs), "startxref", 9)) offs--; if(ParseXRef(offs)) return -5; //"trailer"を検索する("startxref"の前にある) while(strncmp((char*)(data.pBlobData+offs), "trailer", 7)) offs--; if(ParseTrailer(offs+7)) return -6;「trailer」とクロスリファレンステーブルは、PDFファイルの最後に記載されていますので、データの最後から逆順でキーワードを検索します。
ParseXRef( )は、クロスリファレンステーブルの構文解析をするメソッドです。
ParseTrailer( )は、trailer部を構文解析をするメソッドです。
1.4 クロスリファレンステーブルの解析
クロスリファレンステーブルの構文解をするメソッドです。
xrefは、以下のように宣言されています。
PDFオブジェクトのうちディクショナリは、Streamオブジェクトを伴う場合があります。その目的のためにStreamキーワードのついたプロパティ(streamOffsなど)とメソッド(GetStreamOffs( )など)を用意しています。
int ParseXRef(int offs)
{
BYTE *pdf = data.pBlobData;
offs += 9; //"startxref"を読み飛ばす
while(((pdf[offs]<'0')||(pdf[offs]>'9'))&&((ULONG)offs<data.cbSize)) offs++;
if((pdf[offs]<'0')||(pdf[offs]>'9')) return -1;
offs = atoi((char*)(pdf+offs));
//チェック
if(strncmp((char*)(pdf+offs), "xref", 4)) return -2;
offs += 4;
//オブジェクト番号
while((ULONG)offs<(data.cbSize-1)){
//クロスリファレンステーブル構文解析
int startNum, endNum;
while((pdf[offs]<'0')||(pdf[offs]>'9')) offs++; //数字まで読み飛ばし
startNum = atoi((char*)(pdf+offs));
while((pdf[offs]>='0')&&(pdf[offs]<='9')) offs++; //数字を読み飛ばし
while((pdf[offs]<'0')||(pdf[offs]>'9')) offs++; //数字まで読み飛ばし
endNum = atoi((char*)(pdf+offs));
while((pdf[offs]>='0')&&(pdf[offs]<='9')) offs++; //数字を読み飛ばし
while((pdf[offs]<'0')||(pdf[offs]>'9')) offs++; //数字まで読み飛ばし
//参照用クロスリファレンス作成
for(int i = startNum; i < endNum; i++){
int elemOffs = atoi((char*)pdf+offs);
int elemGen = atoi((char*)(pdf+offs+11));
char elemNf = (char)(pdf+offs)[17];
CXRef e(elemOffs, elemGen, elemNf);
if(elemNf == 'n')
if(ParseIndirectObj(i, &e)) return -1;
xref[i] = e;
offs += 20;
}
//サブセクションが続く?
if((pdf[offs]<'0')||(pdf[offs]>'9')) return 0;
}
return -2;
}
クロスリファレンス・テーブルは1つ以上のサブセクションで構成され、それぞれでインダイレクトオブジェクトごとのオフセットを示しています。
オフセット値を示す部分は、固定フォーマットですので、簡単に解析しています。ここで得られたオフセットから、使用中のインダイレクトオブジェクトの構文をParseIndirectObj( )メソッドで解析します。xrefは、以下のように宣言されています。
map<int,CXRef> xref;CXRefは、クロスリファレンス・テーブルのエントリー(PDFのオブジェクト)を格納するためのクラスで以下のように宣言されています。
PDFオブジェクトのうちディクショナリは、Streamオブジェクトを伴う場合があります。その目的のためにStreamキーワードのついたプロパティ(streamOffsなど)とメソッド(GetStreamOffs( )など)を用意しています。
class CXRef
{
private:
int offs; //オフセット値
int gen; //世代番号
char nf; //'n':利用中、'f':削除済み、NULL:未定義
int objOffs; //オブジェクトのオフセット値
int objLen; //オブジェクトの長さ
int objType; //オブジェクトの種類
int streamOrgLength; //<< .../Length nnn ... >>に示された長さ(nnn)
int streamOffs; //Streamオブジェクトのオフセット値(キーワードを含まないバイナリーの値のみ)
int streamLen; //Streamオブジェクトの長さ(同上)
public:
CXRef(void);
CXRef(const CXRef&);
CXRef(int, int, char);
~CXRef(void);
private:
void Init();
void Cleanup();
public:
int GetOffs();
int GetGen();
int GetNF();
int GetObjectOffs();
int GetObjectLen();
int GetObjectType();
int GetStreamOrgLength();
int GetStreamOffs();
int GetStreamLen();
bool IsDeleted(); //削除されたオブジェクト
bool HasStream(); //このオブジェクトがStreamオブジェクトを内包していれば"真"。Dictionary以外では常に"偽"
void SetObjectOffs(int);
void SetObjectLen(int);
void SetObjectType(int);
void SetStreamOffs(int);
void SetStreamLen(int);
void SetObjectInfo(int offs, int len, int type);
void SetObjectInfo(int offs, int len, int type);
void SetObjectInfo(int offs, int len, int type,int streamOrgLength, int streamOffs, int streamLen);
};
>>> 次へ
サンプル アプリケーションについて
PDFデータを解析できるサンプルアプリケーションを公開しています。PDFParse17_1_0.zip(Winfows版)をダウンロードして、お手元のPDFデータを解析してください。
このアプリケーションのソースコードは、PDF Tools SDKをご購入されたお客様のご希望により開示しています。詳細はお問い合わせください(メール)。
(記載の会社名および製品名は、各社の登録商標および商標です。)

