Rubyでスクリーンショットサーバ(2)
API Ruby Webサービス
Mozshotさんがベースにしたという、このソースを読んでみることにします。
まずは動かしてみます。ソースをダウンロード後、以下のスクリプトを用意します。
snap.rb
#!/usr/bin/ruby ENV['DISPLAY'] = ':1.0' require 'gtkmozembed' require 'moz-snapshooter' Gtk.init MozSnapshooter.new Gtk.main
以下のように実行してみます。
[root@devel ~]# Xvfb :1 -screen 0 1024x768x24 & [1] 19816 _XSERVTransSocketOpenCOTSServer: Unable to open socket for inet6 _XSERVTransOpen: transport open failed for inet6/xxxxxxxxxx:1 _XSERVTransMakeAllCOTSServerListeners: failed to open listener for inet6 Could not init font path element /usr/X11R6/lib/X11/fonts/CID/, removing from list! [root@devel ~]# ruby snap.rb 1 Wrote screenshot-thumb.png Could not init font path element /usr/X11R6/lib/X11/fonts/CID/, removing from list!
なにやらエラーが出ていますが、とりあえあずは無視します。
カレントディレクトリにscreenshot-thumb.pngというファイルが作成されていれば成功です。
勉強の意味で、勝手にソースにコメントをつけてみました(snapshotメソッドのところはまだ理解してませんが。)。
moz-snapshooter.rb コメント付き
# # MozSnapshooter # Web site thumbnailer # # Copyright (C) 2005 Mirko Maischberger # Released in the Public Domain # # From an idea by Andrew McCall -# http://www.hackdiary.com/archives/000055.html require ‘gtkmozembed’ ######################################################### # # MozSnapshooterクラス # Gtk::Windowのサブクラス # ######################################################### class MozSnapshooter < Gtk::Window ######################################### # # initializeメソッド # ######################################### def initialize # Gtk::Window.initialize(=Gtk::Window.new)を呼び出す # 他のウィジェットを含むことのできる新しいコンテナ(トップレベルウィンドウ)を作成 super # selfはGtk::Window.newでできたオブジェクト # コンテナのタイトルとボーダーを設定 # Gtk::Window#title= # Gtk::Container#border_width= self.title=”MozSnapshooter” self.border_width = 1 # width,highを設定 self.resize(780, 570) # プロファイルのパスを設定 # ENV[’HOME’].mozillaディレクトリにRubyGeckoプロファイルを作成 # ENV[’HOME’]の最後にスラッシュがないので、~/配下ではなく # username.mozillaというディレクトリがつくられてしまった… Gtk::MozEmbed.set_profile_path(ENV[’HOME’] + ‘.mozilla’, ‘RubyGecko’) # Gtk::Container#<< # Gtk::Container#addと同じ。 # コンテナ(トップレベルウィンドウ)にMozEmbedウィジェットを追加 している self << Gtk::MozEmbed.new # childって何?おそらくコンテナに追加されたMozEmbedウィジェットのオブジェクトだろう # chrome(クロム)のフラグをセットしている # chromeはmozillaの外観などに対する設定ファイルがあるディレクトリ。 # ALLCHROMEなので、すべてのchromeをセットしている。 # http://cow.neondragon.net/index.php/415-Fun-With-Firefox-Chrome-Urls self.child.chrome_mask = Gtk::MozEmbed::ALLCHROME # Gtk::Widget#set_size_request # MozEmbedウィジェットのサイズを指定 # なぜかコンテナより大きい self.child.set_size_request(816,600) # GLib::Instantiatable#signal_connect # net_stopシグナルを受信したら、on_net_stopハンドラを呼び出す。 # net_stopシグナルはページをロードし終わったら、発生する。 # asincronouslyって何? self.child.signal_connect(”net_stop”) { on_net_stop } # http://www.ruby-lang.orgをロード self.child.location = “http://www.ruby-lang.org” # インスタンス変数 # net_stopシグナルを受信してスクリーンショットを取るまでの # 時間を定義している(1/1000秒単位) @countdown = 2 # destroyシグナルを受信したら、終了。 # The user is bored, let’s quit. self.signal_connect(”destroy”) do $stderr.print “closing…n” Gtk.main_quit end self.show_all end ######################################### # # on_net_stopメソッド # # 先にあったnet_stopシグナルのハンドラを定義 # 1/1000秒後、falseがリターンするまでブロックを実行。 # @countdownで定めた時間が経過したら、 # screenshotメソッドを実行。 # ######################################### def on_net_stop Gtk::timeout_add(1000) do @countdown -= 1 if(@countdown > 0) puts @countdown true else screenshot false end end end ######################################### # # screenshotメソッド # # スクリーンショットを作成 # ######################################### def screenshot # Gtk::MozEmbed#parent_window # 親のウィンドウ(コンテナ)を取得 gdkw = self.child.parent_window # geometryを取得 x, y, width, height, depth = gdkw.geometry width -= 16 pixbuf = Gdk::Pixbuf.from_drawable(nil, gdkw, 0, 0, width, height) pixbuf = pixbuf.scale(320, 200, Gdk::Pixbuf::INTERP_HYPER) pixbuf.save(”screenshot-thumb.png”,”png”) puts “Wrote screenshot-thumb.png” Gtk.main_quit end end
ブラウジング・スナップショットとも外部コマンドに頼ってませんし、ブラウジング終了のシグナルを受信してからスナップショットをとっているところがいいです。なんかPythonのソースと似てますね。Rubyの勉強が終わったらPythonにも手をつけてみようと思います。
次はいよいよMozshotさんのソースに挑戦してみようと思います。
*1:ちなみに私のプログラミングスキルは、
Perl->ハッシュのリファレンスがわかるくらい
C->しばらく使ってないとポインタを忘れる
Ruby->いきなりrailsに手を出して四苦八苦
という感じです。オブジェクト指向もよくわかっていません。
ですので、その程度のレベルということでお願いします。



