最近、PDFへのフォント埋め込みで気になることがあったので、フォントについて少し調べてみました。
はじめに
先日、故あってOpenTypeフォントがWindowsで使えるかを調べてみたところ、Google社がオープンソースで展開しているNoto Sans JPフォントをMicrosoft Wordで使用すると正常なPDFを作成することができない場合があることがわかりました。
試した環境 (Windows 10 Home 64ビット 20H2 + Microsoft Word 2107) でNoto Sans JPフォントを使用した文書を作成し、以下の手順でPDFを作成しました。
まず、Wordの標準機能であるエクスポートの「PDF/XPSドキュメントの作成」を使用すると、OpenTypeフォントで作成されたテキストはラスター画像に変換され、テキストデータはPDFに記録されないようです。
サードパーティー製であってもTrueTypeフォントはテキストデータとしてPDFに記録されますが、他のOpenTypeフォントでもテキストがラスター画像化されるため、WordのPDFエクスポート機能はOpenTypeフォントの埋め込みに対応していないようです。
ところで、細かいことを言うとOpenTypeフォントにTrueType形式も含まれますが、ここでは便宜的にCFF形式のOpenTypeフォントをOpenTypeフォント、TrueType形式のOpenTypeフォントをTrueTypeフォントと呼ぶことにします。
次にWindows 10の機能として提供されているMicrosoft Print to PDFというPDFファイルを出力するプリンタードライバーを使用してWordからPDFを作成してみました。
出力されたPDFファイルは文字化けを起こして全く読めないものになりましたが、Acrobat Reader上でテキストを選択してコピーし、テキストエディタ (メモ帳) にペーストすると正しいテキストがペーストされたので、ファイル上の文字コードは正しいけれどもそれに対応する文字が表示されていないことがわかりました。
別のPDF作成ツールとしてCube Soft社が無償配布しているCubePDFというPDFを作成するプリンタードライバーを使用してみました。
こちらで作成したPDFファイルはきちんと読むことができますが、Acrobat Readerを使用してテキストのコピー・ペーストを行うと不正なテキストがペーストされ、外見は政党にもかかわらず文字コードが不正になっている可能性があることがわかりました。
なお、同じファイルをmacOS版Wordで開き、macOSのPDF出力機能を使用してPDF化した場合も同様にテキストのコピー・ペースが正しくできなかったため、この現象はCubePDFに起因して起きているのではなく、フォントまたはWordに起因した現象と考えられます。
また、他のOpenTypeフォントではMicrosoft Print to PDFとCubePDFのどちらでも文字化けせず、コピー・ペーストも正常に実行できるPDFデータが作成できたので、今回の現象はOpenTypeフォント一般の事象ではなく、フォントに依存して発生する現象であると考えられます。
ということで、とりあえずフォントとPDFについて調べてみることにしました。
CIDとcmap
今回の現象の原因として考えられるのはOpenTypeフォント (とTrueTypeフォント) が文字コードと字形データを分離していることと思われます。
アプリケーションはテキストデータをUnicodeやシフトJISなどの文字コードで保持しています。
画面上に文字を表示する際にはフォントデータから文字コードに対応する字形データを取り出し、画像化して画面に出力します。
ところで、歴史的な理由によりWindowsの場合、アプリケーションからシステムに渡される文字コードにはシフトJIS系の文字コードとUnicode系の文字コードがあります。
また、長音記号「ー」のように縦書きと横書きで字形の異なる文字があります。
さらに日本語にはありませんが、ラテン系文字であれば「ff」や「fi」のように特定の文字並びに専用の文字を使用する合字やアラビア系の文字のように文字の並びに応じて字形が変化するものがあります。
こういった文字を表現できるようにOpenTypeフォントやTrueTypeフォントでは文字コードと字形を分離して、個々の字形に対してCID (TrueTypeフォントの場合はグリフIDと呼ぶようですが、面倒なのでまとめてCIDと呼んでおきます) というコードを割り当て、文字コードと該当するCIDの関係を記したテーブルであるcmapを用意しています。
システムは使用している文字コード、縦書き横書きの区別をもとに対応するcmapテーブルを参照して文字コードからCIDを決定し、CIDから字形データを取得するという2段階で表示を行う仕組みになっています。
印刷とフォント埋め込み
OpenTypeフォントやTrueTypeフォントは仕様が公開されているので、プリンターの解像度や機能に合わせて最適化した専用の画像生成処理を実現することができます。
この場合、フォントデータの一部を埋め込みフォントとして印刷データに組み込むことが行われます。
こういった場合には文字コードを保存しておく必要はないため、cmapを使用せずにCIDを直接文字コードとして使用することが可能です。
例えばPostScriptやPDFではプリンタードライバーがCIDを文字コードとして印刷データを生成しているようで、PDFファイルをAcrobatで開いてプロパティからフォントを確認するとエンコーディングがIdentity-H (またはIdentity-V) になっています。
Identityエンコーディングを使用するとcmapによるコード変換を省略できること、cmapの選択が不要になる、さらにはcmapを埋め込む必要がなくなる点が利点になると考えられます。
PDFにおける特別な要求
ところで、PDFは単純な印刷データとしてレイアウトやページ画像を再現できるだけではなく、文書データとして文字列の検索やコピー・ペーストができることが求められます。
この要求を実現する方法はいくつか考えられますが、PDFではCIDからUnicodeに変換するテーブル (ToUnicode cmap) を埋め込みフォントに追加することで実現しています。
このような形式を採用したのはおそらく、PDF中のテキスト表現をUnicodeに限定するとUnicodeでコード化されていない文字の扱いが難しくなり、印刷データのレイアウト再現が困難になるためと推測できます。
Noto Sans JPで発生している事象
Noto Sans JPで発生している事象は2種類、画面上は文字化けしていないが、コピー・ペーストで得られる文字列のコードが不正になっていると、画面上文字化けしているが、コピー・ペーストでは正しい文字コードが得られるがあります。
それぞれのPDFがどのようになっているかを確認しました。
macOS版のWordからmacOSのPDF出力機能を使用して出力したファイルのコンテントストリームは以下のようになっていました。
/C1 1 Tf <4efc5116338147a35ace> Tj
最初の "/C1 1 Tf" はフォントを選択、次の "<4efc5116338147a35ace> Tj" はテキスト出力で、4EFC、5116、3381、47A3、5ACEのコードで示される5個の文字を出力しています。
これはCubePDFで出力したPDFでも同じコードが出力されていた (文字コードが16進表現ではなくバイナリデータになっているなど、若干の違いはありましたが) ので、CIDコードとして正しいものだと思われます。
これに対してMicrosoft Print to PDFで出力したPDFではコンテントストリームが以下のようになっていました。
[<18AF><199B><0F4C>10.000000<160B><1D4B>] TJ
"TJ" は字間の調整を含むテキスト出力で、数値を除く18AF、199B、0F4C、160B、1D4Bの5個が文字コードとして出力されています。
フォントは同じものを使用しているので、これらの文字コードは該当する文字のCIDと一致していないと考えられ、それが文字化けの原因となっているようです (一応念のためですが、これらのコードは該当する文字のUnicodeあるいはシフトJISコードとも一致しません)。
ところで、これら3種のPDFのToUnicode cmapを確認すると、以下のような結果でした。
まず、CubePDFですが、ToUnicode cmapには4文字しか登録されていませんでした。
次にmacOSのPDF出力機能を使用して出力したPDFのToUnicode cmapを確認すると、Microsoft Print to PDFのコンテントストリームに出現したコード5個が先に挙げた5個の文字のUnicodeに対応するコードとして記録されていました。
また、Microsoft Print to PDFで作成したPDFのToUnicode cmapにも同じく18AF、199B、0F4C、160B、1D4Bの5個のCIDに対して期待されるUnicode値が書かれていました。
ここからNoto Sans JPに含まれているUnicode cmapに何らかの問題があること、CubePDFやmacOSのPDF出力機能はUnicode cmap以外のcmapを使用して文字描画を行っているため、正常のCIDが出力されていることが推測されます。
ということで、次はNoto Sans JPのcmapを調査するフェーズに入るのですが、cmapを調査するための環境を用意できていないため、続きはそのうちにとさせてください。
使用した文書・ツール
参考として今回の調査で使用した文書・ツールを紹介しておきます。
仕様書類
PDF仕様はAdobe社が配布している「PDF Reference version 1.7」を参考にしています。
PDF仕様の開発、管理がISOに移管されたためか、現在Adobe社公式サイトのトップページからダウンロードページまでたどることはとても難しいので、検索等を使用して入手するか、有償になりますがISOからの入手を検討してください。
OpenTypeフォント仕様はマイクロソフト社公式サイトのWindowsデベロッパーDocsサイトにある以下のURLで参照できます。
https://docs.microsoft.com/en-us/typography/opentype/spec/
CFF形式の字形データの詳細はAdobe社のドキュメント参照するようになっていますが、今回は字形データにまでは踏み込んでいないので、内容は確認していません。
ツール
PDFデータの確認にはiText社<https://itextpdf.com/en>がオープンソースで提供しているRUPS <https://github.com/itext/i7j-rups>を使用しています。
RUPSはPDFオブジェクトのツリー表示、ページオブジェクトのリスト表示、圧縮ストリームのテキスト出力などの機能があり、PDFデータの出力障害に対する原因調査に使えそうです。
PDFに関連する動作確認やテストを行う場合は本来PDFデータの生成にAdobe Acrobatとともに提供されるAdobe PDF WriterおよびAdobe PDF Makerアドインを本来使用すべきですが、諸般の事情により今回はCubeSoft社<https://www.cube-soft.jp/>がオープンソースで展開しているCubePDFを使用しました。
以上、あまり情報はありませんが、何か参考になれば幸いです。
bewise.jp - 2021年8月5日の投稿の再投稿
0 件のコメント:
コメントを投稿