Closed aminophen closed 7 years ago
素朴に pdf special の解釈をひっくり返してみました。
--- texk/dvipdfm-x/spc_util.c 2016-11-26 03:24:24.000000000 +0900
+++ texk/dvipdfm-x/spc_util.c.fix1 2016-12-06 18:36:13.000000000 +0900
@@ -355,13 +355,29 @@
double rotate)
{
double c, s;
+ int dirmode, temp_dirmode;
c = cos(rotate);
s = sin(rotate);
+ dirmode = pdf_dev_get_dirmode();
+ if (dirmode) {
+ temp_dirmode = 1;
+ } else {
+ temp_dirmode = 0;
+ }
+ switch (temp_dirmode) {
+ case 1:
+ M->a = yscale * c; M->b = yscale * s;
+ M->c = -xscale * s; M->d = xscale * c;
+ M->e = xoffset; M->f = yoffset;
+ break;
+ default:
M->a = xscale * c; M->b = xscale * s;
M->c = -yscale * s; M->d = yscale * c;
M->e = xoffset; M->f = yoffset;
+ break;
+ }
}
static int
このパッチをあてると
にある 2 つのテストソース(から \usepackage{pxtatescale} を削除した状態)でうまくいっているようにみえますが、pTeX 以外で使われた場合とか、他のことはあまり考えていません。
コレって、「新版のdvipdfmx.def」で通用しているんですか?
(何となく、pdf:btrans xscale...
に相当するところをパッチしているように見えるので)
通用しませんね。pdf:literal
の解釈を変えるのは危険そうな気がして pdf:btrans xscale...
の方にパッチしたのですが、でもそれだと意味がないわけで… 同じ目的に使える \special が複数あるとややこしいですね。マクロの方でなんとかするしかないのでしょうか?
いろいろ考えましたが、私が最初に掲げた pdf:btrans xscale...
に対するパッチは(汚いので refactor してからだと思いますが)適用してよいのではないかと思いました。
dvips.def にある scale 関連の ps:
special は、現在の dvipdfmx の mpost.c で対策が施されているため縦組でも正常に動作しています。dvips.def からの抜粋:
\def\Gscale@start{\special{ps: currentpoint currentpoint translate
\Gscale@x\space \Gscale@y\space scale neg exch neg exch translate}}
\def\Gscale@end{\special{ps: currentpoint currentpoint translate
1 \Gscale@x\space div 1 \Gscale@y\space div scale
neg exch neg exch translate}}
これは現行の dvipdfmx.def の pdf:btrans xscale...
という special と等価なはずです。それなのに、現在の dvipdfmx は「ps:
なら大丈夫で pdf:
ならダメ」という挙動を示しています。
一方、ps:
special を「新 dvipdfmx.def」の pdf:literal
special に相当する書式で書き直すと(乗除計算が雑ですがそこは無視することにして)
\makeatletter
\def\Gscale@start{\special{ps: currentpoint currentpoint translate
[\Gscale@x\space 0 0 \Gscale@y\space 0 0] concat neg exch neg exch translate}}
\def\Gscale@end{%
\@tempdima\Gscale@x\p@
\@tempdimb\Gscale@y\p@
\edef\@reversedapt{\strip@pt\dimexpr256\p@/\@tempdima*256}% 1/\Gscale@x
%\typeout{\@reversedapt}% for debug
\edef\@reversedbpt{\strip@pt\dimexpr256\p@/\@tempdimb*256}% 1/\Gscale@y
%\typeout{\@reversedbpt}% for debug
\special{ps: currentpoint currentpoint translate
[\@reversedapt\space 0 0 \@reversedbpt\space 0 0] concat
neg exch neg exch translate}}
\makeatother
これは縦組で失敗します。失敗するという点では嬉しくないわけですが、ps:
も pdf:
も失敗なので互換であるという考え方ができます。
結局「pxtatescale.sty を新 dvipdfmx.def の pdf:literal
に合うように書き直して配布、dvipdfmx 本体には xscale
が使われた場合に縦組対処を施す」というのが ps:
と pdf:
の互換性という観点からはよいと思うのですが、いかがでしょう。
そもそも、pdf:btrans
って何をするものなのでしょうか?
具体的には、pdf:literal
で相応の座標変換(cm
)を書くのと何が違う?
(まあ、コレを言い出すと永遠に進まなくなる気がするけど…)
自分の感想としては、 「scale演算子の解釈“だけ”変える」 という処置がとれる、というのがそもそも不思議で仕方がないわけなんですよね。
実際に少し試したところだと、
2 1 scale
→ 2 0 0 1 0 0 cm
となるべきところを、縦組モードの場合は、
2 1 scale
→ 1 0 0 2 0 0 cm
のように変えている。でもtranslateとかrotateは影響しないようです。
でも、PostScriptのコードとしては 2 1 scale
の代わりに
[ 2 0 0 1 0 0 ] concat
と書いても等価になるはずです。これはどう扱うべきなのか。あるいは、
[ 2 1 -1 1 42 0 ] concat
みたいにもっと複雑な場合はどうなのか。
実際には、dvipdfmxのPS解釈器は、このコードには対応していないようです。
この結果から考えてみると、結局、scaleの解釈だけ変えられるのは、そもそも 「dvipdfmxのPS言語の解釈能力が低くて、その使用場面が限られる」 ことが根拠になっている、ような気がしてきます。要するに、 「dvips.defのコードさえ通ればよい」 と考えた、ということです。
もしこの推定が当たっているとするなら、PDF specialで同様の処置をするのは、 極めて危険な気がします。 PDF specialはもっと広範な目的で使われる余地があるからです。
一つの例ですが、dvipdfmxでは、
pdf:btrans matrix 1 2 3 4 5 6
のように変換行列を直に書くことができるようです。
これはどのような cm
命令を生成すべきなのでしょうか。
結局、scaleの解釈だけ変えられるのは、そもそも 「dvipdfmxのPS言語の解釈能力が低くて、その使用場面が限られる」 ことが根拠になっている、ような気がしてきます。要するに、 「dvips.defのコードさえ通ればよい」 と考えた、ということです。
(変え「られる」という言葉は「コードの上で実現可能である」ではなく「結果として得られる全挙動が期待どおりと見込める」という意味ですよね、念のため。)
私のパッチは「コードの上で実現可能である」を pdf:
の xscale と yscale に持ち込んだものです。とりあえずそうしてみたのは、ps:
について scale 演算子の解釈“だけ”変えていることが、今のところ問題視されていないように思えたからです。
しかし、その前提に、仰るような「dvipdfmxのPS言語の解釈能力が低くて、その使用場面が限られる」という条件があるのだとすれば
もしこの推定が当たっているとするなら、PDF specialで同様の処置をするのは、 極めて危険な気がします。 PDF specialはもっと広範な目的で使われる余地があるからです。
は妥当な主張のように思えてきました。
dvipdfmx の解釈を変えるのではなく、「新旧の dvipdfmx.def が通るように」を目指した新しい pxtatescale.sty は以下のようになります。
% pxtatescale.sty
\NeedsTeXFormat{pLaTeX2e}
\ProvidesPackage{pxtatescale}[2017/01/16 v0.3]
\def\pxqtg@pkgname{pxtatescale}
\@ifpackageloaded{graphics}{}{%else
\PackageError\pxqtg@pkgname{Package 'graphics' not loaded}\@ehc}
\begingroup
\def\pxqtg@patch@status{1}%
\def\pxqtg@try@patch#1#2#3{%
\edef\pxqtg@tempcsname{\string#1}%
\def\pxqtg@temp{#2}\ifx#1\pxqtg@temp
\gdef#1{#3}%
\def\pxqtg@patch@status{0}%
\fi}
% first trial (new definition)
\pxqtg@try@patch\Gscale@start
{\special{pdf:btrans}%
\special{pdf:literal \Gscale@x\space 0 0 \Gscale@y\space 0 0 cm}}
{\special{pdf:btrans}%
\special{pdf:literal
\iftdir \Gscale@y\space 0 0 \Gscale@x\space
\else \Gscale@x\space 0 0 \Gscale@y\space
\fi 0 0 cm}}
\ifnum\pxqtg@patch@status=\z@\else
% second trial (old definition)
\pxqtg@try@patch\Gscale@start
{\special{pdf:btrans xscale \Gscale@x\space yscale \Gscale@y}}%
{\special{pdf:btrans
\iftdir xscale \Gscale@y\space yscale \Gscale@x
\else xscale \Gscale@x\space yscale \Gscale@y
\fi}}
\fi
\ifnum\pxqtg@patch@status=\z@
\PackageInfo\pxqtg@pkgname{Patch applied to \pxqtg@tempcsname}%
\else
\PackageWarningNoLine\pxqtg@pkgname{Patch cannot be applied to \pxqtg@tempcsname}%
\fi
\endgroup
これを公開する、という方向でよいでしょうか。
これは forum:961 に関連したものです。
のですが、現在の dvipdfmx は PostScript special を使用した場合と PDF 用 special を使用した場合で挙動が異なります(PostScript special のほうが期待される出力)。
簡単な対処として「dvipdfmx.def のマクロにパッチする」という方法が @zr-tex8r さんの pxtatescale.sty にありますが、要するに「元のコードにパッチをあてている」だけですので、あまり本質的ではないように思います。そして、最近気づいたのですが、まさに次期バージョンの dvipdfmx.def ではパッチがあたらなくなってしまうことがほぼ確定のようです (latex3/graphics-def@986048a) から、この際 dvipdfmx の本体で対処を考えてはどうかと思いました。