Ruby のバージョンは 1.8.7 です.
--------
test.tex
--------
\ifx\kanjiskip\undefined\else
\ifx\ucs\undefined
\documentclass{jsarticle}
\else
\documentclass[uplatex]{jsarticle}
\fi
\fi
\usepackage[dvips]{hyperref}
\begin{document}
\section{テスト}
abc
\end{document}
$ platex test.tex
$ platex.test.tex
$ dvips -Ppdf -z -f test.dvi | convbkmk -e > test.ps
または
$ uplatex test.tex
$ uplatex test.tex
$ dvips -Ppdf -z -f test.dvi | convbkmk -u > test.ps
で処理をすると
convbkmk:213:in `check_parentheses_balance': encoding is not consistent (RuntimeError)
という RuntimeError の例外が発生し正常な PS ファイルが出力されませんでした.
platex の場合は -g オプションを指定すれば処理が可能でした.
uplatex の場合は -g オプションを指定すると
convbkmk:319:in `file_treatment': did not succeed in guess encoding! (RuntimeError)
という RuntimeError の例外が発生し正常な PS ファイルが出力されませんでした.
この ps ファイルを ps2pdf で処理しようとすると
GPL Ghostscript 9.05: Unrecoverable error, exit code 1
となり正常な PDF ファイルが作成できません.
convbkmk.rb の 213 行目に
raise 'encoding is not consistent'
という行があり,この行を
#raise 'encoding is not consistent'
のようにコメントアウトすることで platex では -e または -g オプション,uplatex では -u オプションを指定することで
ps2pdf でエラーにならずに目次が文字化けしていない PDF ファイルができました.
検証ありがとうございます.
たしかに -z オプションをはずすと platex は -e, -g オプションで,uplatex では -u, -g オプションでうまく処理できますね.
-z オプションの有無の違いをみるため
$ dvips -Ppdf -o test.ps
$ dvips -Ppdf -z -o test2.ps
として PS ファイルの中身をみてみたところ違いはありますが
-z オプションがあってもなくても目次の変換の対象となる pdfmark の部分は
SDict begin [/Count -0/Dest (section.1) cvn/Title (テスト) /OUT pdfmark
end
となっていました.
この PostScript の文字列の (テスト) の部分を UTF16-BE with BOM の PostScript 表現
(テスト) -> <FEFF30C630B930C8>
に変換してくれることを期待していました.
私は昔 TeX で JavaScript を使った PDF ファイルを作成していたときに日本語を出力させようとして
これと同じようなスクリプトを書いて処理しようとしたことがあります.
そのときに書いた処理は pdfmark を見つけて対象となる文字列を変換するだけの簡単なプログラムだったので
-z オプションの有無で変わるとは思っていませんでした.
どうもありがとうございました.
$ locate convbkmk/usr/local/texlive/2011/bin/x86_64-linux/convbkmk/usr/local/texlive/2011/texmf-dist/scripts/uptex/convbkmk.rb
$ uplatex test.tex$ uplatex test.tex$ dvips -Ppdf -z -f test.dvi | /usr/local/texlive/2011/texmf-dist/scripts/uptex/convbkmk.rb -u > test.ps
はい.bin ディレクトリの方の convbkmk を呼び出していました.
ただ私の環境では texmf-dist/scripts/uptex/convbkmk.rb でも同様にエラーになりました.
bin 配下の convbkmk は texmf-dist/scripts/uptex/convbkmk.rb へのシンボリックリンクになっているようです.
$ ls -l /usr/local/texlive/2011/bin/i386-linux/convbkmk
/usr/local/texlive/2011/bin/i386-linux/convbkmk -> ../../texmf-dist/scripts/uptex/convbkmk.rb
> Ruby は長い間ほったらかしですが、1.9.2p0 (revision 29306) と出ました。
W32TeX でテストしてみると ruby 1.9.3p194 (2012-04-20) では問題が発生しませんでしたが
ruby 1.8.7 (2012-02-08 patchlevel 358) では同様の問題が発生しました.
convbkmk.rb は Ruby 1.9 系列とそれ以外で記述内容が異なるようです.
以前 W32TeX で Ruby 1.9 系列を使用していたときは convbkmk.rb でこの問題は発生していなかったので
Ruby 1.8.7 と明示的に指定しました.
それと今回のこととは全く関係ないのですが,私の環境では W32TeX で
>texdoc -l -s hyperref
とすると
e:/w32tex/share/texmf/scripts/texdoc/texdoc.tlu:7: module 'texdoc.main' not foun
d:
no field package.preload['texdoc.main']
[kpse lua searcher] file not found: 'texdoc.main'
[kpse C searcher] file not found: 'texdoc.main'
[kpse All-in-one searcher] file not found: 'texdoc'
と表示されて texdoc が実行できないようです.
TeX Live 2011 では実行可能です.
ファイル自体は存在しているのになぜか見つけてくれないのが少し気になったので質問してみました.
TeX Live の texdoc は使用可能でそちらを使用すればいいので解決できなくても今のところは問題ありません.
> e:\w32tex\bin\texlua.exe e:/w32tex/share/texmf/scripts/texdoc/texdoc.tlu -l -s hyperref
> はどうですか?
これも同様にエラーになりました.
>e:\texlive\2011\bin\win32\texlua.exe e:/w32tex/share/texmf/scripts/texdoc/texdoc.tlu -l -s hyperref
とすると実行できるようです.
texdoc.tlu の中身を見て
require('texdoc.main')
の部分に注目して
E:\w32tex\share\texmf\scripts>texlua ./texdoc/texdoc.tlu -l -s hyperref
を実行してみると実行できました.
1 e:\w32tex\share\texmf\doc\latex\hyperref\manual.pdf
2 e:\w32tex\share\texmf\doc\latex\hyperref\hyperref.pdf
3 e:\w32tex\share\texmf\doc\latex\hyperref\manual.html
4 e:\w32tex\share\texmf\doc\latex\hyperref\ChangeLog.pdf
5 e:\w32tex\share\texmf\doc\latex\hyperref\backref.pdf
6 e:\w32tex\share\texmf\doc\latex\hyperref\nameref.pdf
7 e:\w32tex\share\texmf\doc\latex\hyperref\options.pdf
8 e:\w32tex\share\texmf\doc\latex\hyperref\paper.pdf
9 e:\w32tex\share\texmf\doc\latex\hyperref\slides.pdf
10 e:\w32tex\share\texmf\doc\latex\hyperref\manual2.html
11 e:\w32tex\share\texmf\doc\latex\hyperref\manual3.html
12 e:\w32tex\share\texmf\doc\latex\hyperref\README.pdf
= Readme, hyper-crossreferenced
13 e:\w32tex\share\texmf\doc\latex\hyperref\README
= Readme
14 e:\w32tex\share\texmf\doc\latex\hyperref\ChangeLog
Please enter the number of the file to view, anything else to skip:
この結果から以下のように E:\w32tex\share\texmf\scripts ディレクトリで texdoc を実行すると実行できるようです.
E:\w32tex\share\texmf\scripts>texdoc -l -s hyperref
私の環境では W32TeX の texdoc は E:\w32tex\share\texmf\scripts ディレクトリ以外はエラーになってしまうようです.
これが正解です.
E:\w32tex\texmf.cnf が原因でした.
昔の texmf.cnf のバックアップをとってそのままにしていました.
E:\w32tex\texmf.cnf が残っていても (2) の set TEXMFCNF=e:/w32tex/share/texmf/web2c とする方法を使うとうまくいきました.
e:/w32tex/share/texmf/web2c/texmf.cnf よりも e:/w32tex/texmf.cnf が優先されてしまうというのは今回初めて知りました.
たいへん勉強になりました.
ありがとうございました.
> e:/w32tex/texmf.cnf が優先されてしまうというのは今回初めて知りました.
W32TeX では 環境変数が空のとき,
01. bindir
02. bindir-no-oya
03. bindir-no-oya-no-oya
04. bindir/share/texmf-local/web2c
05. bindir-no-oya/share/texmf-local/web2c
06. bindir-no-oya-no-oya/share/texmf-local/web2c
07. bindir/texmf-local/web2c
08. bindir-no-oya/texmf-local/web2c
09. bindir-no-oya-no-oya/texmf-local/web2c
10. bindir/share/texmf/web2c
11. bindir-no-oya/share/texmf/web2c
12. bindir-no-oya-no-oya/share/texmf/web2c
13. bindir/texmf/web2c
14. bindir-no-oya/texmf/web2c
15. bindir-no-oya-no-oya/texmf/web2c
の優先順位で texmf.cnf を読んで行くと思います。
(コンパイル時の設定で決まる)
なお, texmf.cnf が複数あったら全て読みます。
変数の値は,定まった時点で (先に出た方) 決定します。
つまり,配布 texmf.cnf は 11番目の優先順位にあります。
if RUBY_VERSION >= "1.9"$RUBY_M17N = trueclass Stringdef to_utf16be(enc)self.force_encoding(enc.current).encode('UTF-16BE')endendelse$RUBY_M17N = falserequire "jcode" # for method each_charrequire "kconv"
......(以下略)
$ dvips -Ppdf -z -f test.dvi | ruby1.9.1 /usr/local/texlive/2011/texmf-dist/scripts/uptex/convbkmk.rb -u > test.ps
--- convbkmk.rb~ 2011-05-01 23:50:20.000000000 +0900
+++ convbkmk.rb 2012-05-07 23:06:38.000000000 +0900
@@ -290,7 +290,7 @@
while l = ifile.gets do
line.force_encoding('ASCII-8BIT') if $RUBY_M17N
line += l
- if (line !~ %r!(/Author|/Title|/Subject|/Keywords)! )
+ if (line !~ %r!(/Author|/Title|/Subject|/Keywords)(\s*\(|[\r\n])! )
ofile.print line
line = ''
next
ちなみに
ruby 1.8.7 (2009-06-12 patchlevel 174) [x86_64-linux]
でテストしました。
副作用が見つからなければ更新します。まずかったらご指摘ください。
ご指摘のありましたように、
Ruby 1.9系と1.8系では、処理が異なるところがあります。
1.9系では、M17Nの機能を使用しています。
1.8系では、それと同様に動作するよう心がけていますが、
今回、 String#valid_encoding? の動作が引っかかったようです。
Ruby 1.8.7 で動作することを確認しました.
他にも 1.8.7 と 1.9.3 で
\section{テスト}
のかわりに
\section{\texorpdfstring{テスト}{テスト}}
を使用した場合は 1.8.7 と 1.9.3 で結果が異なると思います.
1.8.7 の場合 (文字コード変換ライブラリに Kconv を使用した場合)
(テスト) -> <FEFF30C630B930C8>
1.8.7 の場合 (文字コード変換ライブラリに Iconv を使用した場合)
1.9.3 の場合
(テスト) -> <FEFFFF83FF7DFF84>
となると思います.
昔,半角カナを使用した目次を作成しようとして 1.8 系列の Ruby でスクリプトを作成しましたが
nkf ではダメだったので iconv を使用しました.
1.9 系列では
iconv will be deprecated in the future, use String#encode instead.
と出力されるので iconv は deprecated (非推奨) になってしまっているようです.
半角カナを使用することはまずないと思うので特に対応は必要ないとは思いますが
一応お知らせしておきます.
\section{\texorpdfstring{テスト}{テ\012ス\012ト}}
とした場合に Ruby 1.9.3 と 1.8.7 でうまく処理ができないようです.
以下のように修正すると処理できました.
- conv += $RUBY_M17N ? $&.oct.chr('ASCII-8BIT') : $&.oct.chr
+ #conv += $RUBY_M17N ? $&.oct.chr('ASCII-8BIT') : $&.oct.chr
+ conv += eval('"' << $& << '"')
conv.each_char { |chr|
- if chr == "\r" || chr == "\n"
- buf += chr
- else
+ #if chr == "\r" || chr == "\n"
+ # buf += chr
+ #else
chr.to_utf16be(enc).each_byte {|byte|
buf += '%02X' % byte
}
- end
+ #end
}
しおりを8進数表記で記述することは
特別な場合を除いてあまりないと思うので
特に対応は必要ないとは思いますが
一応報告しておきます.
少々長いですが、もしよろしければお付き合いお願いします。
\xxx の8bit記法でバイト列を書いた場合に、仮定しているencodingが何かにより文字が変わる問題です。
例えば
\section{\texorpdfstring{(1) test}{test[\303\242][\240][\037]}}
\section{\texorpdfstring{(2) テスト}{テスト[\303\242]}}
とあったときを検討します。
ちなみに
\303 :: hex 0xC3, U+C3は、Ã, PDFDocEncodingは、Atilde(Ã)
\242 :: hex 0xA2, U+A2は、¢, PDFDocEncodingは、cent(¢)
\240 :: hex 0xA0, U+A0は、non break space, PDFDocEncodingは、Euro(€) U+20AC
\037 :: hex 0x1F, U+1Fは、unit separator, PDFDocEncodingは、tilde(˜) U+02DC
PDFDocEncodingでは、0xC3 0xA2 が Atilde(Ã), cent(¢) を示します。
UTF8では、0xC3 0xA2 が U+E2 (â) を示します。
EUC-JPでは、0xC3 0xA2 が 35区2点 (但) を示します。
仮定しているencodingが何かにより文字が変わります。
また、\xxx の8bit記法は、PDFの仕様上、
テキスト文字列(bookmarkなどの箇所に使用される文字列)に記述された場合
(a) PDFDocEncoding もしくは、
(b) BOMが先導した場合は UnicodeのUTF16BE
だそうです。
Ref. PDFリファレンス第2版 アドビシステム著 ISBN4-89471-338-1 §3.8.1 テキスト文字列
下記の環境[1a]〜[1c][2a]〜[2e]を使用した場合を考えてみます。
[1] dvipdfmx
[1b] platex(EUC) \AtBeginShipoutFirst{\special{pdf:tounicode EUC-UCS2}}
[1c] uplatex(UTF8) \AtBeginShipoutFirst{\special{pdf:tounicode UTF8-UCS2}}
[2] dvips
[2b] 松本隆太郎さん convert-euc
[2c] 角藤さん bkmk2uni
[2d] ps2jpdf
[2e] convbkmk.rb
欧文LaTeXでは、PDFDocEncoding を期待した結果となり、
[1a][2a]では、(1)の方は、
従来のpLaTeXでは
[1b]で試してみると、(2)の方は、EUC-JP想定で変換され
調べ切れていませんが、おそらく[2b][2c][2d]も同様だと想像しています。
upLaTeX+dvipdfmxでは
[1c]で試すと、(2)の方は、UTF8想定で変換され
従来の[2e]では、
欧文のみの場合には変換しない方針、
和文を含む場合は変換する方針だったので、バグがなければ、
(1)の方は、
(2)の方は、[1b]ならばEUC-JPが想定され
しかし、PDFの仕様の(a)(b)を勘案すると、
\xxx を見つけた場合にEUCやUTF8を想定するのは不適切という気がしてきました。
和文を含む含まないで結果が変わるのも、不整合な印象です。
仕様案を考えてみます。
仕様案その1
\xxx を見つけた場合には PDFDocEncoding を常に期待し、
PDFDocEncoding → UTF16BEの変換をする。
仕様案その1a
\xxx を見つけた場合には PDFDocEncoding を常に期待し、
欧文ならば、変換なし
和文ならば、PDFDocEncoding → UTF16BEの変換をする。
仕様案その2
\xxx を見つけた場合には PDFDocEncoding を期待するモードをdefault、
\xxx を見つけた場合には UTF16BE を期待するモードをコマンドラインオプションで選択可能とし、
各encoding → UTF16BEの変換をする。
仕様案その3 (従来のdvipdfmx+CMap変換の仕様)
CMap が不使用ならば \xxx を見つけた場合は PDFDocEncoding を期待するモードで
変換なし
和文ならば、
CMap が EUC-UCS2 ならば \xxx を見つけた場合は EUC-JP を期待するモード
CMap が UTF8-UCS2 ならば \xxx を見つけた場合は UTF8 を期待するモード
各encoding → UTF16BEの変換をする。
仕様案その3a (従来のconvbkmk.rbの仕様案)
欧文ならば、\xxx を見つけた場合は PDFDocEncoding を期待するモードで
変換なし
和文ならば、
convbkmk.rb が EUC-JP モードならば \xxx を見つけた場合は EUC-JP を期待するモード
convbkmk.rb が UTF8 モードならば \xxx を見つけた場合は UTF8 を期待するモード
各encoding → UTF16BEの変換をする。
今のところ、仕様案その1a にしようかと思っています。
この場合、仕様案その3 との乖離が大きくなるのが難点ですが、欧文LaTeX との乖離は小さくなる方向です。
仕様案その2 は、\xxx の8bit記法を UTF16BE でわざわざ書かなくても、と思います。
( そういえば、bkmk2uniでは、\0xXXXX と書くとUnicodeで直接指定出来る機能が入っているそうですが、
convbkmk.rb でもサポートした方がよいのでしょうか。 )
いずれにせよ、仕様案その3a を捨てると
PDFDocEncoding → UTF16BEの変換を用意することになりそうで、ちょっと手間がかかりそうです。
あるいは、割り切って、不整合な感じには目をつぶって、仕様案その3a を押し通すか。
ご意見があればよろしくお願いします。
PDF の文字列はすべて Unicode (16bit) に対応しているわけではなく
場合によっては PDFDocEncoding (8bit) にしか対応していない場合があります.
Unicode にすると文字化けしたり
Acrobat JavaScript が動作しなくなったりする場合があります.
PDF の文字列は基本的には PDFDocEncoding で表現して
それで表現できない場合は Unicode で表現するのが無難だと思います.
> bkmk2uniでは、\0xXXXX と書くとUnicodeで直接指定出来る機能が入っているそうですが、
> convbkmk.rb でもサポートした方がよいのでしょうか。
bkmk2uni では半角カナが処理できなかったので,私は \0xXXXX で記述していました.
convbkmk.rb では半角カナが使えるので,私には特に必要ではありませんが
サポートすれば bkmk2uni との相互運用性は高くなると思います.
私の感覚はこんな感じです。
TeX が(
\special
等で)PDF 文字列を書く場合は、原則的に PDF 仕様で正しく解釈される(つまり、BOM 付なら UTF-16BE、それ以外は PDFDocEncoding)ものを書くべきだ。(u)pLaTeX + hyperref で和文文字が含まれる場合に DVI 上で不正な文字列になるのは「処理の都合」、つまり「TeX 上で行わずに後の段階(フィルタ)で行う」ことにしたからに過ぎない。ところで、hyperref では、PDF の文字列は「unicode オプション付きなら UTF-16BE、なしなら PDFDocEncoding」としている。unicode 付きの場合、8 ビット欧文文字は「変換」が施される一方、ユーザが入力する「
\xxx
」は透過している(ようだ)。つまり、hyperref の仕様では、「\xxx
」は使用するエンコーディング(UTF-16BE/PDFDocEncoding)で解釈されると考えられる。(u)pLaTeX で hyperref を使う場合、unicode オプションは無意味な出力を作るので専ら無しで使用される。LICR の動作を考えると、この場合にもエンコーディングは PDFDocEncoding と考えるべきである。そして、hyperref の仕様が変わらないと考えるなら、ユーザの「
\xxx
」はやはり PDFDocEncoding で解釈されるとするのが妥当である。
(u)pLaTeX + hyperref で DVI に書き出される①「PDF 文字列(もどき)」は
- ASCII 文字
\xxx
等のエスケープシーケンス- (ある漢字コード X で表された)和文文字(非 ASCII 文字)
が混ざった列となります。先述の「感覚」に従うと、これが②「表すべき文字列」は
- 1 は当然その文字を表す;
- 2 の
\xxx
はバイト値を PDFDocEncoding で解釈する; - 3 はその(X で解釈した)和文文字を表す;
としてできるものになります。無論、3 が存在する場合は、単に①を「PDF 文字列」の仕様に従って解釈しても②とは一致しません。だから、変換フィルタが行うべき処理は、①を「②に解釈される PDF 文字列」に変換すること、となります。
convbkmk.rb は (u)pLaTeX のためのものと考えるならば、unicode オプション(つまり UTF-16BE)をサポートする必要はないでしょう。
以上の考えに従い、私は「仕様 1」または「仕様 1a」(この 2 つは機能的には同じ)を支持します。
ところで質問ですが、内部 Unicode 動作の upTeX が \special
に和文文字を出力した場合、DVI には UTF-8 で書き込まれるのでしょうか?
convbkmk Ver.0.04 を出しました。
upTeXのページ からどうぞ。
仕様案その1a にしたつもりです。
\xxx は、PDFDocEncoding として解釈、
\0xUUUU は、UTF-16BE として解釈します。
また \n \\ などのエスケープシーケンスや、
テキスト文字列に改行文字が含まれる場合にも対応しました。
今回は、かなりテストしたので、大丈夫と思っています。
\special
に和文文字を出力した場合、DVI には UTF-8 で書き込まれるのでしょうか?その通りだと思います。
ところで、
otfbeta v1.7b5のupLaTeX拡張 において \UTF{}, \UTFT{}, \UTFC{}, \UTFM{} のマクロをUnicodeの拡張面 (U+10000以上) に拡張しましたが、例えば、
もし仮に otf.sty の方でサロゲートペアの処理をして
( 従来通りなら "\0x20B9Fる" は "\0x20B9" "F" "る" と解釈される。 )
しかし、どうも私にはそのマクロを書く力は不足しているようです。
どなたかお力添えをいただけると助かります。
深夜から早朝の間に仕上げてしまうとは。お体をお大事に。
早速試してみました。
(1) サロゲートペアが上手くいくようになりました。
ありがとうございます。
(2) オリジナルの otf.sty では
bkmk2uni, out2uni で上手くいきませんでした。
それが今回のものは上手くいくようになっていました。
(3) オリジナルの otf.sty や bkmk2uni, out2uni では
今回のものは、\0xFFFD に変換されてしまいました。
修正を試みましたが、出来ませんでした。
(3) が解決できたら、
otfbetaのupLaTeX拡張に取り込ませてもらってもよろしいでしょうか。