0

MacのRubyでPhidgets RFIDリーダーを使う

PhidgetsをRubyから使う方法は去年も調べたのだが、良いrubygemが無かったのでPhidgets Serverを立てるしかないかなと思っていたけど、
最近リリースされたphidgets-ffiを使うとRubyスクリプト単体で使えた。

他にも”phidgets”や”phidgets4r”などのgemもあるが、OSの判別のコードがSnow Leopardに対応していなかったりonAttachなどのイベントを発行してくれなかったりAPIがRubyっぽくなかったりする。
phidgets-ffiが一番対応デバイス数多くてドキュメントもしっかりしていて良い。


■インストール
まずPhidgets 21 Installerをインストールする。Cで書かれたライブラリと、Macにはコントロールパネルがインストールされる。

次にgemを入れる

gem install ffi phidgets-ffi


■テスト
自分でプログラムを書く前に、システム環境設定にPhidgetsコントロールパネルが増えているのでそこから動かしてみる。
PhidgetsデバイスをUSBポートに挿すとGeneralのタブに名前が増えるので、ダブルクリックすればそれぞれのデバイスに合わせたGUIが出てくる。


■phidgets-ffiを使う
RFIDリーダーを動かしてみた。これだけでRFIDタグをのせた・どけた事がイベントで取れて、タグのIDも読める。
ffiなので多分Linuxでも動くはず。

ffi-rfid.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'phidgets-ffi'

rfid = Phidgets::RFID.new

puts 'waiting RFID Reader'

rfid.on_attach do |device, obj|
puts "#{device.device_class} attached"
device.antenna = true
device.led = true
sleep 1
end

rfid.on_tag do |device, tag, obj|
puts "tag : #{tag}"
end

rfid.on_tag_lost do |device, tag, obj|
puts "tag lost : #{tag}"
end

sleep 5
if rfid.attached?
loop do
end
else
puts 'device not found'
end

0

hugeurlをアップデートした

twitterのURL展開隠しAPIを使っていたのだがいつの間にかなくなっていたので、HTTP-HEADしてresponseのlocationを見るようにした。

gem install hugeurl
gemの使い方はここに書いたのと同じ

 

今回は新たにhugeurlコマンドを付けておいた。gem installするだけで使えるようになっているはず。
% hugeurl http://t.co/abcde
で展開したり
% cat foo.txt | hugeurl
でファイルまるごと展開できる。

0

webブラウザから印刷できるサーバー作った

webブラウザでファイルをアップロードしたり、URLをHTTP-POSTしたら印刷できる奴を作った。研究室のwebサーバーに設置したらわりとウケてた。

出力デバイスとしてプリンタがより手軽に使えるようになる。
例えばメッセージをプリンターから出したりとか、Ethernetにつながったハードウェアから印刷したりとか、いろいろなARマーカーをどんどん吐き出すとかできるのできっと便利。


SinatraからMac/Linuxのlprコマンドを呼び出して印刷する感じの実装をした。
URLをpostされたら、content_typeをチェックしてから、html以外ならダウンロードして印刷、htmlの場合はxvfbとwebkitを起動してキャプチャしてPDFを作って印刷するとかがんばった実装をした。


https://github.com/shokai/print-server




■セットアップ
Sinatraなのでローカルですぐ起動させられる。

git clone git@github.com:shokai/print-server.git
cd print-server
brew install qt imagemagick
gem install bundler
bundle install
cp sample.config.yaml config.yaml
config.yamlにデフォルトプリンタの指定などが書いてある。
Linuxの人はREADME.mdを見ろ。


■起動
ruby development.rb
http://localhost:8080で起動する


■印刷
HTTP POSTで印刷できる
curl -d 'url=http://shokai.org/blog/' http://localhost:8080/url

multipart/form-dataでデータ入稿もできる。


■その他memo
このへんの事をするツールをhelperディレクトリにまとめてある


lprとlpstatで印刷している
ターミナルから印刷する – 橋本詳解


xvfbとwebkit起動してスクリーンショットを撮る
capybara-webkitでwebページのスクリーンショットを撮る – 橋本詳解


ImageMagickをmini_magickから使って、縦長のスクリーンショットを分割した
mini_magickとImageMagickで画像を切り取る – 橋本詳解


Prawnで画像を1つのPDFにまとめる
画像をpdfファイルにまとめる – 橋本詳解

5

いかにしておっぱい画像をダウンロードするか〜2012 をRubyで書いた

元ネタ:いかにしておっぱい画像をダウンロードするか〜2012 – ゆーすけべー日記


昔、yusukebeさんとは大学で同じ研究室だった。
俺がまともにプログラムを書けるようになったのは、研究室に入った時に新入生向けのyusukebeサブゼミに入って、Flashで実装されたRSSリーダーのソースコードを見せてもらったあたりがきっかけだった気がする。

俺も高校生が(Rubyで)プログラミングをはじめるきっかけになりたいので、Ruby版を作ってみました。
Rubyもこういうwebクローラーを作るのに向いている言語だし、最近のMacなんかには最初からインストールされているので試してみると良いよ。


まずjson gemをインストールする。

sudo gem install json


oppai.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'open-uri'
require 'json'
require 'digest/md5'
require 'uri'
require 'kconv'

APP_ID = '' ## https://ssl.bing.com/webmaster/developers/appids.aspx から取得
API_URI = 'http://api.bing.net/json.aspx'

out_dir = './data'
Dir.mkdir out_dir unless File.exists? out_dir

page_count = 0
dl_count = 0

loop do
params = {
:AppId => APP_ID,
:Version => 2.2,
:Market => 'ja-JP',
:Sources => 'Image',
'Image.Count' => 50,
'Image.Offset' => page_count * 50,
:Adult => 'off',
:Query => 'おっぱい'
}

url = API_URI + '?' + params.map{|k,v| "#{URI.encode k.to_s}=#{URI.encode v.to_s}"}.join('&')
data = JSON.parse open(url).read.toutf8

data['SearchResponse']['Image']['Results'].each do |entry|
next unless entry['MediaUrl'] =~ /\.jpe?g$/i
dl_count += 1
fname = Digest::MD5.hexdigest(entry['MediaUrl'])+'.jpg'
fpath = "#{out_dir}/#{fname}"
next if File.exists? fpath

puts "#{dl_count} : Download... #{entry['MediaUrl']}"
img = open(URI.encode entry['MediaUrl']) rescue next
img.close
next unless img.content_type =~ /^image\/.+/i
next if img.path.to_s.size < 1
File.rename(img.path, fpath)
end
page_count += 1
end



並列ダウンロード版。parallelを使って10並列ダウンロードする。

gem install parallel


oppai_paralle.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'open-uri'
require 'json'
require 'digest/md5'
require 'uri'
require 'kconv'
require 'parallel'

APP_ID = '' ## https://ssl.bing.com/webmaster/developers/appids.aspx から取得
API_URI = 'http://api.bing.net/json.aspx'

out_dir = './data'
Dir.mkdir out_dir unless File.exists? out_dir

page_count = 0
dl_count = 0

loop do
params = {
:AppId => APP_ID,
:Version => 2.2,
:Market => 'ja-JP',
:Sources => 'Image',
'Image.Count' => 50,
'Image.Offset' => page_count * 50,
:Adult => 'off',
:Query => 'おっぱい'
}

url = API_URI + '?' + params.map{|k,v| "#{URI.encode k.to_s}=#{URI.encode v.to_s}"}.join('&')
data = JSON.parse open(url).read.toutf8

Parallel.each(data['SearchResponse']['Image']['Results'], :in_threads => 10) do |entry|
next unless entry['MediaUrl'] =~ /\.jpe?g$/i
dl_count += 1
fname = Digest::MD5.hexdigest(entry['MediaUrl'])+'.jpg'
fpath = "#{out_dir}/#{fname}"
next if File.exists? fpath

puts "#{dl_count} : Download... #{entry['MediaUrl']}"
img = open(URI.encode entry['MediaUrl']) rescue next
img.close
next unless img.content_type =~ /^image\/.+/i
next if img.path.to_s.size < 1
File.rename(img.path, fpath)
end
page_count += 1
end

0

webページを印刷できるようにキャプチャしてPDFファイルにまとめる

webkit2pngを使うとwebページをキャプチャして画像にできるので、さらにImageMagickでA4サイズでの印刷用に加工してpdfjamで1つのPDFファイルにまとめるようにしてみた。
こんなpdfができる

■準備
必要なツールをhomebrewとrubygemsでインストールする

brew install webkit2png imagemagick pdfjam
gem install ArgsParser


■キャプチャする
ruby capture_webpage.rb -url http://shokai.org/blog -out tmp/shokai-blog.pdf

–landscapeオプションを付けるとA4横長ページにできる。

■コード
capture_webpage.rb
#!/usr/bin/env ruby
## capture webpage and make PDF
## brew install webkit2png imagemagick pdfjam

require 'rubygems'
require 'ArgsParser'
require 'FileUtils'

parser = ArgsParser.parser
parser.bind(:help, :h, 'show help')
parser.comment(:url, 'URL')
parser.bind(:width, :w, 'page width', 1200)
parser.comment(:landscape, 'landscape layout', false)
parser.bind(:out, :o, 'output file', 'out.pdf')
first, params = parser.parse(ARGV)

if parser.has_option(:help) or !parser.has_params([:url])
puts parser.help
puts "e.g. ruby #{$0} -url http://shokai.org/blog/ -out shokai-blog.pdf"
exit 1
end

tmp_fname = "#{Time.now.to_i}_#{Time.now.usec}"
tmp_dname = File.dirname(params[:out])+'/'+tmp_fname

FileUtils.mkdir_p(tmp_dname) unless File.exists? tmp_dname
puts cmd = "webkit2png --dir '#{tmp_dname}' -o #{tmp_fname} -F -W #{params[:width].to_i} '#{params[:url]}'"
system cmd

unless png = Dir.glob("#{tmp_dname}/#{tmp_fname}*-full.png")[0]
STDERR.puts "capture failed"
exit 1
end

x,y = `identify '#{png}'`.split(/\s/).select{|i|
i =~ /^\d+x\d+$/
}.first.split('x').map{|i| i.to_i}

w = x
h = params[:landscape] ? (w/1.41).to_i : (w*1.41).to_i

parts = 0.upto(y/h).map{|i|
fname = "#{tmp_dname}/#{i}.png"
puts cmd = "convert -crop #{w}x#{h}+0+#{h*i} '#{png}' '#{fname}'"
system cmd
fname
}

scape = params[:landscape] ? 'landscape' : 'no-landscape'
puts cmd = "pdfjam --#{scape} --outfile '#{params[:out]}' --pdftitle '#{params[:url]}' #{parts.join(' ')}"
system cmd

Dir.glob("#{tmp_dname}/*").each{|f|
File.delete f
}
Dir.rmdir tmp_dname



PDFならlprとlpstatコマンドで印刷できるので、URLを入力したら目の前のプリンタからでてくるとかできる。