ImageMagickがInvalid UTF-8 sequenceを吐き出す
最近Rubyばっかり書いてる気がする。世の中わからないことでいっぱいだ。
convert -version
$ convert -version | grep Version Version: ImageMagick 6.9.0-0 Q16 x86_64 2015-02-03 http://www.imagemagick.org
困ったこと
ImageMagickがちょっとくらいおかしな文字を流してきたところで大抵の場合は問題がないんだけど、
つい先日serverspecでImageMagickの対応しているフォーマットをテストしようと下のようなテストコードを書いたら、
Invalid UTF-8 sequenceで落ちてしまい大変だった。
describe command("convert -list format") do let(:disable_sudo) { true } its { should match(/#{Regexp.escape('PNG24*')}/) } end
検証
example.rb
stdout = `convert -list format` p /PNG/.match stdout
結果:
example.rb:2:in `match': invalid byte sequence in UTF-8 (ArgumentError) from example.rb:2:in `<main>'
ですよねー。convert -list formatがInvalid UTF-8 sequenceを吐いているのだ。
Workaround
とりあえず、ぱっと思いついた方法は二つで、ServerSpec::Type::Command#stdoutを書き換えるか、
itsをやめてstdoutから不正なUTF-8文字を取り除いてsubjectにセットするか。
どっちでも簡単にできるけど、ServerSpec::Type::Command#stdoutを書き換えるのは何だか大げさな気がするので、
今回はstdoutから不正な文字を取り除く方法で対応することにした。
module Serverspec::Type class Command < Base def stdout command_result.stdout.scrub end def stderr command_result.stderr.scrub end end
まあ、こんなことをしてもいいんですが・・・。
describe command("convert -list format") do let(:disable_sudo) { true } subject { described_class.stdout.scrub } it { should match(/#{Regexp.escape('PNG24*')}/) } end
こっちのほうがいいかな。
described_classでdescribe対象のインスタンスServerspec::Type::Commandが取れるので、そのstdoutを持ってきます。
後は、subjectにstdout.scrubをセットしておしまい。
なお、String#scrubはRuby2.1.0で追加されたメソッドなので、2.1より前のバージョンではstring-scrub gemを入れる必要がある。
そもそも
ImageMagickのconvertコマンドが標準出力に書き出しているInvalid UTF-8 sequenceとは何なのか、ImageMagickのソースコードをちょっと追ってみました。
String#scrubには不正な文字を置き換える機能があるので、どの文字が不正なのか調べてみるとどうやらDJVUに怪しい?が・・・。
ということで、coders/djvu.cを見てみると、RegisterDJVUImage関数でentry->description=AcquireString("Déjà vu");というコードを見つけました。
AcquireStringはmemcpyしているだけなので、元の文字が壊れている気がする・・・。
最後に
イミワカンナイ
— シリル@にこまき勢 5thありがとう (@t_cyrill) 2015, 2月 4
追記
UTF-8ではなくlatin 1なのではという話がありました。iconvとかで変換する・・・とか、いかがでしょう?