RubyでQRコードを生成してみる

あらすじ

この記事は Ruby Advent Calendar 2013 - Qiita [キータ] の 24 日目の記事です。

  • 23 日目: mrknさん
  • 24 日目: ここ
  • 25 日目: aerealさん

とりあえず、私用で URL から QR コードを生成したいので、 Ruby で実現できるか調べてみた。

成果物

とりあえず、以降の手順の QR コード作成方をもう少しゴチャゴチャやって Heroku にデプロイ。

課題

  • 特にエラーチェックとかしてない
  • 日本語がうまく読み取れない

今回使った rqrcode の Issue の中にこんなものを発見した。 UTF8 strings under Ruby 1.9.2 · Issue #3 · whomwah/rqrcode · GitHub

で、やってみると、確かに日本語を QR コードに落とす事ができた!

ただし、ここでさらにわからないことが増えた…。

  • UTF-8 文字列を安全に CP852 に変換する方法(今は force_encoding で無理やり変換している)
  • なんで CP852 なのか
  • そもそも CP852 とは

参考サイト

環境

  • Windows 7
  • Ruby 1.9.3
    • RubyGems 1.8.25
    • Bundler 1.3.5

手順

  1. barby という Ruby のバーコード生成ライブラリを使用する
  2. barby から QR コードを生成するために rqrcode が必要
  3. QR コードを画像で吐き出すために chunky_png が必要(画像なら何形式でもよかった)
  4. 吐き出した png をブラウザから確認するために sinatra を使用

ソースコード

という事で、必要なgem。

gem 'sinatra'
gem 'barby'
gem 'rqrcode'
gem 'chunky_png'

URL を QR コードに変換するには、

  • QR コードにしたい文字列を用意
  • QR コードとして読み込む
  • 変換したい形式の Outputter で読み込む(今回は png )
  • 読み込んだ バイナリデータ を書き出す

コードはこんな感じ。これは google の Url を QR に変換している。

# encoding: utf-8

require "barby"
require "barby/barcode/qr_code"
require "barby/outputter/ascii_outputter"
require "barby/outputter/png_outputter"
require "rqrcode"

module QR
  extend self

  def barcode(type, data=nil)
    if data.nil? then
      data = <<-"EOS"
        http://google.com
      EOS
    end

    code = Barby::QrCode.new(data.encode("UTF-8"))
    case type
    when :png
      blob = Barby::PngOutputter.new(code)
      File.open('./barcode.png', 'wb') do |f|
        png = blob.to_png

        f.write png
      end
    when :ascii
      code.to_ascii
    end
  end
end

if $0 == __FILE__ then
  puts QR::barcode(:ascii)
end

一番初めは ASCII で出力してみるといいかも。

出した結果。

$ ruby qr.rb
 X  X  X  X  X  X  X        X  X  X        X           X  X  X  X  X  X  X
 X                 X              X  X  X  X     X     X                 X
 X     X  X  X     X        X  X  X        X     X     X     X  X  X     X
 X     X  X  X     X     X     X  X     X     X  X     X     X  X  X     X
 X     X  X  X     X     X     X     X           X     X     X  X  X     X
 X                 X        X  X        X  X     X     X                 X
 X  X  X  X  X  X  X     X     X     X     X     X     X  X  X  X  X  X  X
                            X        X     X  X  X
 X  X           X  X  X     X  X     X  X  X  X              X  X
    X           X              X        X  X  X     X     X  X     X
 X  X  X  X  X     X  X  X  X     X  X     X  X  X  X  X        X        X
 X     X  X  X                 X  X           X  X     X     X           X
    X     X  X  X  X  X  X  X  X     X           X     X  X     X     X  X
 X  X  X     X                 X     X        X     X     X
 X                 X        X  X     X     X  X  X  X  X        X        X
 X              X     X  X  X  X  X  X        X        X     X     X     X
 X     X  X  X  X  X  X  X  X     X  X  X        X  X  X  X  X  X  X     X
                         X  X  X     X  X        X           X
 X  X  X  X  X  X  X     X        X              X     X     X  X  X  X  X
 X                 X     X     X                 X           X
 X     X  X  X     X              X  X  X  X  X  X  X  X  X  X  X  X
 X     X  X  X     X              X        X        X  X           X  X  X
 X     X  X  X     X        X  X        X     X  X  X           X        X
 X                 X     X     X  X        X  X  X     X                 X
 X  X  X  X  X  X  X     X  X  X     X        X  X  X  X  X  X  X        X

ここに sinatra ( start.rb )から呼ぶように。

equire 'sinatra'
require 'qr'

get '/' do
  code = QR::barcode(:png)
  '<img src="barcode.png">'
end

はまったとこ

バイナリファイルを書き込む時は b を忘れないようにする!

画像ファイルは生成されるんだけど、開いてみると「こわれています」と表示されてしまう……。

処理の途中でバイナリを確認していくと、こうなっていた。

正常な場合のバイナリデータ

ソース内で file オープンして write する直前のものを確認

89 50 4E 47 0D 0A 1A 0A ...

「こわれている」画像のバイナリデータ

実際に生成されたブツをバイナリエディタで確認

89 50 4E 47 0D 0D 0A 1A 0D 0A ...

ん?なんか違う。

シグネチャは PNG ファイルであることを確認するために使用されます。 シグネチャは必ず以下の8バイトとなっています。

0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a

なるほど。シグネチャからしておかしい。そもそもはじめから PNG になっていないのか。

なんでだろう?

…と、よくよくコードを見直してみると、 File.open した時のオプションが w だった。

File.open('./barcode.png', 'w') do |f|

b オプションを付加すると正常な画像になった!

File.open('./barcode.png', 'wb') do |f|

バイナリで書き込むの初めてだから失念していた。注意しないといかん。

関連記事(この記事の初版より古い記事はリンクがグレーで表示されます)

  1. 2013/09/07 [Ruby] [Git] [Jekyll] Jekyllバージョンアップの際に思いのほか手こずった話 てっく煮さん製プラグインの更新に追従したい編
  2. 2013/09/03 [Ruby] [Rails] Ruby1.9.3のWebrickで出るCould not determine content-length...エラーを消す方法(2.0.0では解決済)
  3. 2013/08/26 [Ruby] ソースコード中に0xC2A0(UTF-8のNO-BREAK SPACE)が混ざり実行できなくて困った話
  4. 2013/08/20 [Ruby] [Rails] [Redmine] Rails3のログ出力にANSIカラーコードを使用しない設定
  5. 2013/08/09 [Ruby] [Redmine] [MySql] [StartUp] WindowsにRedmine2.3をインストールする手順と、プラグイン作成用メモ
  6. 2013/08/07 [Ruby] [Jekyll] [Git] Jekyllバージョンアップの際に思いのほか手こずった話 Jekyll Bootstrapの更新に追従したい編
  7. 2013/05/27 [Jekyll] [Ruby] Jekyll@GitHub Pagesの運用形態を変えたのでAnalyticsの設定が効かなくなっていた
  8. 2013/05/23 [Jekyll] [Liquid] [Ruby] 記事の目次を出力するJekyllプラグインの改良
  9. 2013/04/27 [Ruby] [Chef] [イベント] BPStudy#68に参加しました #bpstudy
  10. 2013/04/11 [Ruby] [Jekyll] Jekyllのバージョンを 0.12.0 にあげた
  11. 2013/04/01 [Ruby] [StartUp] [Chef] 入門Chef Solo - Infrastructure as Code を読みながらChef Soloで遊べるようになるまで
  12. 2013/03/18 [Selenium] [Firefox] [Ruby] Selenium WebDriverでFirefoxがロードできなくなった
  13. 2013/03/07 [Ruby] [Selenium] [iPhone] [IE] [Test] IEとかiPhoneWebView上でSeleniumを走らせる
  14. 2013/03/03 [Ruby] [Evernote] [OAuth] 自作EvernoteスクリプトをOAuth対応する
  15. 2013/02/25 [Ruby] [StartUp] Ruby 2.0.0 をpikとrvm経由でインストール&環境構築