Hatena::ブログ(Diary)

マクロツイーター このページをアンテナに追加 RSSフィード Twitter

2016-05-21

xdvipdfmx がうまくいきません

PDFタイトルで🍣するとアレ

以前の記事で述べたように、XeTeX(xdvipdfmx)の既定の動作*1では、pdf:docview special などで与えられる「PDF の文書情報の文字列」について、UTF-8 → UTF-16BE の変換を行う。

% plain XeTeX 文書, 文字コードUTF-8
\special{pdf:minorversion 4}% オブジェクト圧縮を回避
\special{pdf:docinfo << /Title (☃) >>}% U+2603 SNOWMAN
\nopagenumbers \null \bye

(文書情報のオブジェクト*2

2 0 obj
<<
  /Creator ( XeTeX output 2016.05.21:1924)
  /Title <feff2603> % UTF-16BE に変換済
  /Producer (xdvipdfmx \(20150315\))/CreationDate(D:20160521192429+09'00')
>>
endobj

もちろん、“UTF-16BE に”変換しているので、BMP 外の文字があっても大丈夫……。

% plain XeTeX 文書, 文字コードUTF-8
\special{pdf:minorversion 4}
\special{pdf:docinfo << /Title (🍣) >>}% U+1F363 SUSHI
\nopagenumbers \null \bye
2 0 obj
<<
  /Creator ( XeTeX output 2016.05.21:1929)
  /Title <feffdf63d83c>
  /Producer (xdvipdfmx \(20150315\))/CreationDate(D:20160521192940+09'00')
>>
endobj

……アレ?

/Title <feffdf63d83c> % UTF-16BE…?

アレアレ??

df63d83c

違う! これだとサロゲートペアの値の順番が逆!

そういうわけで、この文書の Adobe Reader で開いて文書情報を見てもタイトルの🍣は正常に表示されない。

当該の部分のソース(spc_pdfm.c の 500 行目付近)を見てみると……あれまあ。

    if (usv > 0xFFFF) {
      /* supplementary-plane character: generate high surrogate */
      unsigned long hi = 0xdc00 + (usv - 0x10000) % 0x0400;   /*←これは low surrogate!*/
      if (op > wbuf + WBUF_SIZE - 2)
        return -1; /* out of space */
      *op++ = hi / 256;
      *op++ = hi % 256;
      usv = 0xd800 + (usv - 0x10000) / 0x0400;                /*←これは high surrogate!*/
      /* remaining value in usv is the low surrogate */
    }
    if (op > wbuf + WBUF_SIZE - 2)
      return -1; /* out of space */
    *op++ = usv / 256;
    *op++ = usv % 256;

なお、このバグについては、r39201 [2015/12/26] においてリファクタリングが行われるのに巻き込まれて(いつの間にか?)直ったらしい。従って、もうすぐリリースされる TeX Live 2016 では正常になっているはずである。

LaTeX では問題なし

ちなみに、このバグの影響範囲であるが。

  • up(La)TeX + dvipdfmx で UTF-8 → UTF-16BE の文字コード変換を行う場合は「pdf:tounicode UTF8-UTF16」の special 実行が必須であり、この場合は ToUnicode CMap の適用の処理が行われる。
  • XeLaTeX で hyperref パッケージを用いる場合は、hyperref 自体が(TeX 言語で)UTF-8 → UTF-16BE の変換を 行うので、xdvipdfmx の変換処理は使われない。

そういうわけで、LaTeX の範囲においてはこのバグを踏むことはほぼ無いといっていいだろう。

*1pdf:tounicode special が指定されない場合。

*2:見やすさのため整形して示している。

2016-05-17

TeX と 20 年戦ってわかったこと

f:id:zrbabbler:20160517232819p:image:w240

というわけで……

改めて。

TeX と 20 年戦ってわかったこと

f:id:zrbabbler:20160517232818p:image:w260

以上。

2016-05-04

LaTeX でもっともっとカラー絵文字する話(bxcoloremoji v0.3a)

upLaTeX 以外でもカラー絵文字できる bxcoloremoji パッケージ、を更新してみた。

昨年(2015 年)の年末あたりに Twitter で使えるカラー絵文字が大幅に拡充されて、従来の〈⛄〉(U+26C4 SNOWMAN WITHOUT SNOW)に加えて〈☃〉(U+2603 SNOWMAN)もカラー絵文字で表示されるようになった。

☃のカラー絵文字が登場したのであれば、当然、これを LaTeX でも使えるようにすべきである。というわけで、今まで coloremoji パッケージの画像データを流用する前提だったのを改めて、twemoji のリポジトリ*1から持ってきた画像ファイルを同梱するようにした。デフォルトではこの画像データが用いられる。

% upLaTeX 文書; 文字コードUTF-8
\documentclass[uplatex,dvipdfmx,a4paper]{jsarticle}
\usepackage{graphicx}
\usepackage{bxcoloremoji}% デフォルト設定
\begin{document}
私は\coloremoji{⛄}よりも\coloremoji{☃}が好きです。
\end{document}
f:id:zrbabbler:20160504113955p:image

画像データのセットを選ぶオプションは以下のようになっている。

  • twemoji-pdf: twemoji の PDF 画像。*2
  • twemoji-png: twemoji の 72 ピクセルPNG 画像。
  • twitterlowreshires: これらは従来通り coloremoji パッケージの画像データを流用することを表す。

新しくサポートされた絵文字の中には“肌色調を表す修飾子(modifier)を付したもの”や“ZWJ(U+200D)を用いて複数の文字を組み合わせたもの”のような複雑なものも存在するが、これらも正常に出力される。*3

\coloremoji{%
🖖🏾% 1F596 1F3FE : U+1F596 with Fitzpatrick type-5
👁‍🗨% 1F441 200D 1F5E8 : "Eye in speech bubble" symbol
👨‍👩‍👧‍👧% 1F468 200D 1F469 200D 1F467 200D 1F467 :
    % family of "man + woman + girl + girl"
}
f:id:zrbabbler:20160504113954p:image

縦書き対応

(u)pLaTeX の縦組みモードをサポートした。(どうやら今までサポートしてなかったらしい。)

% pLaTeX 文書; 文字コードUTF-8
\documentclass[dvipdfmx,a4paper]{jsarticle}
\usepackage[utf8]{inputenc}% *pLaTeX では*これが要る
\usepackage{graphicx}
\usepackage{bxcoloremoji}
\usepackage{plext}% 組方向拡張
\begin{document}
\parbox<t>{5zw}{夏は\coloremoji{☃}。}
\end{document}
f:id:zrbabbler:20160504113953p:image

LuaTeX-ja の縦組みモードにも対応している。

% LuaLaTeX 文書; 文字コードUTF-8
\documentclass[a4paper]{ltjsarticle}
\usepackage{graphicx}
\usepackage{lltjext}% 組方向拡張
\begin{document}
\parbox<t>{5\zw}{夏は\coloremoji{☃}。}
\end{document}

CJK パッケージ対応

(pdf)LaTeX + CJK パッケージを使う場合に、CJK(*)環境の中でも正常に機能するようになった。従って、BXJS クラス + (pdf)LaTeX の文書でもカラー絵文字が使える。

% pdfLaTeX 文書; 文字コードUTF-8
\documentclass[pdflatex,ja=standard]{bxjsarticle}
\usepackage{graphicx}
\usepackage{bxcoloremoji}
\begin{document}
吾輩は\coloremoji{🍣}である。意味はまだ無い。
\end{document}
f:id:zrbabbler:20160504115248p:image

*1:「Twitter で新たに登場したカラー絵文字」に関しては、今年(2016 年)の 2 月頃に画像ファイルがリポジトリの“2/”というディレクトリの下に公開されている。(たぶんまだ調整中?) なおライセンスは CC-BY 4.0 である。

*2SVG 画像から Inkscape で変換したものである。coloremoji パッケージに同梱されている“twitter”の PDF 画像のセットはイラレのデータ(.ai)そのものであるが、それよりもこちらの方がずっとサイズが小さい。

*3\coloremoji 命令は複数の絵文字の列を引数にとる仕様なので、これを個々の“文字”に区切るのは結構難しい。

2016-04-26

LuaTeX が直接 Type1 する件が結局解らなかった

てきとーに垂れ流したメモ。

luaotfload が新しくなってアレ?

luaotfload v2.7:
* Remove support for builtin Fontforge libraries (this includes the PFA, PFB, DFONT, and feature file readers).

ふむ。ということは、従来(v2.6)の luaotfload は「PFB」(Type1 フォント)をサポートしていたらしい。ということは、実は LuaTeX では OpenType だけでなく、Type1 フォントの“直接”指定ができる(できた)ということなのか。調べてみたけど、何だかよくわからない、という話。

“TFM 経由”と“直接”

新しい TeX エンジンにおいては、フォントの指定方法には次の 2 種類がある。

  • “TFM 経由”: オリジナルの TeX と同じで、TFM ファイル(*.tfm)を用意して、それに物理フォントをマップする、という方法。
    • pdfTeX では PK 形式、PFB 形式(バイナリの Type1)、OpenType 形式(TrueType グリフの形式も含む)がサポートされている。LuaTeX でのサポート状況も同じようなものだろう。
    • この方式で一番よく利用されている形式は PFB(Type1)。
    • TFM が 8 ビット空間を前提にしているので、この方式で定義したフォントは全て 8 ビットになる。マップ行にリエンコード(.enc)が指定されているならそのエンコーディングに、指定されていないならビルトインのエンコーディングになるはず。
  • “直接”: TFM を経由せずに、物理フォントを直接指定する。
    • XeTeX と LuaTeX でのみ使用可能な方法。
    • この方式で定義されたフォントUnicode の符号空間をもつ。
    • 一般的には、OpenType フォント(TrueType グリフのものも含む)について利用される。

実は、LuaTeX はデフォルトでは、少なくともインタフェースとなる \font プリミティブのレベルにおいては、“TFM 経由”の指定しかサポートしていない。そして、XeTeX と同じような“直接”指定を可能にするためのパッケージが luaotfload なのである。

だとすると、「luaotfload が Type1 をサポートする」というのは、何となく、「Type1 フォントの“直接”指定ができる」ことを意味する、ような気がする。

Type1 を“直接”指定したい話

例えば TeX Live に収録されている Times のクローンである「NimbusRomNo9L-Regu」を例に挙げる。

  • PS フォント名は NimbusRomNo9L-Regu。
  • ビルトインのエンコーディングは StandardEncoding(これの Berry 識別子が“8a”)。
  • TeX Live でのファイル名は utmr8a.pfb。
  • TFM ファイル utmr8a.tfm は存在しない
  • TeX では、これを TeXBase1Encoding(Berry 識別子が“8r”)にリエンコードしたものを utmr8r として使っている。
    utmr8r NimbusRomNo9L-Regu " TeXBase1Encoding ReEncodeFont " <8r.enc <utmr8a.pfb
    
    従って、utmr8r.tfm は存在する。

さてこの状態において、

\font\test=utmr8r

とすると、“TFM 経由”(utmr8r.tfm を経由)で NimbusRomNo9L-Regu が指定される。これはアタリマエであり、また pdfTeX と同じ動作である。

しかし、仮に LuaTeX(+ luaotfload v2.6)で Type1 が“直接”指定できるとなると、utmr8r.tfm とは無関係に NimbusRomNo9L-Regu が指定できるはずである。それを実現するにはどうすればいいか。

マニュアルを読むと

luaotfload パッケージのマニュアルにおいては、Type1 フォントを指定する話は、次の 1 ヶ所しか出てこない。

For example, conventional type1 font can be loaded with a file: request like so:
\font\lmromanten={file:ec-lmr10} at 10pt
The luaotfload package: 3.3.1 Loading by File Name

そしてこれは“TFM 経由”の指定である。何故かというと、TeX Live には ec-lmr10.tfm という TFM ファイルはあるが、ec-lmr10.pfb というフォントファイルは存在しないからである。ec-lmr10.tfm のマップ先は LMRoman10-Regular という Type1 フォントであるが、これのファイル名は lmr10.pfb である。

つまり、ここで登場する \font 命令は、もっと一般的な次の形式と等価である。

\font\lmromanten=ec-lmr10 at 10pt

(なお,\font の右辺にある波括弧については,過去の記事を参照されたい。)

結局のところ、luaotfload のマニュアルでは「Type1 を“直接”指定する話」は全く登場しなかったことになる。何となく、「Type1 は当然“TFM 経由”で使うもの」という雰囲気も感じ取れる。

ZR さんの予想

マニュアルの記述は措いておいて、とにかく「Type1 を“直接”指定できる」と信じた上で、その場合の \font 命令の書き方を考えよう。

Type1 の代わりに、“直接”指定が一般的に行われる OpenType フォントのことを考える。例えば TeXGyreTermes-Regular を“直接”指定したい場合は次の何れかを書くことになる。*1

  • フォント名指定:
    \font\test=name:TeXGyreTermes-Regular
    
  • ファイル名指定:
    \font\test=file:TeXGyreTermes-Regular.otf
    
  • 接頭辞を省略した形:
    \font\test=TeXGyreTermes-Regular
    \font\test=TeXGyreTermes-Regular.otf
    

これの類推で考えると、Type1 フォントの“直接”指定の書式は以下のようになりそうである。

\font\test=name:NimbusRomNo9L-Regu %(1)
\font\test=file:utmr8a.pfb %(2)
\font\test=NimbusRomNo9L-Regu %(3)
\font\test=utmr8a.pfb %(4)

実際にやってみる

TeX Live 2015 において次のような plain LuaTeX 文書を実際にコンパイルしてみる。

\input luaotfload.sty
\font\test=name:NimbusRomNo9L-Regu %(1)
\test Hello!\bye

\font の行を (1)〜(4) の各々で置き換える。)

その結果であるが、フォント名指定の (1) と (3) については、「そのようなフォント名はデータベースにない」というエラーになった。luaotfload で作られるフォントデータベースには Type1 フォントの情報は入っていないということか。

C>luatex test
This is LuaTeX, Version beta-0.80.0 (TeX Live 2015/W32TeX) (rev 5238)
 restricted \write18 enabled.
(./test.tex (c:/texlive/2015/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
(c:/texlive/2015/texmf-dist/tex/latex/base/ltluatex.tex)(using write cache: C:/t
exlive/2015/texmf-var/luatex-cache/generic)(using read cache: C:/texlive/2015/te
xmf-var/luatex-cache/generic C:/Users/yato/.texlive2015/texmf-var/luatex-cache/g
eneric)
luaotfload | main : initialization completed in 0.521 seconds)
luaotfload | db : Reload initiated (formats: otf,ttf,ttc,dfont); reason: "Font N
imbusRomNo9L-Regu not found.".
! Font \test=name:NimbusRomNo9L-Regu not loadable: metric data not found or bad.
<to be read again>
\test
l.3 \test
        Hello!\bye

ファイル名指定の (2) と (4) については、かなり不思議な結果になった。フォントの定義および使用の段階では何もエラーは出ないが、ところが実際に PDF ファイルを出力する段になって、“Invalid font type”のエラーが出て、結局 PDF ファイルは出力されなかった。

C>luatex test
This is LuaTeX, Version beta-0.80.0 (TeX Live 2015/W32TeX) (rev 5238)
 restricted \write18 enabled.
(./test.tex (c:/texlive/2015/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
(c:/texlive/2015/texmf-dist/tex/latex/base/ltluatex.tex)(using write cache: C:/t
exlive/2015/texmf-var/luatex-cache/generic)(using read cache: C:/texlive/2015/te
xmf-var/luatex-cache/generic C:/Users/yato/.texlive2015/texmf-var/luatex-cache/g
eneric)
luaotfload | main : initialization completed in 0.521 seconds)(load luc: C:/texl
ive/2015/texmf-var/luatex-cache/generic/fonts/otf/utmr
8a.luc)(save: C:/texlive/2015/texmf-var/luatex-cache/generic/fonts/otf/utmr8a.lu
a)(save: C:/texlive/2015/texmf-var/luatex-cache/generic/fonts/otf/utmr8a.luc)
[1{c:/texlive/2015/texmf-var/fonts/map/pdftex/updmap/pdftex.map}])<c:/texlive/20
15/texmf-dist/fonts/type1/urw/times/utmr8a.pfb
!LuaTeX error (file c:/texlive/2015/texmf-dist/fonts/type1/urw/times/utmr8a.pfb)
: Invalid font type
 ==> Fatal error occurred, no output PDF file produced!

ソースを少し変えて、実際にフォントのグリフは出力せず、代わりにグリフの幅の情報を表示させてみた。

\input luaotfload.sty
\font\test=file:utmr8a.pfb %(2)
\message{\the\fontcharwd\test`M:\the\fontcharwd\test`i}\bye

すると、これは次のような妥当そうな値を表示する。

8.89pt:2.78pt

以上の結果を踏まえると、LuaTeX + luaotfload では、「Type1 フォントの情報を直接読み込むことはできるが、それを出力 PDF 中のフォントとして利用することはできない」ということになる、ように思える。

というわけではなさそうな話

以上で話が終わればいいが,現実はそんなに甘くなかったらしい。

イロイロ試してみていたところ,なんと一見絶対に失敗しそうに思える次の書式が実は成功する,ということが判明した。

\font\test=file:utmr8a %(5)
\font\test=utmr8a %(6)

つまり,以下のソースはコンパイルが成功し,しかも書いたテキストが完璧に出力されている。

\input luaotfload.sty
\font\test=file:utmr8a
\test Moje vznášedlo je plné úhořů.\bye
f:id:zrbabbler:20160425215734p:image

StandardEncoding にも Latin-1 にもない文字も扱えているので,フォントUnicode エンコーディングで扱われていることが判る。従って,“TFM 経由”ではなく“直接”指定であることは間違いない。それにしても,本来 Unicode の知識を持っていないはずの Type1 フォントUnicode で扱えているのは何とも不思議な感じである……。

*1フォントファミリ名である“TeXGyreTermes”や“TeX Gyre Termes”でも指定できるが、ここではそれは措いておく。

2016-04-03

BXjscls がまた新しくなった(v1.1b)

書いておかないと自分でも忘れるので。

precisetext オプション

新しい XeLaTeX を使う場合に

\documentclass[xelatex,jafont=ipaex,precisetext]{bxjsarticle}

のようにオプションprecisetext を付けておくと、例のアレ

\XeTeXgenerateactualtext=1

が実行される。既定では無効になっている。

こういう事情があるため、既定で有効にするかは思案中……。

simplejasetup オプション

simplejasetup は「簡易な日本語出力用設定」を指示するクラスオプションである。すなわち、エンジンが XeLaTeX で和文ドライバが minimal であり、かつ“他に何も日本語するための設定されていない”場合に、デフォルトで例のアレ

\XeTeXlinebreaklocale "ja"
\XeTeXlinebreakskip=0pt plus 1pt minus 0.1pt
\XeTeXlinebreakpenalty=0

を実行するようになる。つまり和文がちゃんと行分割されるようになる。

simplejasetup は既定で有効になっている。(無効にするためのオプションnosimplejasetup。)だから次のような文書でも行分割が行われる。

% XeLaTeX 文書, 文字コードは UTF-8
\documentclass[xelatex,a5paper,ja=minimal]{bxjsarticle}
% zxjatype も xeCJK も zhspacing も無い!
\usepackage{fontspec}
\setmainfont{IPAexMincho}
\begin{document}
寿限無、寿限無、五劫の擦り切れ、%
海砂利水魚の水行末、雲来末、風来末、%
食う寝る処に住む処、藪ら柑子の藪柑子、%
パイポパイポ、パイポのシューリンガン、%
シューリンガンのグーリンダイ、グーリンダイの%
ポンポコピーのポンポコナーの{\TeX}はアレ。
\end{document}
f:id:zrbabbler:20160403133324p:image

和文ドライバが standard(標準設定)の場合は simplejasetup は自動的に無効になる。また、minimal の場合でも、xeCJK(zxjatype)や zhspacing などの日本語(CJK)処理用パッケージを利用していると判断される場合も、自動的に無効になる。

BXJS クラスは、その設計において日本語処理用パッケージの使用を前提としているため、simplejasetup の設定が実際に役に立つ場面は非常に限られると思う。