PowerShell

ImageMagickでEPSファイルからJpegへ変換

大量のEPSファイルからJpegを出力する必要があった。
確かAdobe CCなら複数ファイルにアクションを適用して一気に処理が出来るはず…
Adobe アクションおよびアクションパネルについて
が、職場にはAdobe CS6が1アカウントしかない。
ということで、「ImageMagickなら何とかなるのでは?」と思ったら何とかなりました。
リサイズのためにImageMagickを使うバッチファイルを組んでいたので、それを流用しようかと思ったのだけど、バッチファイルは長らく触ってないし、仕組みが古すぎて煩雑になるので、やはりここはPowerShellである。
もしかしたら、ワンライナーもいけるか?と思ったら、ワンライナーできました。やっぱりPowerShellですね、先輩。

ImageMagickについて

ImageMagickはWindowsで適当にCドライブに放り込んで使っていたが、convertコマンドが動かない、というかエラー出して止まる。
パスを設定してもダメでフルパスでコマンドを叩くと行ける。同名コマンドが既にWindowsにあって、そちらを呼び出してしまうのが原因らしい。

重要! Windows のシステムには C:\Windows\System32\convert.exe という「FAT ボリュームを NTFS に変換するコマンド」が存在します. ImageMagick 6.9.3-9 以前の画像変換コマンド名は convert でしたので,これと Windows の convert を混同しないように注意が必要です.
TeX Wiki

Windows向けにインストーラーがあるので、最新版の7.0.6を入れ直す(17年8月時点)
コマンド毎のexeファイルから、magick一つになったので、コマンドの重複は回避された。
他に、EPSファイルを解析するためのOSSソフトGhostScriptが必要なので入れておく。
フォーマット変換自体はとても簡単なコマンドになっている。

PS C:\User\ > magick before.eps after.jpg

このように、変換後ファイルの拡張子で指定する。
しかし、Density(dpi)の指定が効かないのである。これが効かないと印刷用のプレビューかサムネイル並の低解像度の画像しか取り出せない。Densityのみ引数の順序で効いたり効かなかったりするようだ。
-densityを先頭に持ってきて、-negateで色調反転を指定、-geometry -resize -scaleいずれかで出力ピクセルサイズを指定。単体ファイルを処理するコマンドは一旦こうなった。

PS C:\User\ > magick -density 300 picture.eps -resize 1200x1200 -negate picture.jpg

PowerShellでパイプラインを作る

Windowsで複数ファイルを一括処理するなら、いにしえよりバッチファイルと相場が決まっているが、まあ面倒だし、長らく触ってないのでPowerShellを使う。
特定フォルダ以下のEPSファイルのみを取得するなら、Get-ChildItemFilterを組み合わせる。

Get-ChildItem -Recurse -Filter *.eps -depth 1

シンプル。このコマンドで1階層下のサブフォルダまでのEPSファイルを取得できる。
PowerShellでファイルの一覧を取得
ちなみにGet-Childern -Recurseは、ls -rでも実行可能。
次にパイプでmagickコマンドに渡す。
PowerShellのパイプはオブジェクトを渡す仕様になっている。Linux系でのBashでは標準出力が渡されていくので、若干勝手が異なる。パイプライン内でのオブジェクトは$_変数にて表される。
Get-ChildItemで取得したファイル一個ずつに処理をしたい場合は

Get-ChildItem -Recurse -Filter *.eps -depth 1 | Foreach ($_) { Commandlet }

|パイプを繋いでパイプラインを構築し{ }内に単体処理のコマンドレットを書く。
Foreach ($_)ForEach-Objectでもいいし、もっと簡単に% { Commandlet }とも書ける。
(挙動がForEach-Objectと%は同等、Foreachは異なるが、今回はどれでもOKのはず)
Get-ChildItemにて取得したファイルのフルパスを出力させるには…

Get-ChildItem -Recurse -Filter *.eps -depth 1 | Foreach ($_) { echo $_.fullname }

ファイルの一覧からパスを取得
これで複数フォルダに入っているEPSファイル群のパスが取得できた。
先に出力ファイルのパスを作ってみる。フルパスの最後、拡張子の文字列を置き換える。

$_.fullname.replace("eps","jpg")

fullname は文字列オブジェクトなので、replaceメソッドを使って、epsをjpgに書き換える。
というわけで { } 内のImageMagickを使った単体処理のコマンドレットは

magick -density 600 $_.fullname -scale 1200x1200 $_.fullname.replace("eps","jpg")

これを全て組み合わせると、複数のEPSファイルをJPG変換するワンライナーのできあがり。

Get-ChildItem -Recurse -Filter *.eps -depth 1 | foreach($_) { magick -density 600 $_.fullname scale 1200x1200 $_.fullname.replace("eps","jpg")}

これでカレントフォルダ内のepsファイルを1200pxのjpgへ変換できる。

CMYKとRGB

少し処理をしてみたところ、若干、画像が暗いように見えた。元が印刷用だからCMYK-RGBの変換かな?と思って調べてみたところ、下記の記事で同じことをやってた。
大量の印刷用画像をウェブ用に変換する方法 クックパッド開発者ブログ
ICCカラープロファイルを指定しての変換が可能らしい。すごいぞ、ImageMagick。
記事と異なっていたのは、

  1. 変換後のカラープロファイルしか指定が効かない
  2. カラーマネジメントシステムであるLittle CMSは不要だった

ということで、最終的なワンライナーはこうなった。

PS C:\Users\ > Get-ChildItem -Recurse -Filter *.eps -depth 1 | foreach($_) { magick -density 1200 $_.fullname -profile sRGB_v4_ICC_preference.icc -scale 1200x1200 -negate -modulate 110 $_.fullname.replace("eps","jpg")

Density 1200はやりすぎの様に思うが、何せ最大解像度で出力させたかったのでこの値とした。通常、カラー印刷は300dpi~350dpiである。
Modulate 110で明るさを110%にした。

使ってみて

処理中はWindowsが重くなる、また処理にやたら時間のかかるファイルがあったりするなど、多少の問題はあったが、変換自体は問題なし。
ImageMagickは高性能なので、大量の画像ファイルを処理する必要があるときは重宝する。EPSファイルも扱えるとは思わなかった、強力。
OSS is 強い。
かくして、誰かがイラレでEPSを開いてはJpeg保存、開いてはJpeg保存することはなかった。