doraTeX / TeX2img

TeX2img for macOS
https://tex2img.tech
Other
26 stars 2 forks source link

TikZのパターンがSVG化の際に欠ける #64

Closed doraTeX closed 8 years ago

doraTeX commented 8 years ago

現象

次のソースを TeX2img でSVG化すると,パターンが欠ける。

\documentclass[dvipdfmx]{article}
\usepackage{tikz}
\usetikzlibrary{patterns}
\pagestyle{empty}
\begin{document}
\begin{tikzpicture}
\filldraw[pattern = north east lines] (0,0) rectangle (5,5);
\end{tikzpicture}
\end{document}

# 原因

~~#34 で,mudraw の最新バージョン対応のために -l オプションを外したことが原因。 TeX2img.app に内包されている旧バージョンの mudraw は -l オプションを受け入れる。#34 の改修前のように,-l を付けておけば,パターンも無事に保持される。~~

# 対策

GUI版については,.app に内包されている旧バージョンの mudraw を使っているので,-l を付けるように戻せばよいだろう。 CUI版については,

とするのが最善か?

# 検討事項

新バージョンの mudraw でも旧バージョンの -l に相当することはできないものか?

doraTeX commented 8 years ago

#34 で,mudraw の最新バージョン対応のために -l オプションを外したことが原因。 TeX2img.app に内包されている旧バージョンの mudraw は -l オプションを受け入れる。#34 の改修前のように,-l を付けておけば,パターンも無事に保持される。

いや,どうもそういう単純な話でもないようで,マシンを変えてみると再現性がなかったりする模様……。 再現条件をもう少し細かく調べてみないと原因・対策は分からない。

doraTeX commented 8 years ago

-l の有無は無関係だった模様。 ソースのコンパイルを,standalone クラスを使うか preview パッケージを使うかして tikpicture だけを切り出したPDFを出力するようにしておけば,斜線パターンが保持されることを発見。 standalone / preview をかませることで mudraw が扱いやすい PDF が生成されるようだが,詳細は不明……。

doraTeX commented 8 years ago

68 の方法を応用することで,この問題も解決できそうです。

現状,gs 9.15 以上での pdfwrite を用いたアウトライン化SVG生成は

pdfwrite でアウトライン化PDF生成 → mudrawでSVG変換

としていますが,これを

eps2write(または pdfwrite + pdftops)でアウトライン化EPS生成 → EPSの冒頭に /oldstroke /stroke load def stroke {strokepath fill} def を追加 → epstopdf でPDFに戻す → mudrawでSVG変換

という経路を経れば,patternsライブラリによるパターンのアウトライン化が可能でした。

できればEPSを経由しない方が望ましいのですが……。 pdfwrite のときに一緒に /oldstroke /stroke load def stroke {strokepath fill} def をできないものでしょうか。

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=out.pdf -dAutoRotatePages=/None -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf

では Syntax error になってしまいました。

GPL Ghostscript 9.18 (2015-10-05)
Copyright (C) 2015 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Error: /syntaxerror in -file-
Operand stack:
   stroke
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push
Dictionary stack:
   --dict:1193/1684(ro)(G)--   --dict:0/20(G)--   --dict:79/200(L)--
Current allocation mode is local
GPL Ghostscript 9.18: Unrecoverable error, exit code 1
aminophen commented 8 years ago

あれれ、この話のときは pdfwrite で出来ていたのですが…

doraTeX commented 8 years ago

実はその話のときも,自分は一度も「pdfwrite と同時のパスのアウトライン化」というものに成功したことがありませんでした……。 自分が何か勘違いしているのか,MacとWindowsの違いなのか……?

doraTeX commented 8 years ago

現状の変換経路では,「パスのアウトライン化」を行うのは,改造版 pstoedit にかける直前の EPS に対してのみとなっていますので,「pdfwrite と同時のパスのアウトライン化」の必要は幸い生じておりませんでした。 ですが,SVG出力などにおいてもパスのアウトライン化を行っておく方が無難ということになれば,「pdfwrite と同時のパスのアウトライン化」の手法をきちんと確立しておいた方がよさそうですね。

aminophen commented 8 years ago

いま Mac で .dashpath のやつ(=破線のストロークを実線のストロークに分割)を試しましたが、これは Windows と同じで可能でした。

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=out.pdf -c ".setpdfwrite /oldstroke /stroke load def /stroke {.dashpath [] 0 setdash oldstroke}def" -f in.pdf 

あれれ…とよくみたら @doraTeX さんのコマンドは stroke/stroke になっていないじゃないですか!

 /oldstroke /stroke load def stroke {strokepath fill} def

ではなく

 /oldstroke /stroke load def /stroke {strokepath fill} def

が正しいです。

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=out.pdf -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf 
aminophen commented 8 years ago

OS によらず pdfwrite / eps(2)write で -c オプションを使えばパスのアウトライン化や破線ストロークの分割が一発で可能なことを確認しました。これで安心です。

ところで、ここで触れたように、PDF などの形式でもストロークをアウトライン化する選択肢があってもよいかもと思っています。仮にこれを付けた場合、SVG もその設定状態に応じて変えるというのがよいでしょうか。

doraTeX commented 8 years ago

pdfwrite のときに一緒に /oldstroke /stroke load def stroke {strokepath fill} def をできないものでしょうか。

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=out.pdf -dAutoRotatePages=/None -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf

あれれ…とよくみたら @doraTeX さんのコマンドは stroke が /stroke になっていないじゃないですか!

すみません,1回目の方ではコピペをミスしました。 ですが,2回目のコマンドラインの方では正しく /stroke となっており,こちらの実験も /stroke で行っています。

Ghostscript のバージョンはいくつで実験しておられますでしょうか。 こちらでは,

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=out.pdf -dAutoRotatePages=/None -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf

は,gs 9.16 (MacPorts) では成功,9.18(Richardのページで配布しているものを美文書インストーラ方式でインストールしたもの)では上記のエラー,という結果になっています。

doraTeX commented 8 years ago

なお,gs 9.16 では,stroke 改変付き pdfwrite 自体はとおるものの,それを mudraw にかけてもやはりパターンが欠けます。

gs 9.16 の環境で,in.pdf (テキスト保持PDFとして切り出したもの)に対して以下の一連のコマンドを実験してみました。

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=out1.pdf -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf 
/Applications/TeX2img.app/Contents/Resources/mupdf/mudraw -o out1.svg out1.pdf

gs -dNOPAUSE -dBATCH -sDEVICE=eps2write -sOutputFile=out2.eps -dCompressPages=false -dASCII85EncodePages=true -f in.pdf 
echo "/oldstroke /stroke load def /stroke {strokepath fill} def" | cat - out2.eps > out2-modified.eps
epstopdf -outfile=out2.pdf out2-modified.eps 
/Applications/TeX2img.app/Contents/Resources/mupdf/mudraw -o out2.svg out2.pdf

/Applications/TeX2img.app/Contents/Resources/pdftops/pdftops -eps in.pdf out3.eps
echo "/oldstroke /stroke load def /stroke {strokepath fill} def" | cat - out3.eps > out3-modified.eps
epstopdf -outfile=out3.pdf out3-modified.eps 
/Applications/TeX2img.app/Contents/Resources/mupdf/mudraw -o out3.svg out3.pdf

この実験では,pdftops を経由する out3.svg のみでパターンが保持されました。

aminophen commented 8 years ago

gs 9.16 (MacPorts) では成功,9.18(Richardのページで配布しているものを美文書インストーラ方式でインストールしたもの)では上記のエラー,という結果になっています。

すみません、gs9.18 はソースからのビルドが Mac で通らず試せなかったため gs9.16 オンリーで実験していました。gs9.18 での実験はビルド環境が整っている Windows であとで試してみます。

gs 9.16 では,stroke 改変付き pdfwrite 自体はとおるものの,それを mudraw にかけてもやはりパターンが欠けます。

確かに SVG になったときにパターンがみえるのは out3.svg だけですね。out3.pdf をよくみると、パターンにカーソルをあてると文字のように選択できて xxxxxxxx... となります。不思議。

どちらももう少し調べてみます。

aminophen commented 8 years ago

よく考えたら私の Lion ならマスクメロン版 Ghostscript.app が使えるなと思って、gs9.18 を入手することに成功しました。ところが

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=out.pdf -dAutoRotatePages=/None -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf

はエラーなく終了しました(できたファイルは gs9.16 のものと同じ見た目)。

Error: /syntaxerror in -file-
Operand stack:
   stroke

が再現しません。あれ?

doraTeX commented 8 years ago

美文書方式でインストールした gs 9.16 の環境でも同じエラーが発生しました。 どうやら,バージョンではなくインストールの仕方が影響しているようです。

aminophen commented 8 years ago

美文書方式でインストールした gs 9.16 の環境でも同じエラーが発生しました。 どうやら,バージョンではなくインストールの仕方が影響しているようです。

えっ… それは困りました… 美文書では gs のライブラリのどれかが正しく読まれなくなっている可能性があるということですよね?

doraTeX commented 8 years ago

美文書インストーラでは,/Applications/TeXLive/mactexaddons/share/ghostscript/9.16 以下に Resourcesfonts など一式を入れます。 そして,MacTeX のインストーラが /usr/local/bin に入れようとするファイル一式(gs実行バイナリやps2pdf など)を,/Applications/TeXLive/mactexaddons/bin に入れます。 そして,/Applications/TeXLive/mactexaddons/bin に,gs という名で次のスクリプトを設置します。

#!/bin/bash

GHOSTSCRIPT_PREFIX=${MACTEXADDONS_PREFIX:-/Applications/TeXLive/mactexaddons}

case $(uname -m) in
    x86_64) __gs=${GHOSTSCRIPT_PREFIX}/bin/gs-noX11-64Bit;;
    *)      __gs=${GHOSTSCRIPT_PREFIX}/bin/gs-noX11;;
esac

$__gs \
    -I ${GHOSTSCRIPT_PREFIX}/share/ghostscript/9.16/Resource/Init \
    -I ${GHOSTSCRIPT_PREFIX}/share/ghostscript/9.16/Resource/Font \
    -I ${GHOSTSCRIPT_PREFIX}/share/ghostscript/9.16/lib \
    -I ${GHOSTSCRIPT_PREFIX}/share/ghostscript/9.16/fonts \
    -I ${GHOSTSCRIPT_PREFIX}/share/ghostscript/fonts \
    $@

これにより,/usr/local/bin を汚さずに済んでいます。 しかし,gsのバイナリ自体は,/usr/local/bin/usr/local/share を参照するようにビルドされており,この gs 呼び出しスクリプトでは,-I でそれにパスを追加して gs を機能させているのですが,この偽装が -c .setpdfwrite には通用しないのかもしれません。

aminophen commented 8 years ago

なるほど… だとすると美文書の gs はひょっとして .setpdfwrite パラメタが効かない(たとえば ps2pdf が不十分な PDF を吐き出す)可能性があるのではないでしょうか?

ところで -c というのは gs のインタフェースにない PostScript のパラメタをいろいろ実行するためのもので、「.setpdfwrite」とか「/stroke の再定義」とかがそれぞれパラメタです。.setpdfwrite というパラメタが何をやっているのかは忘れてしまいましたが、pdfwrite するときに付けたほうがよいパラメタをまとめて与えるための何かだった気がします(gs のドキュメントによるとパフォーマンスが上がるとかなんとかなのでたいしたことはなさそうですが)。

doraTeX commented 8 years ago

なるほど… だとすると美文書の gs はひょっとして .setpdfwrite パラメタが効かない(たとえば ps2pdf が不十分な PDF を吐き出す)可能性があるのではないでしょうか?

その可能性はありますが,通常のPSファイルに対する ps2pdf であれば,問題なくPDFが出力できています。(美文書インストーラを作成したときにもテストは行いました。)

aminophen commented 8 years ago

.setpdfwrite の効果はパフォーマンスが上がる程度と gs のドキュメントに書かれていますので、たかだかその程度で済んだというところだと思います。

美文書だけのために pdfwrite に /stroke の再定義を封じられるのは変なので、美文書の gs サポートは諦めるほかない気がします。バイナリを /Applications/TeXLive/mactexaddons に抱え込む前提であれば、それにあわせて rebuild するべきだったということでしょうか…

aminophen commented 8 years ago

なんとか美文書のような特殊な方法でインストールされた gs でも -c による拡張を使える方法があればよいわけですね(-c による拡張を全面的に封じられているとすればそれはかなりまずい)。美文書環境の再現法はこれでわかりましたので試すことはできますが、見込みは薄いです。

doraTeX commented 8 years ago

うーん,自分が美文書gsユーザであることもあり,美文書gsの利用を封じられるのは厳しいです……。 それよりは,EPS経由のルートを利用し,pdfwrite でのパスのアウトライン化を行うのを回避する方がありがたいです。

バイナリを /Applications/TeXLive/mactexaddons に抱え込む前提であれば、それにあわせて rebuild するべきだったということでしょうか…

インストール先をインストーラで柔軟に変更できる設計にするために,「MacTeXのgsビルド+ラッパースクリプト」という構成をとっていました。

aminophen commented 8 years ago

インストール先をインストーラで柔軟に変更できる設計にするために,「MacTeXのgsビルド+ラッパースクリプト」という構成をとっていました。

そういえば Unix 的インストールと Mac 的インストールがありましたね。それだとしょうがないか…

EPS経由のルートを利用し,pdfwrite でのパスのアウトライン化を行うのを回避する方がありがたいです。

ではその方向で進めましょう。

-c による拡張を使えるようにする回避策」の探索も、別の task として後々考えることとします。

aminophen commented 8 years ago

-c による拡張を使えるようにする回避策」の探索も、別の task として後々考える

早速できてしまいました。ただし一手間かかります。この方法は、gs のドキュメントに書かれている -c オプションの解説に登場する equivalent な方法です。

たとえば、以下を pdfLaTeX でコンパイルして出てくる dash.pdf を stroke から strokepath fill に変換することを考えます。

% dash.tex
\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\begin{document}
\begin{tikzpicture}
\draw[dashed](0,0)--(1,0);
\draw[dashed](2,0)--(1,1);
\end{tikzpicture}
\end{document}

この場合、次の内容の set-strokepath.ps ファイルを適当な場所に置きます:

.setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def

そして、コマンドは以下のようにします(gs-bibun というのは先ほどの教えていただいたシェルスクリプトです):

$ gs-bibun -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=dash-out.pdf -dAutoRotatePages=/None /path/to/set-strokepath.ps dash.pdf

そうすると、出てくる dash-out.pdf はストロークのアウトラインがとられた状態になります。

コマンドの見た目は以前に登場した「gs で PDF / PS / EPS を結合する」と同じですが、PS にページ描画命令が入っていないため、以上の作業が可能になります。

もちろん

$ gs-bibun -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=out.pdf -dAutoRotatePages=/None -c ".setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def" -f in.pdf

を実行すると

GPL Ghostscript 9.18 (2015-10-05)
Copyright (C) 2015 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Error: /syntaxerror in -file-
Operand stack:
   stroke
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push
Dictionary stack:
   --dict:1193/1684(ro)(G)--   --dict:0/20(G)--   --dict:79/200(L)--
Current allocation mode is local
GPL Ghostscript 9.18: Unrecoverable error, exit code 1

を再現することもできていますので、gs-bibun を作成したテスト法は合っているつもりです。

doraTeX commented 8 years ago

そういえば Unix 的インストールと Mac 的インストールがありましたね。

「Mac風」「Unix風」の2つのテンプレートを選べるほか,そのテンプレートを土台として,テキストボックスの内容を書き換えることで,インストール先はユーザが任意にカスタマイズできるようになっています。 そういう事情で,ラッパースクリプトが必須となるわけです。

外部 ps を経由する方法でうまくいくことは確認できました。 これで「美文書 gs では -c を用いたカスタマイズができない」という問題を回避することができて幸いでした。

ただし,

gs 9.16 では,stroke 改変付き pdfwrite 自体はとおるものの,それを mudraw にかけてもやはりパターンが欠けます。

確かに SVG になったときにパターンがみえるのは out3.svg だけですね。out3.pdf をよくみると、パターンにカーソルをあてると文字のように選択できて xxxxxxxx... となります。不思議。

という問題は依然として変わりませんでした。

美文書方式 gs 9.18 + 外部 ps 方式で pdfwrite で in.pdf をアウトライン化し,それを mudraw で svg にしても,SVG上はやはりパターンが欠けてしまいました。

そもそも,mudraw にかける以前の問題として,

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dNoOutputFonts -sOutputFile=dash-out.pdf -dAutoRotatePages=/None stroke.ps in.pdf

によって生成する dash-out.pdfを Illustrator で開くと,次のようになり,見た目が全く異なります。

2015-12-11 19 29 13

そして,この模様の部分はアウトライン化されていません。

つまり,

.setpdfwrite /oldstroke /stroke load def /stroke {strokepath fill} def

では,「パスのアウトライン化」は可能でも,「塗りパターンのアウトライン化」はできていないことが分かります。

「塗りパターンのアウトライン化」を行う PostScript コードはあるのでしょうか?

doraTeX commented 8 years ago

dash-out.pdf を Illustrator で開くと,次のようになり,見た目が全く異なります。

そもそも,最初の in.pdf 自体が,Preview / Acrobat で開いた場合(斜線に見える)と,Illustrator で開いた場合(斜め破線に見える)で見た目が違いますね……。

doraTeX commented 8 years ago

以前言及したように,previewパッケージを経由しておく方法も試してみました。

\documentclass[dvipdfmx]{article}
\usepackage{tikz}
\usetikzlibrary{patterns}
\pagestyle{empty}
\usepackage[dvipdfmx,tightpage,active]{preview}
\PreviewEnvironment{tikzpicture}
\begin{document}
\begin{tikzpicture}
\filldraw[pattern = north east lines] (0,0) rectangle (5,5);
\end{tikzpicture}
\end{document}

生成PDF :in-preview.pdf

2015-12-11 20 08 02

aminophen commented 8 years ago

外部 ps を経由する方法でうまくいくことは確認できました。 これで「美文書 gs では -c を用いたカスタマイズができない」という問題を回避することができて幸いでした。

これは奥村先生に一応お伝えしておいたほうがよいと思いました。あとでこちらから伝えておきます。(そもそも今まで上がってこなかったということは、gs の猛者は美文書ユーザにいなかった?)

パターンが変わるという問題は、なんだか mudraw のせいではなさそうなので、あとでそれも調べてみます。(昨日アドベントカレンダーの記事を書き始めたばかりで間に合わせるのに必死です…)

doraTeX commented 8 years ago

このgsのパッケージングを行ったのは山本さんなので,山本さんにもご一報を入れる必要があるでしょうね。

doraTeX commented 8 years ago

あと,もちろん著者であられる黒木さんにも。

aminophen commented 8 years ago

そうなのですね。では山本さんにもお知らせしておきます。もちろん黒木さんも。

aminophen commented 8 years ago

メールは送信しました。

TikZ の塗りパターンはさすがに stroke で書かれていないのでしょうから、stroke を再定義してもダメでしょうね。塗りパターンが gs のどの命令に対応するのか、今度ゆっくり調べておきます。

abenori commented 8 years ago

今更ながら試してみたら(一番最初の例を)確かにうまく行かないですね.だけどなんだか非常に微妙で(というか仰っている通りで)手元では

となりました.しかも,一つ目と二つ目の生成されたSVGの違いは命令の有無とかではなく座標か何かの値が違うだけに見えます.何でそれだけでだめになるんだろう.

aminophen commented 8 years ago

ややこしいので、一度まとめます。テストに使用したバージョンは TeX2img for Mac 2.1.4 / gs9.16 / mudraw 1.7a です。

テストファイルの作成

ここから、pattern.pdf と pattern.pdf を入力として画像変換していきます。

TeX2img for Mac 2.1.4 に通す

透過・余白なし・テキスト保持のスキームで SVG を出す(つまり pdfcrop メイン)

透過・余白なし・アウトライン化のスキームで SVG を出す(つまり pdfcrop + gs メイン)

gs や mudraw を手動で実行

直接 mudraw にかけて SVG を出す

いったん gs の pdfwrite に通して(アウトライン化なしの“ロンダリング”)から mudraw にかける

gs のコマンドは

$ gs -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=filename-pdfwrite.pdf -c .setpdfwrite -f filename.pdf

mudraw のコマンドは

$ mudraw -o filename.svg filename(-pdfwrite).pdf

観察結果

凡例:

PDF on Acrobat Pro X

すべて同じみため。

PDF on Inkscape 0.48.5 (Lion, X11)

gs を通す前は斜め破線にみえ、通した後はおびただしい数の細かい斜め破線になる。

SVG on Safari 6 (Lion)

preview を通さない場合のみ TeX2img はテキスト保持でもアウトライン化でもパターンが消える。

SVG on Inkscape 0.48.5 (Lion, X11)

gs を通った場合だけ一瞬みえて消えて再び現れるという変な挙動を示す。

というわけで、いまのところ◎としてよい SVG はひとつも出てきません…が、少なくとも一律に○以上が出るのを目標にとりあえず調節することにしましょう。

ファイルのセットも用意しました:こちら。セットには PDF を調べやすいように、それぞれのファイルを qpdf で uncompress したものも同梱しました。

$ qpdf --stream-data=uncompress filename.pdf qpdf-filename.pdf
doraTeX commented 8 years ago
pdftops -eps pattern.pdf out1.eps
echo "/oldstroke /stroke load def /stroke {strokepath fill} def" | cat - out1.eps > out2.eps
epstopdf -outfile=out3.pdf out2.eps 
mudraw -o pattern-pdftops.svg out3.pdf

として pattern-pdftops.svg を作るルートはいかがでしょうか。 以前の実験では,このルートでのみパターンが保持されました。

aminophen commented 8 years ago

pdftops を経由する方法を試してみました。SVG を Safari でみると○(微妙に欠ける)・Inkscape でみると△(動かすとみえる)、その前の out3.pdf を Adobe でみると◎・Inkscape でみると▲(拡大するとおびただしい数の斜め破線)でした。→ 追記:これは Poppler 0.38.0 の pdftops です

doraTeX commented 8 years ago

ファイルセットのURLが壊れているのかダウンロードできなかったのですが,URLを加工してダウンロードできました。 ダウンロードして得られたファイルセットに対して,上記の pdftops を試してみた結果は次の通りです。

これらのSVGは,Safariで見ると完全に綺麗につながっている(◎)ように見えます。 (その代わり,他の方法で生成したSVGと比べて,ファイルサイズが100倍以上あります。)

aminophen commented 8 years ago

(リンク修正しました。ありがとうございます。)

ダウンロードして得られたファイルセットに対して,上記の pdftops を試してみた結果は次の通りです。

あれ、うちで作ったものはファイルサイズがほかとほぼ同じです… → 追記:これは Poppler 0.38.0 の pdftops です

aminophen commented 8 years ago

ところで、qpdf で uncompress した PDF をみていて気づいたことが一つあります。

本件で問題の TikZ のパターンは、PDF Reference 1.7 の 4.6 節に登場する Patterns で描かれています。qpdf-patterns.pdf をテキストエディタで見たときの

10 0 obj
<< /BBox [ -.99628 -.99628 3.9851 3.9851 ] /PaintType 2 /PatternType 1 /Resources << >> /TilingType 1 /Type /Pattern /XStep 2.98883 /YStep 2.98883 /Length 43 >>
stream
q 0.3985 w 0.0 0.0 m 3.08846 3.08846 l S Q endstream
endobj

が該当します。どうやらパターンの繰り返し単位(の描画内容とバウンディングボックス)を指定しているらしく、これが別の obj から参照されて繰り返し描画されるのでしょう。

先ほどの▲にあたる「拡大するとおびただしい数の…」は、一部は gs のせいでしょう。gs は「再描画」する際に座標系を10倍に拡大するらしいことがわかっています:引用

10倍に座標系が拡大されているが、500 6000 3700 0 S がどうやら一本のストロークを描画しているようで、ここに破線配列が適用されている。

座標系を拡大しているのに、gs はこのパターンの座標変換を完全には行っていない気がします。qpdf-patterns-pdfwrite.pdf の以下がそれっぽいです:

13 0 obj
<< /BBox [ -0.99628 -0.99628 3.9851 3.9851 ] /Matrix [ 1 0 0 1 -0.00390625 -0.00390625 ] /PaintType 2 /PatternType 1 /Resources << /ExtGState << /R4 11 0 R >> /ProcSet [ /PDF ] >> /TilingType 1 /Type /Pattern /XStep 2.98883 /YStep 2.98883 /Length 105 >>
stream
0.1 0 0 0.1 0 0 cm
/R4 gs
q
-9.96094 -9.96094 49.8086 49.8086 re W n
3.985 w
0 0 m
30.8828 30.8828 l
S
Q
endstream
endobj

パターンの描画内容は座標が拡大されているようなのですが、パターンの BBox や Step が元のままにみえます。

doraTeX commented 8 years ago

pdftops を経由させる Ver. 2.1.5 beta 1 を作りましたので,これで pattern.pdf や patternpr.pdf のSVG化を試してみてください。 こちらでは(斜線パターン・余白有無・背景塗り有無も含めて)うまく動いているように見えます。 (白紙ページ対応などのエラー処理は未実装です。)

aminophen commented 8 years ago

Mac 環境を離れたので、明日テストします。「pdftops 経由」だとアウトライン化 SVG の場合はどういう風になるのでしょうか?(もしかして gs 経由後の PDF でも pdftops を通すと復活?)

doraTeX commented 8 years ago

あ,TeX2imgはEPS経由でテキストを保持する経路はサポートしておりませんので,今回の「pdftops経由によるSVG生成」はアウトライン化SVG生成にのみ作用します。

Ver. 2.1.5 beta 1 で生成したアウトライン化SVGは以下の通りです。

El Capitan の Safari では,綺麗に表示されます。 ただしファイルサイズは1.3MBまでふくれあがっています(他の方法で作ったSVGは2KB程度)。

aminophen commented 8 years ago

具体的な経路がわかっていないのですが、アウトライン化 SVG ということは手前で gs の pdfwrite か epswrite でアウトライン化しているわけですよね。そうすると、mudraw はもう二度と Inkscape で正しく表示できる SVG を作れなかったわけで、ブラウザ専用の SVG しかできないとなるとあまり根本的な解決になっていないと思うんですよね…(しかも私のところでは SVG が同じコマンドでも巨大にならなかったのでどこが違うのか…?→ 追記:これは Poppler 0.38.0 の pdftops です。)

doraTeX commented 8 years ago

こうしてできたSVGを Illustrator で開いてみたら,謎の暗号のような表示になりました……(pattern-215b1.svgpatternpr-215b1.svg の両方同様)。

2015-12-14 20 00 52

ブラウザ専用の SVG しかできないとなるとあまり根本的な解決になっていないと思うんですよね…

確かに。そう考えると,やはり「一律で○以上になる方法を探す」方がよさそうですね。

aminophen commented 8 years ago

そして、私はいまだに「Inkscape で斜め破線に見える PDF(●)」の状態から Inkscape でパスを変形する方法を探してはいるのですが、見つかっていません。ここで変形できれば、新旧 PDF のソースを見比べて原因を特定できるのですが…(前の破線の応急処置のときは、ソース中の該当箇所をそうやって発見しましたし)

doraTeX commented 8 years ago

同じく ● の見え方をする Illstrator で,塗りパターンをアウトライン化してみたらこうなりました

aminophen commented 8 years ago

pattern.pdf と pattern-illustrator.pdf を比較するとだいぶ PDF の内部構造が変わっていますが、確かにパターンがパスに変形されていますね。うーん、どこから手を付けていいのやら。

比較しやすいように、「pattern.pdf を単に Illustrator で開いて別名で保存しなおしただけ」というのもいただけますか?

doraTeX commented 8 years ago

こちらです。

aminophen commented 8 years ago

なるほど、「塗りパターンをアウトライン化」というのは /Pattern オブジェクトを完全に壊して PDF を再構成しているのですね。この前の破線のときのような小さな変更ではないため、すぐには分かりませんがもう少し調べてみます。

aminophen commented 8 years ago

とりあえず、検証用に pattern.pdf とほぼ同等の見た目をつくる最小の PostScript コードを置いておきます。最後に登場する 0 0 500.0 800.0 rectfill の範囲を変えれば pattern.pdf と同じものを描けます。

%!PS-Adobe-3.0
currentcolor
<< % Begin pattern dictionary
  /PatternType 1
  /PaintType 2
  /TilingType 1
  /BBox [-0.99628 -0.99628 3.9851 3.9851]
  /XStep 2.98883
  /YStep 2.98883
  /PaintProc {
    gsave
      0.3985 setlinewidth
      0 0 moveto
      3.08846 3.08846 lineto
      stroke
    grestore
  }
>> % End pattern dictionary
matrix % Identity matrix
makepattern setpattern
0 0 500.0 800.0 rectfill
showpage

これをアウトライン化したいわけですよね…うーん。

aminophen commented 8 years ago

少しずつ分かってきたことがあるので追加情報です。

すぐ上のコメントの例示 PS コードを見ていただくと分かりますが、この Issue は「ある図形が単色塗りで fill されたのではなく、パターンのタイリングで fill された場合」の問題であることがわかっています。このような Pattern Fill が PostScript でサポートされたのは PostScript Level2 以降となっています。このような Pattern Fill を PostScript Level1 で emulate する方法として Adobe が例示している方法が、Adobe TechNote #5112 にあります。具体的には「特殊な見た目を持つ Type3 フォントを並べて敷き詰める」というものです。

これを実践した一例が pdftops にあたります。私のコメント

パターンにカーソルをあてると文字のように選択できて xxxxxxxx... となります。不思議。

と書いたのはまさにその証拠で、pdftops の場合は「単位タイルの描画内容を x のグリフだけ定義した Type3 フォントに格納し、x を敷き詰める」という手法で、これは結果的に「完全にパターン辞書を崩して平易化」に成功しています。したがって、「pdftops を使う」は一つの解決策としてアリでしょう。文字 x が選択できて気持ち悪いのですが、そのあとにアウトライン化を通せばグリフのアウトライン化によって OK になります。

こうしてできた PDF は、必ず元と同じ見た目になるのではないかと思います(この新しい PDF を mudraw にかければ SVG も正常なはず)。ただ、個人的には pdftops を経るのはあまり好みではないです(Windows 版では新たにつけないといけませんし、極力 EPS を経たくない)。Adobe TechNote に記載されている emulate を gs だけでできないでしょうか? あるいは、pdftops の当該部分のコードを TeX2img に取り込めないでしょうか?

doraTeX commented 8 years ago

こうしてできた PDF は、必ず元と同じ見た目になるのではないかと思います(この新しい PDF を mudraw にかければ SVG も正常なはず)。

確かに,そうなりました。PDFの見た目は正常です。これを mudraw にかけて得られたSVGは,ブラウザでの見た目は

2015-12-17 3 33 24

となり,正常です。

Illustrator での見た目は

2015-12-17 3 32 58

と,真っ黒になってしまいましたが,アウトライン表示をしてみると

2015-12-17 3 33 02

となっており,確かに斜め線のパスが生成されていることが分かります。 これも「正常」のうちに入るでしょう。

Mac版は pdftops を既に内包していますので,もし gs での emulate 法が見つからなければ,アウトライン化SVG生成はこの経路で行くことにしましょう。