CL-PDF と ZPB-TTF の擴張

* きっかけ

文書生成にCL-PDFを利用させてもらふやうになつて久しいが、ある日某部門から、特定のPDFリーダ (Adobe AcrobatReader) で文字化けせずにテキストをcopy/pasteできるやうにとの要請を受けた。
ghostscriptを使ってpdf壓縮をすると、サイズは小さくはなるのだが、copy/pasteしたときに一部テキストが文字化けする。
とくにIPAMinchoを埋込んだ部分は壓縮前であつても文字化けする。[]
これは Google Chrome や Safari でも同樣。ただし、Microsoft Edge や FireFox などでは、文字化けせずにcopy/pasteが出來る。

* pdf2text

一部browserでは文字化けしないのだから、文字化けする方に技術的不具合があることは容易に想像できるが、これを證明するために自分でpdf2text處理をprogramしてみた。
一部ブラウザは =/Encoding /Identity-H= 指定されてゐるとテキストを拾へないやうだ。
=/CIDSystemInfo==/Ordering(UCS)= とあるのだから、 UCS2 か UCS4 のコードだと思って解釋できさうなものだし、事實拾へるブラウザもあるわけだが、自分で書いたコードでは UCS2 として解釋しテキスト抽出に成功させた。

CL-USER(93): (pdf:pdf2text "~/project/cl-pdf/PDFs/Identity-H.pdf")
;; Inside non-filter file
#<EQL hash-table with 1 entry @ #x1042bdf32>
("いろはにほへどちりぬるをあさきゆめみしゑひもせすわがよたれぞつねならむわがよたれぞつねならむ.....")

* Encoding

さうかうするうちに、 =/Encoding /UniJIS-UTF16-H= としてやれば、ブラウザの如何にかかはらず、テキスト抽出が出來る事に氣付いた。
ただし、 =/Identity-H==/UniJIS-UTF16-H= に置換へるだけでは cl-pdf が吐出す cidmap が =/Ordering(Japan1)= のオーダーになってゐないので、竝び換へが必要である。これを =read-ipa-file= で實現した。[iroha.pdf]

* フォント壓縮

CL-PDF で IPAMincho を使って、かつ、テキスト copy/paste が出來るといふ要求には答へることができたが、未だサイズが大きい。
フォント壓縮に ghostscript を利用すると、一部ブラウザでの一部文字の文字化けが置こる。とくに半角カナが拾へない。これは自分で書いたprogramでもedgeなど文字化けしないブラウザでも同じで、今のところ原因は追及してゐないが、IPAMinchoの埋め込みフォントだけでも壓縮できれば、サイズ輕減の上で ghostscript には及ばずながら、要求元部門は默らせることができさうである。

* zlib

CL-PDFではzlibを使ってstreamオブジェクトを壓縮する方法が提供されてゐる
今迄宛ってこなかったが、この方式でどの程度壓縮することができるのが見てみると、zlib無(8361590)に對して zlib有(5914565)と、多少の輕減はあるものの、MByteのオーダは變はらない。

* zpb-ttf

CL-PDFではzpb-ttfといふ ttf font loader を利用してゐるが、このloaderを解析し、loadしたfontを逆にdumpできれば、解決の絲口となるかと思ひ、ひと先づ、loadしたものと全く同じものをdumpできるやう、zpb-ttfを擴張した

* cmap

次に、IPAMincho には三つの cmap が定義されてゐるが、 cmap table のうち、UCS2 のものだけdumpし、他は無視しても、埋め込みフォントとしては問題のないことを確認した。

* glyph

しかし、これだけだと、せいぜい 1Mbyte 程度の削減にしかならない。
そこで本來の目標であった、glyphを減らす作業にとりかかった。
先づ試みたのは、埋め込むfontのファイルサイズはそのまま(cmap二つ分だけの輕減)とし、不要なglyphはnullで埋めて、必要なglyphだけを書出すといふ方法である。
glyphの大部分をnullで埋めておけばzlibがdeflateの際に縮めてくれるだらう、といふ期待である。
この方法でつくったPDFが、ghostviewで壓縮したサイズには遥かに及ばないものの、元々の大きさの 1/20 程度まで縮めることが出來た。iroha-font-subset-v1.pdf

* =/W=

=/FontDescriptor= が持つ =/W= のサイズが大きい。
現状154501に比べGhostscript版は437byte。これだけで150Kは縮まる。
幸、IPAMinchoはプロポーショナルフォントではないので、Widthは全角1000か半角500しか存在しない。
數の多い全角characterをCL-PDFが持つ width array から除去し、半角のものだけを集めると、數にして225しか存在せず、 =/W= の大きさを276byteまで縮めることが出來た。以上によりPDFの大きさを元々の 1/30 以下に壓縮できた。iroha-font-subset-v2.pdf(239512)

* 更なる壓縮

ghostscriptで壓縮をかけたファイルの中身を見ると =cmap= 他 (=GDEF= =GSUB= =OS/2= =gasp= =name=) のtableが存在せず、また、使はれないglyfは、 =number-of-contours==0= として =end-pts-of-contours= 以下を省いてある。
さらに、使はれないcharacterの =CIDToGIDMap= はnull埋めすることで壓縮效率が増すやうな工夫がされてゐた。
上に倣ひ、不要なtableをdumpするのをやめglyfのdumpを改め、さらに利用されない =CIDToGIDMap= をnull埋めすることで、1/70 程度までの壓縮に成功した。iroha-font-subset-v3.pdf

* 更なる更なる壓縮

ghostscriptで壓縮をかけたファイルと比べ、 =loca= =hmtx= =vmtx= のtableサイズが目立って大きい。
=loca= に置いてはindexをshortで持つかlongで持つか (shortの場合は値を2で割って持つ) の違ひが大きさに關係するが、その判斷は、 =head= tableで指定されてゐる。IPAMinchoではlongで持ってゐたが、これをshortにすることで、25Kほどが節約できた。
また、metrics情報 =hmtx= =vmtx= は、glyphの數だけ情報があれば好いやうなので、これを font index の最大値に押さへ、結果、1/90 以上の壓縮に成功した。iroha-font-subset-v4.pdf

* FontSubsetの命名規則

Adobeの仕樣によれば、FontSubset には、Capital 6文字に =+= を加へた prefix を付けてやらないといけないので、それに對應した。iroha-font-subset-v5.pdf

: /BaseFont /IPAMincho

ではなくて、

: /BaseFont /TYGDXA+IPAMincho

のやうに。

これは以前横田に指摘されてゐたが放っておいたのを仕樣に副ふやうに改めた。

* 埋め込みフォントの除去

埋め込みフォントの除去ができるやうにした。

CL-USER(96): (pdf:remove-embedded-fonts "~/project/cl-pdf/PDFs/iroha.pdf" "temp.pdf")
#P"temp.pdf"

のやうに使ふ。

CL-USER(97): (list (file-length "~/project/cl-pdf/PDFs/iroha.pdf") (file-length "temp.pdf"))
(8361590 314905)

ファイルサイズがあまり減つてゐないのは、FontFile2を除去しただけで、CIDtoGIDMapが未だそのまま殘つてゐるせゐである。

* MSフォントの壓縮

ExcelがSaveAsで吐くPDFには無駄が多いやうだ。
FontFile2を節約すれば小さくできるのではと取掛る。
MS-Gothic, MS-Mincho, MS-PGothic と MS-PMinchoのFontFile2から餘分なtableを除くだけで50%以上の壓縮が出來る。
ただし、半角英數字が表示されないといふ問題に遭遇。
cmap table を入れてやるとうまく出た。何故cmapが必用なのかは解らない。 (GS版にcmapは存在しない)

: CL-USER(525): (pdf::compress-pdf-fonts "1-1-1.pdf" "1-1-1-compress.pdf")
: CL-USER(526): (list (file-length "1-1-1.pdf") (file-length "1-1-1-compress.pdf"))
: (520528 259549)

不要なglyphを削ればさらに壓縮できるかも知れないと、やってみたが、ほとんどサイズは變化せず、しかも、未だ縱書きをサポートしてゐないため、問題が出る。

縦書きに對應し、ghostscriptを眞似て、フォントを一つにまとめてやれば、さらなる壓縮ができる筈だが…

Comments

Popular posts from this blog

Common Lisp コーディングスタイルについて

The Art of the Metaobject Protocol を讀む

Hyperspec を讀む