カラー EPS 画像をコマンド一発でグレースケール変換するワンライナー

カラーの EPS 画像をコマンド一発でグレースケール変換するワンライナーです.特に,Illustrator などでグレースケール化するとファイルサイズが肥大して嫌だという人や,ファイルが大量にある人には便利かと思います.



MATLAB R2006b が吐いた EPS (RGB カラー) の場合,

% perl -p -i.bak -e 's/([0-9.]+) ([0-9.]+) ([0-9.]+) sr/0.299*$1+0.587*$2+0.114*$3." sg"/e;' hoge.eps

Illustrator 10 が吐いた EPS (CMYK カラー) の場合,

% perl -p -i.bak -e 'use List::Util qw(min);s/([0-9.]+) ([0-9.]+) ([0-9.]+) ([0-9.]+) cmyk/"0 0 0 ".(0.299*min(1,$1+$4)+0.587*min(1,$2+$4)+0.114*min(1,$3+$4)." cmyk")/e;' hoge.eps

でいけます.ただし,特殊な図の場合は無理かも.汎用性はあまり確かめてませんし,バージョン依存の可能性もあります.他のアプリケーションで生成した EPS にも使える場合があるかも知れません.バックアップがいらない人は -i.bak を外して下さい.なお,変換式には諸派があるので,あくまで「なんちゃってグレースケール」ということでよろしく.



発端は昼飯時の職場の後輩との会話.



後輩: カラーの PDF をグレースケールにする簡単な方法ってありませんかね?

私: うーん… Illustrator で読み込んでモノクロにできなかったっけ? 自信ないけど.

後輩: できるんですかね? Photoshop でやろうとしたら全体が画像になっちゃってダメでした.

私: あ,Acrobat Distiller にそういう機能なかったっけか?

後輩: それがないんですよ.ていうか MATLAB が吐いた EPS 画像を全部グレースケールにしたいだけなんですけどね.

私: え? 普通に Illustrator で EPS を開いてグレースケールにするんじゃだめ?

後輩: いやー,MATLAB が吐いた EPS を Illustrator で開くととんでもなく肥大化しません? あれが嫌なんです.

私: あーなるほど.うーん…,EPS の PostScript を直接書き換えちゃえばいいんじゃね? …ていうか昔そういうことをやったような記憶が微かにある.むはー.調べてみるか.

後輩: (やや引きつつ) お,おながいします….



というわけで,記憶をひもといてみたところ,昔やったのは「カラー文書を Unix から PostScript プリンタに印刷する時に,プリンタ固有のコードをジョブに追加することで無理矢理モノクロ印刷させる hack」であって,今回のようにファイルそのもののモノクロ化ではなかった (この話はいつか書くかも).あとは EPS 画像内のハイフン記号をマイナス記号に変換する話とかもあったか [2005-11-18].でもまあ,今回も同じ手法が使えるはず,ということで,今日締切の仕事をほっぽりだして現実逃避開始(激ぉ



まず,MATLAB の場合から.同じ図をカラー化したものとモノクロ化したものをそれぞれ保存して diff をとる,というのが基本方針.



MATLAB プロットでは,RGB カラーテーブルは例えば以下のように表現されていることがわかった.

0.000000 0.000000 0.000000 sr
1.000000 1.000000 1.000000 sr
0.900000 0.000000 0.000000 sr
0.000000 0.820000 0.000000 sr
0.000000 0.000000 0.800000 sr
0.910000 0.820000 0.320000 sr
1.000000 0.260000 0.820000 sr
0.000000 0.820000 0.820000 sr

小数の triplet が RGB 成分を,sr が RGB カラーであることを示している (ただし,数値は MATLAB のバージョンによって異なるようで,以前は原色が使われていた).順に black,white,red,green,blue,yellow,magenta,cyan に相当する.



いっぽう,グレースケールの場合は,

0.50000 sg

のように表され,数値が輝度,sg がグレースケールであることを示している.なので,前者の表現から後者の表現に変換してやればよいことになる.



ではどのように変換するか? ここでは,よく使われている RGB→YIQ 変換を使うことにする (人間の視覚特性を考慮した重みづけがなされている).ここで,Y が輝度を表す.

  Y = 0.299R + 0.587G + 0.114B

つまり,EPS ファイルの中から RGB 成分を抜き出して上式で変換したもので置換してやればよいわけだ.このワンライナーでは Perl の s 関数に e オプションをつけて,置換部分を式として評価させている.



いっぽう,Illustrator の吐くファイルの場合はもう少し複雑で,色は CMYK 空間で表現されている.

..0157 .2431 .2863 0 cmyk

そこで,CMYK→RGB→YIQ 変換を行う.RGB と CMYK の関係は,

R = min(1, C+K)
G = min(1, M+K)
B = min(1, Y+K)

となっているので (諸派あるが,最も単純なものを用いた),これを用いて

0 0 0 0.1800322 cmyk

のように K 成分のみに輝度情報を入れてやれば OK.Illustrator でグレースケール化したものと値を比べてみたが,だいたい近い値にはなっているようだ.



ワンライナー万歳!