PDFの基本的構造について
とうとう梅雨が開けてしまいましたって書き出しで用意した記事が残暑に出てくるというのはいかがなものかといわれるとなんとも恐縮至極なのですが、通勤途上は地獄のような暑さです。これは、通勤という行為を止めなければ生命に危機が及んでしまうレベルです。皆様におかれましては各種対策を行いつつ行動されていると存じます。わたしどもに関しましても保冷剤を首筋に巻いて強制的に冷却しながら通っている状態ですが、もう少し大型のものが必要かもしれません。まあ、Covid-19の事もありますのでお外に出ること自体が(ry
もうひとつお知らせすると、mRNAキャリアーを投入してきました〜(^-^)/ 局所的な筋肉痛が生じた状態ですが、発熱などはなく元気いっぱいです。ファイザーすげ〜w
まあ、どうでもいいような事を書き連ねているとものかの先生に読み飛ばし推奨認定されてしまいます(読んでほしいから書いてます)ので、これぐらいで控えさせていただきたいと思う次第ですが、本日お届けするのはIllustratorがPDFを書き出す際の基本的な挙動の検証ということです。過日のモリオ先生のTweetでテキストに付加した線が塗りとズレが生じるという指摘があったので細かいところを検証し評価する事にしました。
まずはターゲット情報を
- Illustrator CC ver.25.2.4/ja_JP
- 小塚ゴシックPr6N/12pt、線幅0.01mm、塗り・線共にK100として設定してあります。
このようにテスト用に文字数を減らしてあります。
このドキュメントをPDF1.7、Illustratorの編集機能を保持した状態(PGFを含めた状態で保存)します。これで準備完了です。
ではテキストに対して指定した線はどの様にPDFに展開されるのかを見ていきましょう。
PDFの内部構造を参照する場合バイナリエディタでにらめっこしたり自前でツール書いたりします。うそです。そんな事する人は居ません……多分居ないと思う……ええ、やりましたよ(^-^;
そんなことはどうでもいいんです。PDFの構造を参照する最適解はAcrobatDC Proのプリフライトパネルを使うです。
IllustratorデータをPDFに含めたのは単純に後でIllustratorで開けるようにと言う意図ですが、IllustratorのプライベートデータであるPGFデータはどの様に保持されているかの見本でもあります。以下のようにPDF構造に影響しない様に配置されます。
このプライベートデータはPDFをレンダリングする際に完全に無視されます。ここで使用されるのはPage Piece Dictionaryと呼ばれるものでPDF 1.4以降に書き出し元アプリケーションがプライベート情報をPDFに埋め込むために用意された仕組みです。Acrobat等がPDFを表示する際には無視されます。
本題に戻りましょう。
頭からざっと説明するとMetadataはXMLで構成されたメタ情報が記述されています。XMP Metadataという方が通りは良いですね。続いてOCPropertiesはOptional Contents Propertiesでオプショナルな情報が含められています。OutputIntentsはプリントアウトなんかで利用するプロファイル等の情報が含まれます。以上の情報は今回は説明しません。
つづいて出てくるのがPagesこちらが今回の本命です。
これを展開するとCountというのが見えます。これは子要素であるKidsがPages以下にいくつあるかを示しています。直接ページ数を表すわけではないところがややこしいところです。
続いて子要素Kidsを見ていきます。これも同様に直接コンテンツが含まれる状態ではなく、PDFファイルの規模によってはいくつかのページグループとなるような塊をいくつかの階層に分けた構造で構成されたりします。今回の例では1ページだけのデータですからPagesに含まれるKidsは1つだけです。これを展開してみるとKids直下にContentsが含まれます。実際のデータはContents以下に含まれるコンテンツストリームに含まれる事となります。この様な階層構造はランダムアクセス性を保持するためのものです。
さて、ここからが本番です。
面倒なのでスクショに注釈をつけてみました。
コンテンツストリームを展開しテキストを構成している部分を見てみます。
BT
BTコマンドはBegin Textでテキストストリームの開始を宣言します。このコマンドはオペランドを取りません。続くkはストローク無しのCMYKの塗り、コマンドであるkの前には4つのオペランドが並びます。PDFの構文はこの様にコマンドに付随するパラメータがコマンドの前に並べられる逆ポーランド記法で記述されるのが特徴です。ここがPostscriptのスーパーセットとして開発された所以です。
0 0 0 1 k
kはDevice CMYKでの塗り設定、パラメータはCMYKの順にならんで0〜1.0のレンジで表されます。
/Perceptual ri
riはレンダリングインテント指定でPerceptualは知覚的なレンダリング処理となります。
/GS0 gs
gsはExtend GStateでResourceに記述されたGS0にリンクします。これは不透明マスクやオーバープリント等設定が含まれますが、今回は解説しません。
/C0_0 1 Tf
TfはText Formatを示し、基本的な指示以外が別途参照として分離されます。
こういった参照に利用されるのがname文字列でスラッシュが目印になり、参照の際のラベルになります。
12 0 0 12 18.5039 829.833984375 Tm
TmはText Marixです。パラメータ構造はアフィン変換用の行列となります。
(\000")Tj
TjはText Runを意味しテキストを表示します。テキストの内容が括弧内なのですが、マルチバイトの場合はバックスラッシュでエスケープされた文字コードとなります。ここで注意が必要なのはここで利用される文字コード自体がカスタム化されたもので、フォントサブセットを生成した際に生成される情報を基に参照して適切なグリフを表示します。
ET
ETはEnd Textでテキスト部分はこれで終了となります。
q
グラフィックステートはq〜Qに構造が記述されます。またグラフィック自体が子要素を保つ場合、入れ子状態になります。
0 858.898010253 612.28302 -858.898010253 re
reはRectangleで四角形を構成します。引数として始点と幅及び高さの4つのパラメータを取ります。
W
Wコマンドは当該グラフィック要素がクリッピングパスであることを示します。
n
nはnon Fill and Strokeでグラフィック要素を閉じます。
0 0 0 1 K
KはCMYKスロトークカラーで各パラメータはCMYKの順で並び0.0〜1.0の範囲の値を取ります。
.028 w
wはStroke Weightですから線幅です。この様に小数点以下の実数は頭の0が省略されます。
q
ここからが実際の子要素のストロークオブジェクトの記述となります。子要素に入ってもそれ以前に設定されたグラフィックステートは継承されます。ですから、線の設定などは子要素に入る前に記述されます。
また、PDFをIllustratorで書き出してから開くとよく分かると思いますが、オブジェクトが1つのものをPDF化したものであってもアートボードサイズのマスクがかかります。ここで見ている構造はその状態を表しています。
続きます。
1 0 0 1 23.04 838.978027343 cm
cmはこのストローク要素に対するアフィン変換用の行列です。この様にオブジェクトに対しての変換行列が用意されてグローバルな位置関係が定義されるのが特徴的な構造でもあります。
以下、実際のストロークの記述となります。
0 0 m
mはmovetoでカレントポジションの位置を移動します。この位置は先の行列のパラメータで与えられた位置からの変化量として記述されます。
-1.152 0 l
lはlinetoでカレントポジションからパラメータで指定された移動量の位置へ直線を引きます。
-4.176 -9.144 l
-3.155999898 -9.144 l
-2.196 -6.17999828 l
1.968 -9.144 l
3.024 -9.144 l
順次線をつないで行きます。
h
hでパスをクローズします。
-1.992 -5.388 m
同様にカレントポジションを移動し次のストロークを開始します。これは「A」の内側のパスの描画になります。
-1.08 -2.64 l
線を引き…
-.912 -2.063999891 -.744 -1.488 -.624 -.936 c
cはcurvetoで曲線を構成する6つのパラメータを取ります。これは前のアンカーの右ハンドル、次のアンカーの左ハンドル、そして次のアンカーの位置のベジェ曲線のパラメータとなります。
-.588 -.936 l
-.468 -1.476 -.312 -2.052 -.12 -2.676 c
.78 -5.388 l
同様にストロークをつないで…
h
最後にhでクローズ
s
ここまでのパラメータと設定を利用してストロークを発生させるのがsコマンドです。
Q
EMC
Q
以上がテキストに線を指定した際の挙動となります。ご覧いただいた様にテキスト自体は埋め込まれたフォントに内包するグリフ情報からレンダリングされますが、設定された線はPDFとしてはアプリケーション上でグリフから抽出したベクトル情報として保存されます。
これが、意味することは、PDFを表示するプラットフォームよってフォントレンダリングと展開された状態で保持されているストロークは完全には一致しないという事になります。微小な演算誤差結果でも行長が長くなると最後の文字ではアウトラインがずれるといった事が起きる可能性があります。
この様な構成が含まれるデータはむしろテキストをアウトライン化した方が安全な場合も出てくるでしょう。
最後に告知です。現在PDFの解説を書いてます。アホみたいにボリュームがある1.7のをベースにしたもので難航していますが気長にお待ち下さい。
こんな感じのやつですね。この部分はExtGStateディクショナリのパラメータ解説の章となります。かなり端折っていますが基本的な構造を紐解くには充分な内容になります。