ホーム < ゲームつくろー! < IKD備忘録

Acrobat SDK
3D Annotationメモ

(2014. 12. 15)


 やけにごちゃごちゃしているAcrobatの3D annotation周りのメモです。


@ 3D Annotationをページに追加

 3D Annotationは「辞書(Dictionary)」でそのデータ構造を記述します。辞書のキーは「名前オブジェクト」、値は「PDF Objectのいくつかの型」です。名前オブジェクトについては後述。型には辞書もあるので構造を入れ子に出来ます。この構造をイメージする事が3D Annotationの肝のようです。

 まず既存のPDFに3D Annotationを追加する所はこういう感じ:

ASFixedRect annotRect;    // アノテーションの領域構造体

// 72dpiを基準として適当なアノテーションの領域を定めている
annotRect.left   = Int16ToFixed( 1.0 * 72 );
annotRect.top    = Int16ToFixed( 9.5 * 72 );
annotRect.right  = Int16ToFixed( 7.0 * 72 );
annotRect.bottom = Int16ToFixed( 4.0 * 72 );

// ページに3Dアノテーションを追加
// pdPageはPDFのページドキュメント
PDAnnot newAnnot = PDPageAddNewAnnot( pdPage, -2, ASAtomFromString("3D"), &annotRect );

追加だけなら意外と簡単です。領域を決めてPDPageAddNewAnnot関数を呼ぶだけ。第2引数の「-2」は「ページのアノテーション配列の最後に追加」という事らしいです。ページ内にはアノテーションが沢山あって、それが配列として格納されています。第3引数ではASAtomFromString関数を使って文字列から「名前オブジェクト」を作っています。"3D"とすると3Dアノテーションになります。PDFでは「ASAtom型」という一意の名前を表す型が多用されるそうです。

 こうして出来た3DAnnotationはまだ空っぽ。その中の辞書(データ構造)に色々な値を設定する事で3D Anotationが動くようになります。例えば、

PDAnnotSetFlags( newAnnot, pdAnnotPrint | pdAnnotReadOnly );

PDAnnotSetFlags関数はアノテーションに対して色々なフラグを設定する関数です。上の場合、作った3Dアノテーションに対して印刷可能、リードオンリー(変更不可)にしています。



A Cosオブジェクト

 Acrobat及びPDFライブラリには3Dアノテーションを直接扱うメソッドが用意されていません。3D辞書をアノテーションに追加するには「Cos-level API」を使いCosドキュメントとCosオブジェクトを作成する必要があります。CosドキュメントはPDFドキュメントを表し、Cosオブジェクトはそれ以外のPDFオブジェクトを表します。Cosオブジェクトは単純な数値や文字列はもちろん、配列、辞書、ストリームなどの複雑なオブジェクトも表せます。

 Cosオブジェクトを作る関数は「CosNew*****」という名前で統一されています。関数には3つの引数があります:

CosObj obj = CosNew****( Cosドキュメント, bool, 値 );

第1引数にはCosオブジェクトをアタッチするCosドキュメント、第2引数はこのCosオブジェクトを参照型にするか否かです。trueにすると参照型になります。参照型(Indirenct)にするとここで作成したCosオブジェクトを他のページ(ドキュメント)にも使えます。falseにするとこのドキュメント専用になります。第3引数には対応するCosオブジェクトに与える値です。Cosオブジェクトの型によって色々あります。

 いずれの場合も戻り値はCosObj型です。何の型であるかを知るにはCosObjGetType関数にCosObjを渡しその戻り値をチェックします。以下のような列挙型が返ります:

CosNull ヌル
CosInteger 整数型
CosFixed 16bit整数型
CosReal 浮動小数点型
CosBoolean ブーリアン
CosName 名前型
CosString 文字列
CosDict 辞書
CosArray 配列
CosStream ストリーム

Cosオブジェクトは辞書に登録して行くのが普通です。辞書に登録する便利関数としてCosDictPutKeyString関数があります:

CosDictPutKeyString(
    theDict,       // 辞書CosObj
    "TheKey",      // キー文字列
    theCosValue    // 値となるCosObj
);

意味は言わずもがななので省略。



B 3DアノテーションCosオブジェクトにCosページを追加

 今、空の3Dアノテーション(PDAnnot)がある状態です。ここにCosの辞書をぶら下げる為、最初にPDAnnotからCosオブジェクトを作ります:

// 3Dアノテーションから3DアノテーションCosオブジェクトを取得
CosObj cosAnnot = PDAnnotGetCosObj( theAnnot );  

これで3DアノテーションのルートCosオブジェクトが取れました。次に3Dアノテーションを表示するページのCosオブジェクトを登録します:

// 3Dアノテーションを表示するページを登録

CosObj cosPage = PDPageGetCosObj( pdPage );     // ページからCosObjを取得

CosDictPutKeyString( cosAnnot, "P", cosPage );  // キー"P"に登録

ページからCosオブジェクトを取得しそれを3DアノテーションのCosオブジェクト直下にキー["P"]を設けて登録しています。"P"って何だろう?と思うわけですが、そう言うもんだと思っときます(^-^;。またコンテンツ名として"3D Model"という名前も登録しておきます:

// アノテーションに関連しているCosドキュメントを取得
CosObj cosDoc = CosObjGetDoc( cosAnnot );

// "3D Model"というCos文字列を作成
CosObj cosName_3DModel = CosNewString( cosDoc, false, "3D Model", strlen("3D Model") );

// コンテンツ名を登録
CosDictPutKeyString( cosAnnot, "Contents", cosName_3DModel );



C 3Dモデルストリームの作成と登録

 次に3DアノテーションCosオブジェクトに3Dモデルの情報を登録します。これは大きく2つの情報に分かれます。一つは「3Dモデルストリーム」。3Dモデルのデータそのものを表します。もう一つは「情報辞書」。3Dモデルが何であるかを表すパラメータがぶら下がった辞書です。

 3Dモデルストリームは次のように作成します:

// U3Dデータファイルパスを作成しオープン
const char* platformU3dPathName = "C:\hoge\foo.u3d";
ASPathName u3dPathName = ASPathFromPlatformPath( platformU3dPathName );

ASFile asU3dFile = NULL;
ASInt32 iRet = ASFileSysOpenFile( ASGetDefaultUnicodeFileSys(), u3dPathName, ASFILE_READ, &asU3dFile );
if ( (iRet != 0) || (asU3dFile == NULL) ) {
    AVAlertNote("U3Dデータファイルをオープン出来ませんでした。");
    E_RETURN (false);
}

// ファイルからデータストリームを読み込み
ASStm fileStm = ASFileStmRdOpen( asU3dFile, 0 );
if( fileStm == NULL ) {
    AVAlertNote( "U3Dデータファイルストリームがありませんでした。" );
    E_RETURN (false);
}

Acrobatは単純な文字列でファイルを開いてくれません。ASPathNameという専用の型に変換する必要があります。それを行うのがASPathPlatformPath関数です。ただこの関数、ちょっと古いそうで最近だとASFileSysCreateFilePath関数を使うそうです。でも上でも一応動きます。これで作成したASPathNameパスオブジェクトをAsFileSysOpenFile関数の第2引数に渡すとファイルを開いてくれます。第4引数にできるファイルオブジェクト(ASFile)をさらにASFileStmRdOpen関数に渡すとファイルストリーム化(ASStm)してくれます。何とも面倒ですが仕方ありません(^-^;

 こうして出来た3DモデルストリームからCosオブジェクトを作り登録します:

// Cosストリームを作成
CosObj stm3D = CosNewStream( cosDoc, true, fileStm, 0, true, attrObj, CosNewNull(), -1 );

// 3DアノテーションCosオブジェクトの辞書に登録
CosDictPutKeyString( cosAnnot, "3DD", stm3D );

CosNewStream関数がストリームからCosオブジェクトを作ってくれる関数です。第3引数にファイルストリームを渡します。第6引数のattrObjについてはこの後出てきます。作ったストリームのCosObjを3DアノテーションCosオブジェクトに["3DD"]というキー名で登録すればOKです。

 attrObjはCの冒頭で必要だとした「情報辞書」のCosオブジェクトです。3Dストリームの情報を辞書に記述したものです。必要な項目は以下の通り:

Length ストリームのサイズ(長さ) 必須
SubType "PRC"か"U3D" 必須
Filter 圧縮フィルタ オプション
Type "3D"に固定 オプション
OnInstantiate 3Dストリームが読み込まれた時に実行されるJavaScript オプション

LengthとSubTypeは必須です。残りはオプションなので無くても大丈夫。

CosObj attrObj = CosNewDict( cosDoc, false, 1 );  // 情報辞書作成

CosDictPutKeyString( attrObj, "Type", CosNewNameFromString(cosDoc, false, "3D") );
CosDictPutKeyString( attrObj, "Subtype", CosNewName( cosDoc, false, ASAtomFromString("U3D") ) );

こんな感じで新しい辞書を作り(cosDocにアタッチ)、そこに必須項目を登録します。