まめ畑

ゆるゆると書いていきます

RubyでQRコードを作るには

唐突ですが、RubyQRコードを吐き出したいと思いライブラリを探していたらもちろんあったのですが、若干挙動に不安が。
というわけで諸々メモ。
今回はWindows上のRuby1.8.6で行っています。(いい加減バージョン上げなければ)


Ruby qrcodeでググルと一番最初にQRコードクラスライブラリ for Ruby - QRcode encode class library for Rubyがヒットしますが、こちらはPHP版からの移植で、かつRuby/GDが必要とされておりWindows上でRuby/GDを使うには若干面倒。参考→無理やりWindowsでruby/gd - Ryoの開発日記
なので、探していたらありました。
gemで入れられます。


rqrというライブラリです。
公式サイトはrqr
PS・JPEG・PNG・EPS・TIFF形式で出力出来ます。
リリースエントリを参照すると

サイテック社にてフリーソフトとして配布されているC++のコアをANSIに対応し、rubyでラッピングしました。
extを使っているため比較的高速に動作しますし、ひと通りの画像形式で出力できるという特徴を持っています。

pools.jp | rubyでQRCodeを作成するライブラリrqrをリリース

と書いてあります。
Windows用のパッケージを開くと、QR.soが入っています。


インストールは簡単で

gem install rqr

で完了です。

もしくは、http://rubyforge.org/frs/?group_id=6324:title:bokmarkからWindows用のパッケージをDLして

gem install rqr --local

でも可能です。


Linuxでは

yum install libjpeg
yum install libpng
yum install libtiff

が必要です。

Portを使ったインストール方法などは公式ページにまとまっています。

ちなみに、Ubuntuでは

sudo apt-get install libjpeg-dev
sudo apt-get install libpng12-dev
sudo apt-get install libtiff-dev

です。


しかし、ここで問題が。
インストール中に

No definition for _wrap_CQR_Encode_m_nSymbleSize_set
No definition for _wrap_CQR_Encode_EncodeData

の様なエラーが続々と出ます。
しかし、インストールは成功し正常に動作します・・・。


createメソッドが取るオプションは

# QRCode options (passed to RQR::QRCode.new())
# Use options with hash values.
# :level L:0, M:1(default), Q:2, H:3
# :version S:0(default), M:1, L:2
# :auto_extent true|false auto extent if over version size
# :masking masking pattern 0-7, -1(default auto)
# :length data length
# :module_size module size (pixel)
# :eps_preview true|false

ですが、levelとversionが良くわからなかったのですが、バージョンはQRコードのサイズでレベルが高いほど情報をつめられる
levelはエラー訂正レベルで

レベルL 約 7%
レベルM 約 15%
レベルQ 約 25%
レベルH 約 30%

のエラー訂正が可能ですが、訂正レベルが高くなるほど追加の情報量が多くなります。
QRコードの詳しい事はQRコードドットコム|QRコードのバージョン|株式会社デンソーウェーブにまとまっています。


使い方は非常に簡単です。
公式サイトに書かれている通りです。
日本語も入力可能で改行ももちろん大丈夫です。
文字コードSJISにしないと日本語は化けてしまい読み取れません。
もちろん、日本語のファイル名も可能です。
ファイル形式は拡張子から判断しますが、第3引数にシンボルを渡す事でも指定可能です。

require 'rubygems'
require 'rqr'

$KCODE = "SJIS"

RQR::QRCode.create do |qr|
   qr.save("サイト\r\nhttp://mame-lab.com/", "hoge.png")
end

しかし、素直に作成されるわけではないです。
エラーが表示されます(画像は出力されますが)

c:/ruby/lib/ruby/gems/1.8/gems/rqr-0.2.2-x86-mswin32/lib/rqr/qrcode.rb:57:in `close': undefined method `close' for #<QR::QRDrawPNG:0x2d976f8> (NoMethodError)

closeメソッドない。
つまり、ストリーム閉じてないのか?
と思いソースを見ると。

該当箇所

def close()
   @encoder = nil if @encoder
   p @imager.respond_to? :close, true   #false <=追加して確認
   (@imager.close; @imager = nil) if @imager   #ここ
end

@imagerにcloseメソッドない模様。
しかし、これは

   def save_as_png(path)
      @imager=QR::QRDrawPNG.new
      @imager.draw(path, @options[:module_size], @encoder.m_nSymbleSize, @encoder.m_byModuleData, nil)
   end

各画像形式用のインスタンスを保持しています。
ここからはC++のソースを見ると

int QRDrawPNG::write()
{
   //画像書き出し用の処理

   fclose(stream);   //←閉じてる
   return(0);
#else
   return(1);
#endif
}

書き出しの段階でストリームを閉じているので問題は無いけれど、close関数ないのでメソッドないっすってエラーが出ている模様。
エラーは出ても画像は正常に書き出せているので、気になる場合は該当の箇所の判定を@imagerがnilかどうかではなく、closeメソッドがあるかどうかを判定したほうがいいかも。

ちなみにLinuxではcloseのエラーは出ないようです。


何か勘違いしてるかな?
指摘などありましたらコメントお願いします。