dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
返信数: 15
dvipdfmx と xdvipdfmx で \special{pdf:dest ...} に使える文字列に差分があるようです。

下記のソースを、
uptex + dvipdfmx で処理した場合と、
xetex (+ xdvipdfmx) で処理した場合で、
PDF の「しおり」からジャンプできる文字列とジャンプできない文字列が異なります。



% -*- coding: utf-8 -*-

\ifx\XeTeXrevision\thisisundefined
\else
  \font\textmc"[ipaexm.ttf]:mapping=tex-text"
  \textmc
\fi

\special{pdf:docview << /PageMode /UseOutlines >> }%
\special{pdf:tounicode UTF8-UTF16 }%

\special{pdf:dest (für1) [@thispage /XYZ @xpos @ypos]}%
``für1'' XeTeX + xdvipdfmx ジャンプ不可,upTeX + dvipdfmx ジャンプ可

\vfil

\special{pdf:dest <FEFF006600FC00720032> [@thispage /XYZ @xpos @ypos]}%
$<$FEFF006600FC00720032$>$ (``für2''の16進数UTF-16表記) ジャンプ不可

\vfil

\special{pdf:dest (for1) [@thispage /XYZ @xpos @ypos]}%
``for1'' ジャンプ可

\vfil

\special{pdf:dest <FEFF0066006F00720032> [@thispage /XYZ @xpos @ypos]}%
$<$FEFF0066006F00720032$>$ (``for2''の16進数UTF-16表記) ジャンプ不可

\vfil

\special{pdf:dest (日本語1) [@thispage /XYZ @xpos @ypos]}%
``日本語1'' XeTeX + xdvipdfmx ジャンプ不可,upTeX + dvipdfmx ジャンプ可

\vfil

\special{pdf:dest <FEFF65E5672C8A9E0032> [@thispage /XYZ @xpos @ypos]}%
$<$FEFF65E5672C8A9E0032$>$ (``日本語2''の16進数UTF-16表記) ジャンプ不可

\eject

以下、しおり作成用 special

\special{pdf:out [-] 1 << /Title (für1) /A << /S /GoTo /D (für1) >> >> }%
\special{pdf:out [-] 1 << /Title <FEFF006600FC00720032> /A << /S /GoTo /D <FEFF006600FC00720032> >> >> }%
\special{pdf:out [-] 1 << /Title (for1) /A << /S /GoTo /D (for1) >> >> }%
\special{pdf:out [-] 1 << /Title <FEFF0066006F00720032> /A << /S /GoTo /D <FEFF0066006F00720032> >> >> }%
\special{pdf:out [-] 1 << /Title (日本語1) /A << /S /GoTo /D (日本語1) >> >> }%
\special{pdf:out [-] 1 << /Title <FEFF65E5672C8A9E0032> /A << /S /GoTo /D <FEFF65E5672C8A9E0032> >> >> }%

\bye



双方とも <FEFF....> の表記が使えないのは仕方ないにしても、
(もちろん使えた方がいいと思いますが。。。)
``für'' の ü や日本語など US-ASCII 範囲外の文字があると、
dvipdfmx の場合はジャンプできるのに対して、
xdvipdfmx の場合はジャンプができません。

これはたまたまなので、dvipdfmx の場合でも US-ASCII にしておいた方がよいのか、
それとも xdvipdfmx に問題があるのか、いずれでしょうか。

なお、上記を xdvipdfmx で処理すると、

xdvipdfmx:warning: PDF destination "für1" not defined.

のような警告が出ますので、
UTF-8 文字列の比較か検索か、うまくできていないのかなと思っております。

また、最終的に出力される PDF では、上記のような文字列は使われず、
(0) や (1) のようなものに置き換えられるようですので、
dvipdfmx / xdvipdfmx が pdf:dest の文字列と pdf:out の文字列の
対応関係を認識してくれさえすればうまくいくのではないかと思っています。

個人的には日本語含め US-ASCII 外の文字が使えたほうがありがたいです。

LaTeX の hyperref パッケージは、章・節・図表等の番号を使って、
US-ASCII の範囲内になるような文字列で指定されるようですが、
Texinfo の場合はアンカーとなる @node には番号がなく、
日本語なりドイツ語なり US-ASCII 外の文字列が普通に使われるため、
苦慮しております。
TrueRoad への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Akira Kakuto の投稿
ありがとうございます。 TeX Live SVN r39695 でこの点に関して
xdv と dvi の間で consistent になったと思いますが,よく
わかっていないので副作用が出て元に戻されるかも知れません。
Akira Kakuto への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
角藤先生

早速ご対応いただいてしまったようで、ありがとうございます。

さきほど W32TeX の xdvipdfmx で試した見たところ、dvipdfmx と同様にジャンプできるようになっていることを確認いたしました。

TeX Live 2016 のリリースまで、副作用無しでこのままでいければいいんですが、しばらく svn リポジトリを注目して見ているようにしたいと思います。

どうもありがとうございました。
Akira Kakuto への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
新しくトピックを立てるか否か迷ったのですが、
TeX Live SVN r39695 に関連する現象をみつけましたので、
ここでご報告させていただきます。

・下記の tex ソースで tounicode の行が有効なものとコメントアウトしたもの 2 種類
・xdvipdfmx r39695 前後 2 種類

の、2 × 2 = 4 種類の組み合わせを試してみました。

-------------------------------ここから
% -*- coding: utf-8 -*-

\ifx\XeTeXrevision\thisisundefined
\else
  \font\textmc"[ipaexm.ttf]:mapping=tex-text"
  \textmc
\fi

\special{pdf:docview << /PageMode /UseOutlines >> }%
\special{pdf:tounicode UTF8-UTF16 }% ここの有効・コメントアウトを切り替える

\special{pdf:dest (für) [@thispage /XYZ @xpos @ypos]}%
``für''

\vfil

\special{pdf:dest (for) [@thispage /XYZ @xpos @ypos]}%
``for''

\vfil

\special{pdf:dest (日本語) [@thispage /XYZ @xpos @ypos]}%
``日本語''

\eject

以下、しおり作成用 special

\special{pdf:out [-] 1 << /Title (für) /A << /S /GoTo /D (für) >> >> }%
\special{pdf:out [-] 1 << /Title (for) /A << /S /GoTo /D (for) >> >> }%
\special{pdf:out [-] 1 << /Title (日本語) /A << /S /GoTo /D (日本語) >> >> }%

以下、文章情報用 special

\special{pdf:docinfo << /Title (für) /Author (for) /Subject (日本語) >>}
\bye
-------------------------------ここまで

tounicode が無い場合であっても、\special{pdf:docinfo ...}
の部分は UTF-16 へ変換され、正常な文書情報が生成されました。
また、\special{pdf:out ...} についても、少なくとも /Title 文字列は
UTF-16 へ変換されているのが確認でき、正常な表示ができています。
この部分の動作は r39695 前後で変わりません。

ですので、本来は
「tounicode が指定されていない場合は、UTF-8 から UTF-16 へ変換する」
という仕様なのかな、と思います。

# xdv の場合は元が UTF-8 と決め打ちできるのに対して、
# dvi の場合は Shift_JIS や EUC-JP かもしれず、
#機械的に UTF-16 へ変換できないケースも考えうるので、
#ここの仕様が xdv / dvi で異なるのは問題ないと思います。

一方、\special{pdf:dest ...} の方ですが、
r39695 後の場合、tounicode が無いと、

xdvipdfmx:warning: PDF destination "\376\377" not defined.
xdvipdfmx:warning: PDF destination "\376\377e\345g,\212\236" not defined.

のような警告が出ます。
(\376 などは、その文字コードで出力されており、実際には見えません。)

恐らく最初の行は ``für'' を BOM 付き UTF-16BE 表記にした <FEFF0066...> の冒頭部分、
FEFF が \376\377 として表示され、次の 00 が C 言語の文字列終端と認識されて切れたもの、
ではないかと思いますし、
次の行は ``日本語'' を BOM 付き UTF-16BE 表記にした内容そのものかと思います。

これらは、\special{pdf:out ...} の /D で指定された文字列を UTF-16 変換し、
それらに対応する \special{pdf:dest ...} を探したけど見つけられなかった、
ということだろうと思っています。

r39695 では \special{pdf:dest ...} について tounicode 以外の文字コード変換を
一切行わないように変更されたと認識しております。
そうしますと、tounicode 無しの場合、\special{pdf:out ...} は UTF-16 に変換するが、
\special{pdf:dest ...} は UTF-8 のまま変換しないので一致する文字列が見つけられない、
ということではないかと思っております。
TrueRoad への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
次に r39695 前の場合についてです。
先日ご報告させていただいたように、うまくジャンプできないのですが、
tounicode 有無で微妙に動作が変わります。

tounicode があった場合(先日ご報告した条件の場合)
\special{pdf:dest ...} で非 ASCII 文字列を指定した場合は、
一切ジャンプできないようです。

r39695 後の動作と比較すると、恐らく二重に変換がかかって
おかしくなっているのではないか、とは思います。

詳しくは追えていないので何とも言えませんが、maybe_reencode_utf8() を見ると、
既に BOM 付き UTF-16BE になっている場合は何も変換しない、という処理になっているようなので、
恐らく maybe_reencode_utf8() で UTF-16 変換した後で、さらに tounicode の変換が行われて、
おかしくなっているのではないか、と考えております。

で、tounicode が無かった場合の動作が興味深いです。

以下のソースを処理してみました。

-------------------------------ここから
% -*- coding: utf-8 -*-

\ifx\XeTeXrevision\thisisundefined
\else
  \font\textmc"[ipaexm.ttf]:mapping=tex-text"
  \textmc
\fi

\special{pdf:docview << /PageMode /UseOutlines >> }%
%\special{pdf:tounicode UTF8-UTF16 }% ここの有効・コメントアウトを切り替える

\special{pdf:dest (日本語üウムラウト) [@thispage /XYZ @xpos @ypos]}%
``日本語üウムラウト''

\vfil

\special{pdf:dest (日本語) [@thispage /XYZ @xpos @ypos]}%
``日本語''

\vfil

\special{pdf:dest (日本語1数字) [@thispage /XYZ @xpos @ypos]}%
``日本語1数字''

\eject

以下、しおり作成用 special

\special{pdf:out [-] 1 << /Title (日本語) /A << /S /GoTo /D (日本語) >> >> }%
\special{pdf:out [-] 1 << /Title (日本語1数字) /A << /S /GoTo /D (日本語1数字) >> >> }%
\special{pdf:out [-] 1 << /Title (日本語üウムラウト) /A << /S /GoTo /D (日本語üウムラウト) >> >> }%

\bye
-------------------------------ここまで

tounicode が有効の場合は、

xdvipdfmx:warning: PDF destination "日本語" not defined.
xdvipdfmx:warning: PDF destination "日本語1数字" not defined.
xdvipdfmx:warning: PDF destination "日本語üウムラウト" not defined.

のような警告が出るのですが、tounicode がコメントアウトしてあると、
何も警告が出ません。

ですが、「しおり」のジャンプ先が 3 つとも ``日本語'' になってしまい、
``日本語1数字'' や ``日本語üウムラウト'' には飛びません。

半角の 1 (U+0031) や ü (U+00FC) のような、
U+00FF 以下の文字があると、その前までで切れてしまうようです。
これは恐らく UTF-16BE で 1 バイト目が 00 の文字があったら、
そこを C 言語の文字列終端と認識してしまい、切れてしまうのではないかと思います。
TrueRoad への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
以上、長くなってしまいましたが、本来は \special{pdf:docinfo ...} と同様、
「tounicode が指定されていない場合は、UTF-8 から UTF-16 へ変換する」
「tounicode が指定されている場合は、指定にしたがって変換する」
ではないかと思いますが、いかがでしょうか。

そのためにパッチ等を示せればよかったのですが、
そこまで追い切れておらず、調査した結果の羅列になってしまい、
申し訳ありません。
TrueRoad への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Z. R. の投稿

こちらでも検証してみました。

[テスト用文書ソース]
%\special{pdf:tounicode UTF8-UTF16}% ToUnicode 有無を切り替える
Here's the
\special{pdf:dest <E29883> [@thispage /XYZ @xpos @ypos null]}%
SNOWMAN (UTF-8).
\bigskip
Here's the
\special{pdf:dest <FEFF3020> [@thispage /XYZ @xpos @ypos null]}%
POSTAL-FACE (UTF-16).

\special{pdf:docview << /PageMode /UseOutlines >>}
\special{pdf:outline [-] 1 % SNOWMAN, UTF-8
  << /Title <E29883> /A << /S /GoTo /D <E29883> >> >>}
\special{pdf:outline [-] 1 % SNOWMAN, UTF-16
  << /Title <FEFF2603> /A << /S /GoTo /D <FEFF2603> >> >>}
\special{pdf:outline [-] 1 % POSTAL-FACE, UTF-8
  << /Title <E380A0> /A << /S /GoTo /D <E380A0> >> >>}
\special{pdf:outline [-] 1 % POSTAL-FACE, UTF-16
  << /Title <FEFF3020> /A << /S /GoTo /D <FEFF3020> >> >>}
\bye
結果:
リンク元 リンク先
dvi
ToUni有

旧xdv
ToUni無

旧xdv
ToUni有

新xdv
ToUni無

新xdv
ToUni有
UTF-8 UTF-8 × ×
UTF-16 UTF-8 × × ×
UTF-8 UTF-16 × × ×
UTF-16 UTF-16
dvi: uptex + dvipdfmx
旧xdv: xetex + xdvipdfmx(TeX Live 最新)
新xdv: xetex + xdvipdfmx(W32TeX 最新)

修正の目的は、「①と⑤を同じにすること」であり、確かにそれは実現できています。しかし、(少なくとも自分の感覚としては)XeTeX では ToUnicode を指定することは一般的でなく、②と④(そしてその中でも最初のパターン「UTF-8・UTF-8」)が“最も自然な使い方”でしょう。その観点から見ると、残念ながら劣化していることになります。

Z. R. への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Z. R. の投稿

今自分が理解している範囲で要点をまとめると、以下のようになります。

  • 今の問題である「pdf:destのラベル」は単なる符牒でありUIに表示されるものではないので、“同じバイト列”であればよい。
    (※UIに表示する文字列はUTF-16(かPDFDocEncoding)でないとダメ。)
  • “リンク元のラベル”(つまりpdf:outのリンク先情報に含まれるラベル)は:
    • ToUnicode指定での変換対象にはならない。
    • ToUnicode無しxdvipdfmxでの変換対象にはなる。つまり元がUTF-8ならUTF-16に変換される。
    この違いの原因は、前者は後者と違って「キー名」を判定対象に入れているから。
  • これに合わせて“リンク先のラベル”(つまりpdf:destのラベル)の変換を決めるとすると、以下の処理が望ましいことになる:
    (※ちなみに、ソースコードの構造上、逆に(outlineをdestに)合わせるのは面倒)
    • ToUnicode指定の場合(①③⑤)は変換しない。
    • ToUnicode無しxdvipdfmxの場合(②④)は「元がUTF-8であればUTF-16に変換する」。
Z. R. への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
Z.R.さん

詳細な調査とご説明いただきありがとうございます。
tounicode有無で変換対象が異なるというのは、考え付きませんでした。

たしかに、pdf:out で /D に指定した文字列が見つからないときの警告と思われる、

xdvipdfmx:warning: PDF destination "日本語" not defined.

等は、tounicode が有効のときは UTF-8 で出力され、無効の時は UFF-16 で出力しようとしているようでしたので、tounicode があるときは、逆変換でもしているのかと思ってしまいましたが、そもそも変換していない、んですね。

今回の TeX Live SVN r39753 の変更で、お示しいただいた例ですと tounicode 有無いずれも、リンク元先それぞれの文字コードが一致している場合はジャンプできるようになりましたので、とりあえずの解決にはなっているかと思います。

#不一致の場合はジャンプできないようですが。。。
#お示しいただいているロジックは②のように不一致の場合でもジャンプできるようにする想定なのかな、と思いますが。。。
TrueRoad への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Akira Kakuto の投稿
ありがとうございます。
TeX Live SVN r39753 で
xdvipdfmx に関して
\special{pdf:tounicode UTF8-UTF16}
がある場合も,無い場合もうまく行くようになった
のではないかと思います。 (W32TeX でもまだバイナリは
アプロードしていません)。
Akira Kakuto への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
角藤先生

最新の Win32TeX にてうまくいくようになったことを確認しました。
早速ご対応いただきありがとうございました。
Akira Kakuto への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Z. R. の投稿

最新の (x)dvipdfmx について、2/18 の実験を改めて実施しました。

結果:
ソフトウェア→ dvi xdv xdv xdv xdv dvi xdv xdv
バージョン→ TL
最新
TL
最新
TL
最新
W32
2/18
W32
2/18
W32
2/20
W32
2/20
W32
2/20
ToUnicode→
↓文字コード
UTF-8→UTF-8 × ×
UTF-16→UTF-16

次に、「文書情報の文字列の文字コード変換」の扱いを調べるために、以下の記事の実験を最新の (x)dvipdmfx について実施しました。

[テスト文書:test.tex]
% plain TeX 文書, 文字コードは UTF-8
%\special{pdf:tounicode UTF8-UTF16}% (*)
\special{pdf:docview <<
  /Snowman (☃)
  /Author (☃)
  /Keywords [(☃) (☃)]
  /SnowmanArray [ (☃) (☃) ]
  /SnowmanDict << /S (☃) /T (☃) >>
  /UTF16 <feff2603> % 最初からUTF-16
  /ASCII (Snow) % ASCIIのみ
>>}
\nopagenumbers \null \bye

結果: 「ToUnicode無しのxdvipdmfx」「ToUnicode有りのdvipdfmx」「ToUnicode有りのxdvipdfmx」の全てでCatalog辞書の中身が一致しました。

1 0 obj
<<※整形済
  /Snowman <e29883> 
  /Author <feff2603>
  /Keywords [ <e29883> <e29883> ]
  /SnowmanArray [ <e29883> <e29883> ]
  /SnowmanDict << /S <e29883> /T <feff2603> >>
  /UTF16 <feff2603>
  /ASCII (Snow)
  /Pages 6 0 R
  /Type /Catalog
>>
endobj

自分が関知している限りでは問題ないと思います。

Z. R. への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
一応確認させてください。

TeX Live SVN r39753 (および r39754)や、ソースを見たり、実際の動作を確認してみたところ、2/18 に Z.R. さんが「望ましい処理」としてお書きいただいている処理に変更したのではなく、以下のようになっていると認識しております。

・旧 xdvipdfmx (r39753 以前)

tounicode 有無で UTF-16 への変換範囲が異なる。
tounicode 無しの方が変換範囲が広い。

例えば、\special{pdf:out ...} の /D は tounicode 無しなら UTF-16 へ変換されるが、tounicode 有りなら変換されない。
(\special{pdf:out ...} の /Title は tounicode 有無いずれであっても変換される。)

・最新 xdvipdfmx (r39754 以降)

tounicode 有無で UTF-16 への変換範囲が同一となった。
旧 xdvipdfmx の tounicode 有りと同じ変換範囲。
(キー名を考慮するようになり、変換範囲が狭くなった)

つまり、\special{pdf:out ...} の /D は変換されず、UTF-8 のまま。
(\special{pdf:out ...} の /Title は変換される。)

以上より、r39695 で \special{pdf:dest ...} も変換されないようになっているので、r39754 以降は pdf:out の /D, pdf:dest 双方とも tounicode 有無いずれであっても一切変換されない。
よって、双方で UTF-8 の同じ文字列が指定されていればジャンプできる。

双方で UTF-16 を指定した場合でも基本的にはジャンプできるのだが、U+00FF 以下の文字があると、そこを C 言語の文字列終端と誤認識してしまう問題が残っている。
その場合、ジャンプできなかったり、指定と異なる場所へ飛んでしまうようになる。UTF-8 であれば、そのような問題はないので、UTF-16 で指定せず、普通に UTF-8 で指定すれば問題ない。

これで合っているでしょうか。
TrueRoad への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Z. R. の投稿
半角の 1 (U+0031) や ü (U+00FC) のような、
U+00FF 以下の文字があると、その前までで切れてしまうようです。
これは恐らく UTF-16BE で 1 バイト目が 00 の文字があったら、
そこを C 言語の文字列終端と認識してしまい、切れてしまうのではないかと思います。

こちらの現象についても再現できました。

%\special{pdf:tounicode UTF8-UTF16}
Here's the
\special{pdf:dest <FEFF2603> [@thispage /XYZ @xpos @ypos null]}%
FEFF2603.
\bigskip
Here's the
\special{pdf:dest <FEFF260300213020> [@thispage /XYZ @xpos @ypos null]}%
FEFF260300213020.
\bigskip
Here's the
\special{pdf:dest <FEFF30200023> [@thispage /XYZ @xpos @ypos null]}%
FEFF30200023.

\special{pdf:docview << /PageMode /UseOutlines >>}
\special{pdf:outline [-] 1 %
  << /Title (FEFF2603) /A << /S /GoTo /D <FEFF2603> >> >>}
\special{pdf:outline [-] 1 %
  << /Title (FEFF260300D7) /A << /S /GoTo /D <FEFF260300D7> >> >>}
\special{pdf:outline [-] 1 %
  << /Title (FEFF260300213020) /A << /S /GoTo /D <FEFF260300213020> >> >>}
\special{pdf:outline [-] 1 %
  << /Title (FEFF30200023) /A << /S /GoTo /D <FEFF30200023> >> >>}
\bye

この文書(ToUnicode無し)を、uptex + dvipdmfx でPDFに変換します。(ToUnicode無しのdvipdfmxなので明らかにバイト列は変換されずそのままになります。)PDFのアウトラインからのリンクの挙動は以下のようになりました。

  • “FEFF2603”“FEFF260300D7”“FEFF260300213020”を指定したリンクは全て“FEFF2603”のdestに移動する。
  • “FEFF30200023”を指定したリンクは機能しない(“FEFF30200023”に移動しない)。

これより、ラベルのバイト列のヌルバイト以降が無視されている、という推測が確認できます。

Z. R. への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- Akira Kakuto の投稿
> ラベルのバイト列のヌルバイト以降が無視されている、
> という推測が確認できます。

こちらでも確認しています。C の伝統的文字列を基礎と
しているようなので,UTF-16を直接入力しないことで
避けざるを得ないと思います。
Z. R. への返信

Re: dvipdfmx / xdvipdfmx : \special{pdf:dest ...} で使える文字列

- TrueRoad の投稿
これはパッチを取り込んでいただいたので、TeX Live SVN r39836 で直っているのではないかと思います。