PDF 文書の作成、表示、および変換
PDF 文書は、コンパクトなプログラミング言語で書かれた一連のコマンドとして、解像度に依存しないベクトルグラフィックス、テキスト、およびイメージを格納します。PDF 文書には複数ページのイメージとテキストを含めることができます。PDF は、クロスプラットフォーム、読み取り専用文書の作成、および解像度に依存しないグラフィックスの描画に役立ちます。
Quartz は、すべてのアプリケーションに対して、図 13-1 に示したように、アプリケーションの描画操作を保存する高品質な PDF ドキュメントを作成します。結果として得られる PDF は、システムの他の部分やサードパーティ製の製品によって、特定の用途(特定のプリンタや Web 用など) に最適化されます。Quartz で生成された PDF 文書は、プレビューと Acrobat で正しく表示されます。
図 13-1 Quartz は高品質の PDF 文書を作成します
Quartz は PDF を"デジタルペーパー" として使用するだけでなく、API の一部として、PDF ファイルを表示および生成したり、他の多くの PDF 関連のタスクを実行するために使用できるさまざまな機能を備えています。
PDF 言語と構文を含む PDF の詳細については、PDF リファレンス、第 4 版、バージョン 1.5 を参照してください。
PDF を開いて表示
Quartz は、PDF 文書を表す CGPDFDocumentRef データ型を提供します。CGPDFDocumentCreateWithProvider 関数または CGPDFDocumentCreateWithURL 関数を使用して CGPDFDocument オブジェクトを作成します。CGPDFDocument オブジェクトを作成した後、グラフィックスコンテキストに描画できます。図 13-2 に、ウィンドウ内に表示された PDF 文書を示します。
図 13-2 PDF 文書
リスト 13-1 に、CGPDFDocument オブジェクトを作成し、文書内のページ数を取得する方法を示します。番号付きコード行の詳細な説明は、リストの後に示します。
リスト 13-1 PDF ファイルから CGPDFDocument オブジェクトを作成
CGPDFDocumentRef MyGetPDFDocumentRef (const char *filename) { CFStringRef path; CFURLRef url; CGPDFDocumentRef document; size_t count; path = CFStringCreateWithCString (NULL, filename, kCFStringEncodingUTF8); url = CFURLCreateWithFileSystemPath (NULL, path, // 1 kCFURLPOSIXPathStyle, 0); CFRelease (path); document = CGPDFDocumentCreateWithURL (url);// 2 CFRelease(url); count = CGPDFDocumentGetNumberOfPages (document);// 3 if (count == 0) { printf("`%s' needs at least one page!", filename); return NULL; } return document; }
コードの動作は以下の通りです:
- Core Foundation 関数を呼び出して、表示する PDF ファイルのファイル名を表す CFString オブジェクトから CFURL オブジェクトを作成します。
- CFURL オブジェクトから CGPDFDocument オブジェクトを作成します。
- コード内の次のステートメントが文書に少なくとも 1 ページあることを保証できるように、PDF 内のページ数を取得します。
リスト 13-2 のコードを見ると、PDF ページをグラフィックスコンテキストに描画する方法を見ることができます。番号付きコード行の詳細な説明は、リストの後に示します。
リスト 13-2 PDF ページの描画
void MyDisplayPDFPage (CGContextRef myContext, size_t pageNumber, const char *filename) { CGPDFDocumentRef document; CGPDFPageRef page; document = MyGetPDFDocumentRef (filename);// 1 page = CGPDFDocumentGetPage (document, pageNumber);// 2 CGContextDrawPDFPage (myContext, page);// 3 CGPDFDocumentRelease (document);// 4 }
コードの動作は以下の通りです:
- 指定したファイル名から CGPDFDocument オブジェクトを作成するために関数を呼び出します(リスト 13-1 を参照)。
- 指定されたページ番号のページを PDF 文書から取得します。
- CGContextDrawPDFPage 関数を呼び出すことによって、PDF ファイルから指定されたページを描画します。グラフィックスコンテキストと描画するページを指定する必要があります。
- CGPDFDocument オブジェクトを解放します。
PDF ページの変換を作成する
Quartz は、CGPDFPageGetDrawingTransform という関数を提供します。これは、PDF ページ内のボックスをあなたが指定した長方形にマッピングすることによって、アフィン変換を作成します。この関数のプロトタイプは以下のとおりです:
CGAffineTransform CGPDFPageGetDrawingTransform ( CGPPageRef page, CGPDFBox box, CGRect rect, int rotate, bool preserveAspectRatio );
この関数は、以下のアルゴリズムを使用してアフィン変換を返します。
- 指定した PDF ページの /MediaBox エントリと box パラメータ(media, crop, bleed, trim, or art) で指定した PDF ボックスの型に関連した長方形を交差させます。交差した結果は 実効長方形 になります。
- 実効長方形を、PDF ページの /Rotate エントリで指定された量だけ回転します。
- rect パラメータに指定した長方形の上に結果の長方形を配置します。
- 指定した rotate パラメータの値が 0 でなく 90 の倍数である場合、関数は実効長方形を指定した角度で回転します。正の値は長方形を右に回転し、負の値は長方形を左に回転させます。ラジアンではなく度を渡すことに注意してください。PDF ページの /Rotate エントリにも回転が含まれており、指定した rotate パラメータが /Rotate エントリと組み合わされていることに注意してください。
- 必要に応じて、実効長方形を拡大縮小し、指定した長方形の端と一致するようにします。
- preserveAspectRatio パラメータで true を渡してアスペクト比を保持するように指定すると、結果の長方形は rect パラメータで指定した長方形の、より制限の厳しい寸法の端と一致します。
たとえば、図 13-3 に示したような PDF 表示アプリケーションを書いている場合は、この関数を使用できます。左回転/右回転 機能を提供する場合は、CGPDFPageGetDrawingTransform を呼び出して、現在のウィンドウサイズと回転設定の適切な変換を計算することができます。
図 13-3 PDF ページを右に 90 度回転
リスト 13-3 は、関数に渡されたパラメーターを使用して PDF ページのアフィン変換を作成し、変換を適用してから PDF ページを描画する関数を示しています。番号付きコード行の詳細な説明は、リストの後に示します。
リスト 13-3   PDF ページ用のアフィン変換を作成
void MyDrawPDFPageInRect (CGContextRef context, CGPDFPageRef page, CGPDFBox box, CGRect rect, int rotation, bool preserveAspectRatio) { CGAffineTransform m; m = CGPDFPageGetDrawingTransform (page, box, rect, rotation,// 1 preserveAspectRato); CGContextSaveGState (context);// 2 CGContextConcatCTM (context, m);// 3 CGContextClipToRect (context,CGPDFPageGetBoxRect (page, box));// 4 CGContextDrawPDFPage (context, page);// 5 CGContextRestoreGState (context);// 6 }
コードの動作は以下の通りです:
- 関数に渡されたパラメータからアフィン変換を作成します。
- グラフィックス状態を保存します。
- CTM とアフィン変換を連結します。
- グラフィックスコンテキストを box パラメータで指定された長方形にクリップします。 CGPDFPageGetBoxRect 関数は、指定した定数(kCGPDFMediaBox、kCGPDFCropBox、kCGPDFBleedBox、kCGPDFTrimBox、または kCGPDFArtBox) に関連したページ境界ボックス(media, crop, bleed, trim, and art boxes) を取得します。
- PDF ページを、変換され、クリップされたコンテキストに描画します。
- グラフィックス状態を復元します。
PDF ファイルの作成
Quartz 2D を使用して PDF ファイルを作成するのは、グラフィックスコンテキストに描画するのと同じくらい簡単です。PDF ファイルの位置を指定し、PDF グラフィックスコンテキストを設定し、任意のグラフィックスコンテキストに使用したのと同じ描画ルーチンを使用します。リスト 13-4 に示した MyCreatePDFFile 関数は、コードが PDF ファイルを作成するために実行するすべてのタスクを示しています。各番号付きコード行の詳細な説明は、リストの後に示します。
このコードは、CGPDFContextBeginPage と CGPDFContextEndPage 関数を呼び出して PDF ページを記述していることに注意してください。CFDictionary オブジェクトを渡すと、media、 crop、 bleed、 trim、 及び art boxes を含むページプロパティを指定できます。辞書キー定数のリストとそれぞれの詳細な説明については、CGPDFContext リファレンス を参照してください。
リスト 13-4 PDF ファイルの作成
void MyCreatePDFFile (CGRect pageRect, const char *filename)// 1 { CGContextRef pdfContext; CFStringRef path; CFURLRef url; CFDataRef boxData = NULL; CFMutableDictionaryRef myDictionary = NULL; CFMutableDictionaryRef pageDictionary = NULL; path = CFStringCreateWithCString (NULL, filename, // 2 kCFStringEncodingUTF8); url = CFURLCreateWithFileSystemPath (NULL, path, // 3 kCFURLPOSIXPathStyle, 0); CFRelease (path); myDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // 4 CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File")); CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name")); pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary); // 5 CFRelease(myDictionary); CFRelease(url); pageDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // 6 boxData = CFDataCreate(NULL,(const UInt8 *)&pageRect, sizeof (CGRect)); CFDictionarySetValue(pageDictionary, kCGPDFContextMediaBox, boxData); CGPDFContextBeginPage (pdfContext, pageDictionary); // 7 myDrawContent (pdfContext);// 8 CGPDFContextEndPage (pdfContext);// 9 CGContextRelease (pdfContext);// 10 CFRelease(pageDictionary); // 11 CFRelease(boxData); }
コードの動作は以下の通りです:
- PDF ページのサイズとファイル名を指定する文字列を指定する長方形をパラメータとして取ります。
- MyCreatePDFFile 関数に渡されたファイル名から CFString オブジェクトを作成します。
- CFString オブジェクトから CFURL オブジェクトを作成します。
- メタデータを保持するため空の CFDictionary オブジェクトを作成します。次の 2 行は、タイトルとクリエーターを追加します。CFDictionarySetValue 関数を使用して、必要な数だけキー値ペアを追加できます。辞書の作成の詳細については、CFDictionary リファレンス を参照してください。
- 以下の 3 つのパラメータを渡して、PDF グラフィックスコンテキストを作成します:
- PDF データの位置を指定する CFURL オブジェクト。
- PDF ページのデフォルトのサイズと位置を定義する長方形へのポインタ。長方形の原点は、通常(0、0) です。Quartz はこの長方形をページメディアボックスのデフォルトの境界として使用します。NULL を渡すと、Quartz はデフォルトのページサイズを 8.5 x 11 インチ(612 x 792 ポイント) にします。
- PDF メタデータを含む CFDictionary オブジェクト。追加するメタデータがない場合は NULL を渡します。
出力インテントオプション-インテントのサブタイプ、条件、条件 ID、レジストリ名、出力先プロファイル、および意図したターゲットデバイスまたは生産条件に関する追加情報またはコメントを含む人間が判読可能なテキスト文字列を指定するには、CFDictionary オブジェクトを使用します。出力インテントオプションの詳細については、CGPDFContext リファレンス を参照してください。 - PDF ページのページボックスを保持する CFDictionary オブジェクトを作成します。この例では、メディアボックスを設定します。
- ページの開始を知らせます。複数のページ(PDF など) をサポートするグラフィックスコンテキストを使用する場合は、CGPDFContextBeginPage を CGPDFContextEndPage とともに呼び出して、出力内のページ境界を区切ります。各ページは、CGPDFContextBeginPage と CGPDFContextEndPage の呼び出しで囲まなければなりません。Quartz は、ページベースのコンテキストのページ境界外で実行されるすべての描画操作を無視します。
- アプリケーション定義の関数を呼び出して、PDF コンテキストにコンテンツを描画します。ここで描画ルーチンを提供します。
- ページベースのグラフィックスコンテキストでページの終わりを通知します。
- PDF コンテキストを解放します。
- ページ辞書を解放します。
リンクの追加
作成した PDF コンテキストにリンクやアンカーを追加できます。Quartz は 3 つの関数を提供し、それぞれの関数は、PDF グラフィックスコンテキストをパラメータとしてリンクに関する情報と共に取ります。
- CGPDFContextSetURLForRect を使用すると、ユーザーが現在の PDF ページ内の長方形をクリックしたときに開く URL を指定できます。
- CGPDFContextSetDestinationForRect を使用すると、ユーザーが現在の PDF ページ内の長方形をクリックしたときにジャンプする宛先を設定できます。宛先名を指定しなければなりません。
- CGPDFContextAddDestinationAtPoint を使用すると、ユーザーが現在の PDF ページ内の点をクリックしたときにジャンプする宛先を設定できます。宛先名を指定しなければなりません。
PDF コンテンツの保護
PDF コンテンツを保護するために、CGPDFContextCreate 関数に渡す補助辞書に指定できるセキュリティのオプションがいくつかあります。補助辞書に以下のキーを含めることで、所有者のパスワード、ユーザーのパスワード、PDF が印刷可か、またはコピー可かを設定できます。
- kCGPDFContextOwnerPassword:PDF 文書の所有者パスワードを定義します。このキーが指定されている場合、文書は所有者のパスワードとして値を使用して暗号化されています。それ以外の場合は、文書は暗号化されません。このキーの値は、ASCII コードで表現できる CFString オブジェクトでなければなりません。最初の 32 バイトのみがパスワードとして使用されます。このキーのデフォルト値はありません。このキーの値を ASCII で表すことができない場合、文書は作成されず、作成関数は NULL を返します。Quartz は 40 ビットの暗号化を使用します。
- kCGPDFContextUserPassword:PDF 文書のユーザーパスワードを定義します。文書が暗号化されている場合、このキーの値は文書のユーザーパスワードです。指定しない場合、ユーザーパスワードは空の文字列です。このキーの値は、ASCII コードで表現できる CFString オブジェクトでなければなりません。最初の 32 バイトのみがパスワードとして使用されます。このキーの値を ASCII で表すことができない場合、文書は作成されず、作成関数は NULL を返します。
- kCGPDFContextAllowsPrinting は、ユーザーパスワードでロックを解除したときに文書を印刷できるかどうかを指定します。このキーの値は、CFBoolean オブジェクトでなければなりません。このキーのデフォルト値は kCFBooleanTrue です。
- kCGPDFContextAllowsCopying は、ユーザーパスワードでロックを解除したときに文書をコピーできるかどうかを指定します。このキーの値は、CFBoolean オブジェクトでなければなりません。このキーのデフォルト値は kCFBooleanTrue です。
リスト 14-4 (次の章) は、PDF 文書がロックされているかどうかを確認するコードを示しており、ロックされている場合は、パスワードで文書を開こうとします。
前の章 次の章