アーカイブ
‘Ruby’ タグのついている投稿
ArgsParserをrubygemsに登録した
2010 年 3 月 15 日
コメントはありません
車輪の再発明臭がヤバイが、コマンドラインの引数のパーサを作ったのでrubygemsに登録した。はじめてgem登録した。
gemでインストールできる。
gem update --system
gem install ArgsParser
newgemコマンドでgemを作ってrubygems.orgに登録し、一応rspecでtestも書いた。
gemはrubyforge.orgで公開するのが普通だったけど、2年ぐらい前からgithubでgemが作れる様になったので新しいプロジェクトはみんなgithubに行って、2009年秋?頃にgithubでgemがビルドできなくなったからかrubygems.orgでやってねという事になったらしい。
なのでリポジトリはいつも使っているmercurialにしてbitbucket.orgで公開する事にした。
shokai / argsparser-ruby / overview — bitbucket.org
既にgemにはいくつかCのgetopt風なARGVのparserがあるけど、なんとなくインタフェースが好きじゃないので自分が欲しい物を作った。
- –help -debug等のオプションの有無を判別する
- -x 320 -y 240 等のパラメータ(key value)を取得する
- -hと-helpのように省略名称が関連づけられていれば同じ物として扱う
- -helpと—helpのようなハイフンの数の違いを無視して、全て :help でアクセスできる
- ruby math.rb add -a 10 -b 25 の”add”のような、第一引数を取り出す
- パラメータ名にコメント文を付ける(-helpで起動した時の引数の説明文に使う)
parseすると、第一引数(String)とパラメータ(Hash)が返ってくる。第一引数がない(いきなりパラメータが来た)場合は、第一引数はnilになる。
example.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'ArgsParser'
# 必要なパラメータ名を登録する
parser = ArgsParser.parser
parser.bind(:help, :h, "show help") # name, shortname, comment for help
parser.bind(:frame, :f, "frame image (required)")
parser.bind(:message, :m, "message (required)")
parser.bind(:size, :s, "size (required)")
parser.comment(:min, "minimum size") # add comment for help
parser.comment(:max, "maximum size")
parser.comment(:debug, "debug mode")
# parseして、引数が足りてるか、help表示指定が無いかチェック
first, params = parser.parse(ARGV)
if parser.has_option(:help) or !parser.has_params([:frame, :message, :size])
puts parser.help
puts 'e.g. ruby example.rb -f frame.png -m "hello world" -s 320x240 -debug'
exit 1
end
if first
puts 'first arg : ' + first # 第一引数
end
if parser.has_param(:size)
puts 'size : ' + params[:size] # -sでも-sizeでも :size でアクセスできる
end
# 全ての引数を表示
p params
実行してみる
ruby example.rb hoge -f frame.png -m "hello world" -s 320x240 -debug結果
first arg : hoge
size : 320x240
{:message=>"hello world", :size=>"320x240", :debug=>true, :frame=>"frame.png"}
モバイルSuicaの履歴をtwitterに流したかった
2010 年 2 月 23 日
コメントはありません
xtunnelのためにスクレイピングの勉強をしていて、Mechanize+hpricotからMechanize+nokogiriの組み合わせに乗り換えようと色々と使ってみている中でできた物のひとつ。
昔しゃお先生がやっていたのを俺もやりたくて3ヶ月ぐらい前に作ったけど、mobilesuica.comのおサイフケータイ使用履歴は1日一度早朝に更新される仕様に変更されたらしくボツになった。
結局idやcssなどの手がかりが無くて手動で要素を取り出す事になり、nokogiriはHTMLタグを除去するのにしか使わなかった
MobileSuica.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'nokogiri'
require 'mechanize'
require 'kconv'
module MobileSuica
def MobileSuica.get(user,pass)
agent = WWW::Mechanize.new
agent.user_agent_alias = 'Windows IE 7'
page = agent.get('http://www.mobilesuica.com/iq/ir/SuicaDisp.aspx?returnId=SFRCMMEPC03')
login_form = page.forms_with(:name => 'form1').first
login_form.fields_with(:name => 'MailAddress').first.value = user
login_form.fields_with(:name => 'Password').first.value = pass
page = login_form.click_button
return page.body.toutf8.split(/<tr>/).delete_if{|tr|
!(tr =~ /¥/m)
}.map{|tr|
tr.gsub(/\n/,"").split(/\r/)[0..5].map{|line| # 月日,種別,利用場所,種別,利用場所,残額
Nokogiri(line).inner_text.chomp.strip.gsub(/[\t ]/,"")
}
}
end
end
mobilesuicaのユーザ名、パスワードで履歴を2次元配列として取り出せる。
require 'MobileSuica'月日、種別、利用場所、種別、利用場所、残額の順になる
MobileSuica.get("user", "pass")
01/30
入
川崎
出
横浜
5,110
01/30
入
相鉄横浜
窓出
川崎
5,320
履歴のうち最新の駅名をtwitterに投稿する。-dつけて起動するとdaemonになる
tweet-mobilesuica.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'webrick'
require 'twitter'
require 'MobileSuica'
def start(conf)
loop do
begin
first = MobileSuica.get(conf["suica_user"], conf["suica_pass"]).first
rescue
first = nil
end
if first != nil
last = first if !last
if first != last # 1回前に取得した履歴と比較
puts first
puts '-'*10
if first[1] == '入' && first[3] == '出' # 降車履歴の時
message = first[4].chomp.strip+"なう (suica)"
if !(message =~ /#{conf["ngwords"]}/)
if conf["nopost"] != true
httpAuth = Twitter::HTTPAuth.new(conf["twitter_user"], conf["twitter_pass"])
tw = Twitter::Base.new(httpAuth)
tw.update(message) # twitter post
end
puts message
end
end
last = first
end
end
sleep 60*60*1.5 # 1時間半待つ
end
end
conf = YAML::load open File.dirname(__FILE__)+'/config.yaml'
if ARGV[0] == '-d'
WEBrick::Daemon.start {
start(conf)
}
else
start(conf)
end
設定ファイル。自宅の駅名などはngwordsに入れておく
config.yaml
# config.yaml
# mobilesuica.com user/pass
suica_user : 'username@docomo.ne.jp'
suica_pass : '12345678'
# twitter user/pass
twitter_user : 'shokai'
twitter_pass : 'password'
# postしない駅名を正規表現で
ngwords : "(東京|横浜)"
# for debug
#nopost : "true"
wavファイルの音量を調整する
2010 年 2 月 6 日
コメントはありません
音量の小さいwavファイルのボリュームを上げる。上げすぎて音割れしないようにする。
前に作ったWavFile.rbを使ったら簡単にできた
16ビットwavは+-32768、8ビットwavは+-128の範囲の配列で波形が表現されている。
ソースのwavの波形を配列に取り出して、その中で最大の値を取りだし、全体を何倍すれば+-32768の間になるかの倍率を計算して全部かけ算すれば音量を調整できる。
maximizeVolume.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# wavの音量を最大に調節する
require File.dirname(__FILE__) + '/WavFile'
if ARGV.size < 2
puts 'ruby maximizeVolume.rb input.wav output.wav'
exit 1
end
in_file = ARGV.shift
out_file = ARGV.shift
format, data = WavFile::read open(in_file)
puts format.to_s
bit = 's*' if format.bitPerSample == 16 # int16_t
bit = 'c*' if format.bitPerSample == 8 # signed char
wavs = data.data.unpack(bit)
puts "このwav中の最大音量: #{wavs.max}"
volume_ratio = 32768/wavs.max.to_f if format.bitPerSample == 16
volume_ratio = 128/wavs.max.to_f if format.bitPerSample == 8
puts "補正倍率: #{volume_ratio}"
wavs_fixed = wavs.map{|w|
(w*volume_ratio).to_i
}
puts "補正されたwav中の最大音量: #{wavs_fixed.max}"
data.data = wavs_fixed.pack(bit)
open(out_file, "w"){|out|
WavFile::write(out, format, [data])
}
使う
ruby maximizeVolume.rb input.wav out.wav
約24倍されてout.wavに保存された
フォーマットID: 1
チャンネル数: 1
サンプリングレート: 44100 (Hz)
byte per sec: 88200
bit per sample: 16
ブロックサイズ: 2
このwav中の最大音量: 1335
補正倍率: 24.5453183520599
補正されたwav中の最大音量: 32768
OpenCVで画像のサイズを求めるgearman workerを作って、Rubyから呼ぶ
2010 年 1 月 3 日
コメントはありません
ファイル名を渡すと画像サイズを返すgearman workerを作った。
{"width":1600, "height":1200}
という風にJSON風に値を返す。以前画像のだいたいの色を求めるgearman workerを作ってたんだけど、C++で書いたworker側を単独で動作テストする事ができなくてどうしようか悩んだ。テスト用のclientと同時に作らなければならなくて、どちらにバグがあるのか切り分けるのが面倒だった。
そこで、workerの起動時に
./imgsizeWorker --test "/path/to/imagefile.jpg"という風にgearman clientから来る引数と同じ形式で渡すと、単体のプログラムとしても動作チェックできるようにした。
こうすると普通にworkerとして起動する。
./imgsizeWorker -s localhost -p 7003これはboost::program_optionsでやると便利だった。
今後はこのコードを雛形にすればC++とOpenCVで高速に画像解析して、gearmand経由でスクリプト言語から呼び出しまくれる。
■使ったライブラリ
boostライブラリを中心にいろいろ使った。
opencv1.0は画像サイズを取得する為だけに使った。GUIを使って無いのにcvLoadImage()のためだけにhighgui.hを読み込んでいる。
boost::tupleとboost::tieを使うと返り値を複数返す関数が作れるので、画像の情報を返すのに便利。そういえばRubyでは普通に使ってたけどC#3.5やAS3.0ではタプル無かったな。欲しい。ASはArrayに何でも入れやすいからいいか。
boost::tupleで多値を受け取る – 橋本詳解
boost::tieでtupleを展開 – 橋本詳解
boost::formatでprintf風にstd::stringをフォーマット。
boost::program_optionsで引数をparseする。
boost::program_optionsでコマンドライン引数を読む – 橋本詳解
rubyはxing-gearman-rubyを使った。
橋本商会 » Cでgearman workerを書いてRubyのclientから呼び出す
■プログラム
libgearmanのgearman_worker_add_serverはIPアドレスを渡さないとならないので、一応ホスト名を解決するようにした。
imgsizeWorker.cpp
// 画像サイズを返すgearman worker
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cv.h>
#include <highgui.h>
#include <boost/program_options.hpp>
#include <boost/regex.hpp>
#include <boost/format.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <libgearman/gearman.h>
using namespace boost;
using namespace std;
tuple<int, int> get_size(string fileName); // 画像のwidth,heightを返す
string imgsize(string fileName); // gearman workerとしてclientに返すstringに整形する
void *job_imgsize(gearman_job_st *job, void *cb_arg, size_t *result_size, gearman_return_t *ret_ptr);
int main(int argc, char* argv[]) {
program_options::options_description opts("options");
opts.add_options()
("help,h", "helpを表示")
("server,s", program_options::value<string>(), "gearmanサーバーのアドレス")
("port,p", program_options::value<int>(), "gearmanサーバーのport番号")
("test,t", program_options::value<string>(), "gearman worker単体テスト用query");
program_options::variables_map argmap;
program_options::store(parse_command_line(argc, argv, opts), argmap);
program_options::notify(argmap);
if(!argmap.count("help")){
if(argmap.count("test")){
cout << "---test---" << endl;
string gearman_param = argmap["test"].as<string>();
imgsize(gearman_param); // 単体でworkerとしてのテスト
return 0;
}else if(argmap.count("server") && argmap.count("port")){
gearman_worker_st worker;
gearman_worker_create(&worker);
string g_server = argmap["server"].as<string>();
int g_port = argmap["port"].as<int>();
struct hostent *g_host = gethostbyname((char*)g_server.c_str());
string g_server_addr = str(format("%d.%d.%d.%d") %
(uint)(uchar)g_host->h_addr[0] %
(uint)(uchar)g_host->h_addr[1] %
(uint)(uchar)g_host->h_addr[2] %
(uint)(uchar)g_host->h_addr[3]);
gearman_worker_add_server(&worker, g_server_addr.c_str(), g_port);
gearman_worker_add_function(&worker, "img_size", 0, job_imgsize, NULL);
cout << str(format("---start worker (%s:%d)---") %
g_server_addr % g_port) << endl;
while(true) gearman_worker_work(&worker); // workerとして待機
return 0;
}
}
cerr << "server,portが必要です" << endl;
cerr << opts << endl;
return 1;
}
// opencvで画像サイズを取得
tuple<int, int> get_size(string fileName){
IplImage *img = cvLoadImage(fileName.c_str());
if(!img){
return make_tuple(-1, -1);
}
else{
return make_tuple(img->width, img->height);
cvReleaseImage(&img);
}
}
// 画像サイズを取得してgearman serverに返すstringに整形する
string imgsize(string fileName){
string result_str = "";
int width, height;
tie(width, height) = get_size(fileName);
if(width > 0 && height > 0){
result_str += str(format("{\"width\":%d, \"height\":%d}")
% width % height);
}
else{
result_str = "error : image load error";
}
cout << fileName << " => " << result_str << endl;
return result_str;
}
// gearman worker job
void *job_imgsize(gearman_job_st *job, void *cb_arg, size_t *result_size, gearman_return_t *ret_ptr){
string fileName = (char*)gearman_job_workload(job);
string result_str = imgsize(fileName);
char *result = (char*)strdup(result_str.c_str());
*result_size = result_str.size();
*ret_ptr = GEARMAN_SUCCESS;
return result;
}
Makefile
# Mac用Makefile
SRC = imgsizeWorker.cpp
DST = imgsizeWorker
prefix=/opt/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
CV_LIBS= -lcv -lcvaux -lcxcore -lhighgui
BOOST_LIBS= $(LIBPATH)/libboost_program_options-mt.a
GEAR_INCPATH=/usr/local/include
GEAR_LIBPATH=/usr/local/lib
GEAR_LIBS=$(GEAR_LIBPATH)/libgearman.a
all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/opencv -L. -L$(LIBPATH) $(CV_LIBS) -I$(INCPATH)/boost $(BOOST_LIBS) -I$(GEAR_INCPATH)/libgearman -L. -L$(GEAR_LIBPATH) $(GEAR_LIBS)
client側。workerからの返り値の先頭にerrorが書いていなかったらJSONとしてparseする
testclient.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'gearman'
require 'json'
if ARGV.size < 1
puts '画像へのパスが必要'
puts 'ruby testclient.rb ~/path/to/images/*.png'
exit 1
end
c = Gearman::Client.new(['localhost:7003'])
taskset = Gearman::TaskSet.new(c)
ARGV.sort{|a,b| a.split(/\//).last.to_i <=> b.split(/\//).last.to_i}.each{|name|
puts "add task #{name}"
task = Gearman::Task.new("img_size", name+"\0")
task.on_complete{|result|
if !(result =~ /^error/)
print "return: #{name} => "
p JSON.parse(result)
else
puts "return: #{name} => #{result}"
end
}
taskset.add_task(task)
}
taskset.wait(100) # wait 100(sec)
&をつけていくつかworkerを起動する
./imgsizeWorker -s localhost -p 7003&
./imgsizeWorker -s localhost -p 7003&
clientからtask登録。フォルダ内のjpgファイルを全部登録する
ruby testclient.rb ~/Pictures/selected/*.jpgサイズが返ってくる
add task /Users/sho/Pictures/selected/a66dab3a.jpg
add task /Users/sho/Pictures/selected/3ed6f38e.jpg
add task /Users/sho/Pictures/selected/77ab53f0.jpg
add task /Users/sho/Pictures/selected/889bd644.jpg
add task /Users/sho/Pictures/selected/73177294.jpg
return: /Users/sho/Pictures/selected/a66dab3a.jpg => {"height"=>1200, "width"=>1600}
return: /Users/sho/Pictures/selected/3ed6f38e.jpg => {"height"=>1200, "width"=>1600}
return: /Users/sho/Pictures/selected/77ab53f0.jpg => {"height"=>1200, "width"=>1600}
return: /Users/sho/Pictures/selected/889bd644.jpg => {"height"=>800, "width"=>1280}
return: /Users/sho/Pictures/selected/73177294.jpg => {"height"=>1200, "width"=>1600}
OpenCVで画像のだいたいの色を求めるgearman workerを作って、Rubyから呼び出す
2009 年 12 月 24 日
コメントはありません
画像のだいたいの色を求めるをgearman worker化した。
画像ファイル名をテキストで投げると
{width: 136, height: 147, r: 249, g: 234, b:230}
という形式で画像のサイズとだいたいの色を返す。Cでworkerを書いてRubyで呼び出す方法は橋本商会 » Cでgearman workerを書いてRubyのclientから呼び出すに書いたとおり。
これでOpenCVの解析をgearman workerとして複数並列に動かしてそれをRubyから使いまくるというのができるワハハ
C++なのはboost::regex_splitでも使って引数を受け取ろうかと思ってたんだけど、そもそもファイル名だけしか受け取らなかったから意味がなかった。
imgcolorWorker.cpp
// 画像のだいたいの色とサイズを返すgearman worker最後の*result_sizeに返り値のサイズを入れておかないと、client側には壊れた文字列が来る。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cv.h>
#include <highgui.h>
#include <boost/regex.hpp>
#include <boost/format.hpp>
#include <libgearman/gearman.h>
using namespace boost;
using namespace std;
IplImage *img, *img1px, *imgR, *imgG, *imgB;
void *job_imgcolor(gearman_job_st *job, void *cb_arg, size_t *result_size, gearman_return_t *ret_ptr);
int main(int argc, char* argv[]) {
img1px = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 3);
imgR = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
imgG = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
imgB = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
gearman_worker_st worker;
gearman_worker_create(&worker);
gearman_worker_add_server(&worker, "127.0.0.1", 7003);
gearman_worker_add_function(&worker, "img_color", 0, job_imgcolor, NULL);
while(true) gearman_worker_work(&worker);
return 0;
}
void *job_imgcolor(gearman_job_st *job, void *cb_arg, size_t *result_size, gearman_return_t *ret_ptr){
string fileName = (char*)gearman_job_workload(job);
string result_str = "";
IplImage *img = cvLoadImage(fileName.c_str());
if(!img){
result_str += "{error: image load error}";
}
else{
cvResize(img, img1px, CV_INTER_CUBIC);
cvSplit(img1px, imgB, imgG, imgR, NULL);
result_str += str(format("{width: %d, height: %d, r: %d, g: %d, b:%d}")
% img->width % img->height %
(uint)(uchar)imgR->imageDataOrigin[0] %
(uint)(uchar)imgG->imageDataOrigin[0] %
(uint)(uchar)imgB->imageDataOrigin[0]);
cvReleaseImage(&img);
}
cout << fileName << " => " << result_str << endl;
char *result = (char*)strdup(result_str.c_str());
*result_size = result_str.size();
*ret_ptr = GEARMAN_SUCCESS;
return result;
}
boost::formatはprintfのフォーマットと違ってunsigned charを数値としてそのまま使えなかったので2回キャストした。
Makefile
# Mac用Makefile
SRC = imgcolorWorker.cpp
DST = imgcolorWorker
prefix=/opt/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
CV_LIBS= -lcv -lcvaux -lcxcore -lhighgui
BOOST_LIBS= $(LIBPATH)/libboost_program_options-mt.a $(LIBPATH)/libboost_regex-mt.a
GEAR_INCPATH=/usr/local/include
GEAR_LIBPATH=/usr/local/lib
GEAR_LIBS=$(GEAR_LIBPATH)/libgearman.a
all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/opencv -L. -L$(LIBPATH) $(CV_LIBS) -I$(INCPATH)/boost $(BOOST_LIBS) -I$(GEAR_INCPATH)/libgearman -L. -L$(GEAR_LIBPATH) $(GEAR_LIBS)
gearman client。ワイルドカードで指定して画像ファイルをひとつずつtask登録する
imgcolorClient.rb
#!/usr/bin/env rubytask登録する時に、argmentの末尾に”\0″を付けておかないとworker側で受け取った時におかしくなる事がある。
# -*- coding: utf-8 -*-
require 'rubygems'
require 'gearman'
require 'json'
if ARGV.size < 1
puts '画像へのパスが必要'
puts 'ruby imgcolorClient.rb ~/path/to/images/*.png'
exit 1
end
c = Gearman::Client.new(['localhost:7003'])
taskset = Gearman::TaskSet.new(c)
ARGV.sort{|a,b| a.split(/\//).last.to_i <=> b.split(/\//).last.to_i}.each{|name|
puts "add task #{name}"
task = Gearman::Task.new("img_color", name+"\0")
task.on_complete{|result|
puts "return: #{name} => #{result}"
}
taskset.add_task(task)
}
taskset.wait(100) # wait 100(sec)
workerを2つ起動しておいて、画像をいくつか投げてみる
make
./imgcolorWorker&
./imgcolorWorker&
ruby imgcolorClient.rb ~/Pictures/test/*
workerが2つあるので、結果は順番には返ってこない。
add task /Users/sho/Pictures/test/実装力不全.gif
add task /Users/sho/Pictures/test/そうだ旧都へ行こう.jpg
add task /Users/sho/Pictures/test/zanmai.jpg
add task /Users/sho/Pictures/test/wiring.jpg
return: /Users/sho/Pictures/test/実装力不全.gif => {error: image load error}
add task /Users/sho/Pictures/test/ed93d6de.jpg
add task /Users/sho/Pictures/test/f9286cff.jpg
add task /Users/sho/Pictures/test/fae75abe.jpg
add task /Users/sho/Pictures/test/img278_s201.jpg
add task /Users/sho/Pictures/test/la-metro.jpg
add task /Users/sho/Pictures/test/wiring-s.jpg
add task /Users/sho/Pictures/test/org19361.jpg
add task /Users/sho/Pictures/test/org19364.jpg
add task /Users/sho/Pictures/test/org19375.jpg
add task /Users/sho/Pictures/test/label.png
add task /Users/sho/Pictures/test/246.png
add task /Users/sho/Pictures/test/247.png
add task /Users/sho/Pictures/test/248.png
add task /Users/sho/Pictures/test/249.png
return: /Users/sho/Pictures/test/zanmai.jpg => {width: 1024, height: 768, r: 22, g: 11, b:7}
return: /Users/sho/Pictures/test/そうだ旧都へ行こう.jpg => {width: 1440, height: 1046, r: 21, g: 21, b:20}
return: /Users/sho/Pictures/test/ed93d6de.jpg => {width: 1920, height: 1200, r: 45, g: 33, b:26}
return: /Users/sho/Pictures/test/wiring.jpg => {width: 2106, height: 1584, r: 26, g: 24, b:31}
return: /Users/sho/Pictures/test/f9286cff.jpg => {width: 1920, height: 1200, r: 88, g: 80, b:72}
return: /Users/sho/Pictures/test/fae75abe.jpg => {width: 1920, height: 1200, r: 21, g: 15, b:22}
return: /Users/sho/Pictures/test/img278_s201.jpg => {width: 1024, height: 768, r: 21, g: 92, b:107}
return: /Users/sho/Pictures/test/la-metro.jpg => {width: 1024, height: 768, r: 128, g: 118, b:111}
return: /Users/sho/Pictures/test/wiring-s.jpg => {width: 1024, height: 770, r: 28, g: 24, b:32}
return: /Users/sho/Pictures/test/org19361.jpg => {width: 1280, height: 800, r: 0, g: 0, b:0}
return: /Users/sho/Pictures/test/org19375.jpg => {width: 1024, height: 633, r: 235, g: 235, b:235}
return: /Users/sho/Pictures/test/org19364.jpg => {width: 1024, height: 681, r: 217, g: 217, b:217}
return: /Users/sho/Pictures/test/label.png => {width: 100, height: 80, r: 255, g: 255, b:255}
return: /Users/sho/Pictures/test/247.png => {width: 140, height: 151, r: 246, g: 235, b:233}
return: /Users/sho/Pictures/test/248.png => {width: 138, height: 149, r: 247, g: 234, b:232}
return: /Users/sho/Pictures/test/246.png => {width: 141, height: 153, r: 246, g: 237, b:236}
return: /Users/sho/Pictures/test/249.png => {width: 136, height: 147, r: 249, g: 234, b:230}
ちなみにCore2 DuoのMacbookProなので、workerを1つよりも2つ起動していた方が1.7倍ぐらい速かった。
引数を複数渡したい時は、適当に渡してworker側でboost::regex_splitでも使うか、getoptやboost::program_optionsでparseできるようにして渡せばいいかな
client側での受け取りはRubyだからどうにでもできる。
workerでエラーが起きた時の例外処理の出し方がよくわからない。ret_ptrにGEARMAN_SUCCESS以外を入れて返すべきなのか?

最近のコメント