: O. Yuanying

RailsでQRコードを生成する

QRコードクラスライブラリ for Rubyダウンロードする。

QRコードをpng画像で出力するにはruby-GDライブラリが必要とのこと。つーわけでlibpng3やらGDライブラリとともにruby-GDライブラリをインストール。私はパッケージ管理にFinkを使ってるので以下のようになった。

libpng3のインストール

[yuanying@Kiriko test]$sudo apt-get install libpng3
Reading Package Lists... Done
Building Dependency Tree... Done
The following extra packages will be installed:
...

GDライブラリのインストール

[yuanying@Kiriko test]$sudo apt-get install gd2
Reading Package Lists... Done
Building Dependency Tree... Done
The following extra packages will be installed:
  gd-bin gd-shlibs libjpeg-shlibs 
...

ruby-GDのインストール

RAAから最新版のruby-GDをダウンロードする。

ruby extconfコマンドでMakefileを生成するようだが、念のため--with-gd-include=/sw/include --with-gd-lib=/sw/libと指定する。Linuxの場合はデフォルトで多分平気。

[yuanying@Kiriko src]$wget http://raa.ruby-lang.org/cache/ruby-gd/ruby-GD-0.7.4-1.tar.gz
...
[yuanying@Kiriko src]$tar zxvf ruby-GD-0.7.4-1.tar.gz 
ruby-GD-0.7.4/
...
[yuanying@Kiriko src]$tar zxvf ruby-GD-0.7.4.tar.gz
[yuanying@Kiriko src]$cd ruby-GD-0.7.4
[yuanying@Kiriko ruby-GD-0.7.4]$ruby extconf.rb --with-ttf --with-gd-include=/sw/include --with-gd-lib=/sw/lib --enable-gd2_0
...
[yuanying@Kiriko ruby-GD-0.7.4]$make
[yuanying@Kiriko ruby-GD-0.7.4]$sudo make install
/usr/bin/install -c -m 0755 GD.bundle /usr/local/lib/ruby/site_ruby/1.8/i686-darwin8.5.2

RailsアプリにQRコードライブラリを追加し設定を行う

QRコードを生成するRailsアプリのlibフォルダ以下にQRコードクラスライブラリ for Rubyを展開してやる。

[yuanying@Kiriko Downloads]$wget http://www.venus.dti.ne.jp/~swe/program/qrcode_rb0.50beta8.tar.gz
...
[yuanying@Kiriko Downloads]$tar zxvf qrcode_rb0.50beta8.tar.gz 
qrcode_rb0.50beta8/
qrcode_rb0.50beta8/qrcode.rb
qrcode_rb0.50beta8/sample1.cgi
...
[yuanying@Kiriko Downloads]$cd qrcode_rb0.50beta8
[yuanying@Kiriko qrcode_rb0.50beta8]$ll
total 104
-rw-r--r--     1 yuanying  yuanying   6246  5 27 13:05 README.txt
-rw-r--r--     1 yuanying  yuanying    851  1 13  2003 b.png
-rw-r--r--     1 yuanying  yuanying    848  1 13  2003 d.png
-rwxr-xr-x     1 yuanying  yuanying  16322  5 27 12:57 qrcode.rb*
drwxr-xr-x   233 yuanying  yuanying   7922 12 26  2002 qrcode_data/
-rwxr-xr-x     1 yuanying  yuanying   1963  7 24  2004 qrcode_img.rb*
-rwxr-xr-x     1 yuanying  yuanying    514  7 24  2004 sample0.rb*
-rwxr-xr-x     1 yuanying  yuanying    715  1 13  2003 sample1.cgi*
-rwxr-xr-x     1 yuanying  yuanying    107  5 27 13:06 sample1.rb*
-rwxr-xr-x     1 yuanying  yuanying    653  5 29  2004 sample2.cgi*
[yuanying@Kiriko qrcode_rb0.50beta8]$cp -r * ~/project/rails/test/lib/

Readmeを読んでみると、

qrcode.rbの10行目

@path="./qrcode_data"

をデータディレクトリに合わせて変更してください。

と、書いてあるので、qrcode_dataディレクトリを適切に指定してやる。今回はライブラリをlibフォルダ以下につっこんだので、多分こうなる。

...
def initialize
    @path="#{RAILS_ROOT}/lib/qrcode_data"

    @qrcode_error_correct="M"
...

RailsアプリからQRコードを出力する

それではテストを兼ねてRailsアプリからQRコードを出力してみる。

QrCodeコントローラにindexというメソッドを追加し、以下のように記述する。

def index
  require'qrcode_img'
  @headers['Content-Type'] = 'image/png'
  x = Qrcode_image.new
  # GD::Imageオブジェクトが返る.
  img = x.qrcode_image_out('/log/','png')
  # 文字列として出力し、Content-Typeをimage/pngとする.
  render :text => img.pngStr, :layout => false
  img.destroy
end

サーバを起動し、http://localhost:3000/qr_codeにアクセスしてみる。

見れましたか?

アプリケーションエラーになっちゃう場合

本来ならこれで見れるんだけど、たぶん日本人が作ったアプリケーションだった場合、ほぼ確実にエラーがでてしまってQRコードが生成されない。Nasuta開発ブログの「QRコードの生成について」というエントリにあるようにどうやら文字コードの問題のようだ。

具体的に言うと日本語を利用したRailsアプリの場合、config/environment.rbで$KCODEを指定することが多いと思うのだけど、これを指定することによりRegexpクラスの挙動が変わってしまうことが原因

$KCODEがスレッドローカルな変数だったのならQRコードを生成するメソッド内のみで$KCODEを指定し直せば良いと思われるが、残念ながらグローバルスコープの変数の模様。

というわけでqrcode.rbの方を修正する。qrcode.rbをvendorフォルダではなく、libフォルダにいれたのは修正作業や編集作業が発生するからだったのだ。

修正するのはqrcode.rbの591行目から606行目までのあたりで、Regexp.compileしているところ。

Regexp.compileに第三番目の引数を与えることによってRegexpのエンコーディングフラグをデフォルトに変更しなおしてやる。

# FIX
    demerit_n3 = (hor_temp.scan(Regexp.compile(n3_search, false, 'n')).size)*40

    demerit_n4 = ((((ver.count(n4_search)*100) / byte_num)-50)/5).abs.to_i * 10

    demerit_n2=0
    
    # FIX
    ptn_temp=ver_and.scan(Regexp.compile(n2_search1, false, 'n'))
    ptn_temp.each{|te|
        demerit_n2+=(te.length-1)
    }
    # FIX
    ptn_temp=ver_or.scan(Regexp.compile(n2_search2, false, 'n'))
    ptn_temp.each{|te|
        demerit_n2+=(te.length-1)
    }
    demerit_n2*=3

    # FIX
    ptn_temp=hor.scan(Regexp.compile(n1_search, false, 'n'))

てか久しぶりに長文書いたなあ...。

関連エントリ