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とかで変換する・・・とか、いかがでしょう?