#!/usr/bin/env ruby
Webnailver='$Id: webnail.rb,v 1.10 2005/05/15 13:57:20 waka Exp waka $'.split(" ")[2]
# http://www.double-red.net/
=begin
nDiary filter
指定した url の表示イメージサムネイルを取得、表示する
OUTPUT_DIRECTORY で指定したディレクトリに 'webnail' というディレクトリを用意し、
日記内に
webnail(url タイトル)
などと記述すると
url の画像をキャプチャしてサムネイルを表示し、url へのリンクを張る
サムネイル画像は webnail ディレクトリに
tn_date_url.png のようなファイル名で保存される。
以上が基本。
あれこれポップアップ導入している場合、ndiary.conf に
WEBNAIL_WITH_AP = true
と指定する、もしくはタイトルの後ろに " ap"と指定するとバナーポップアップに
サムネイルを使用するようになり、ブラウザ表示上サムネイル画像は見えなくなる。
例
webnail(url タイトル ap)
あれこれポップアップ
http://www.remus.dti.ne.jp/~a-satomi/bunsyorou/ArekorePopup.html
サムネイルと大きな画像両方を取得する。
例
webnail(url タイトル large)
と記述することでサムネイルと実際の大きさのキャプチャイメージが取得される。
その他、ndiary.conf にて以下の変数が設定できます。
デフォルト動作が気に入らない場合変更下さい。
WEBNAIL_GET_LARGE = true # true で大きい画像もキャプチャ。デフォルトは false。
WEBNAIL_TIME_OUT = 10000 # webnail2.exe のタイムアウト時間(単位:ms)。windows のみ有用
WEBNAIL_TN_HEIGHT = 200 # サムネイル画像の高さ。デフォルトは 200。
WEBNAIL_TN_WIDTH = 150 # サムネイル画像の幅。デフォルトは 150。
WEBNAIL_MENUBUTTON_HEIGHT = 153 # ブラウザの装飾部分の高さ。PC-UNIX のみ有用。
以下は、Windows ユーザ向け。
他のブラウザのイメージキャプチャしたい人は、
Winshot (http://www.woodybells.com/winshot.html)と
ImageMagick (http://www.imagemagick.org/)をインストールし、
WEBNAIL_USE_WS = true
として下さい。
他にも以下の設定が必要。
WEBNAIL_WIN_SHOT = 'WinShot.exe のフルパス'
WEBNAIL_BROWSER = 'web ブラウザのフルパス'
WEBNAIL_WIN_CONVERT = 'ImageMagick convert.exe のフルパス'
例)
WEBNAIL_USE_WS = true
WEBNAIL_WIN_SHOT = 'c:/Program Files/WinShot/WinShot.exe'
WEBNAIL_WIN_BROWSER = 'c:/Program Files/Mozilla Firefox/firefox.exe'
WEBNAIL_WIN_CONVERT = 'c:/Program Files/ImageMagick/convert.exe'
以下の環境で動作する事を確認(2004-03-22 現在)
[PC-UNIX]
Vine Linux 2.6r1
firefox 0.8
ImageMagick-5.2.9-0vl6
[Windows]
Windows XP
ruby
- mswin版 1.8.1 (http://www.dm4lab.to/~usa/ruby/)
- cygwin版 1.8.1 (http://ftp.ruby-lang.org/pub/ruby/binaries/cygwin/1.8/)
webnail2.exe (http://www.hirax.net/cgi-bin/wiki.cgi?Webnail2)
webnail2 を使わない場合以下が必要
winshot (http://www.woodybells.com/winshot.html)
ImageMagick (http://www.imagemagick.org/)
※ ftp://ftp.imagemagick.org/pub/ImageMagick/binaries/
ImageMagick-5.5.7-Q8-windows-dll.exe で確認。
==================================================
Windows での動作確認方法
==================================================
以下 cygwin 前提で説明
※コマンドプロンプトから ruby と webnail2 が起動できればよし
0.準備
パスの通った場所に webnail2.exe を置く
cygwin のターミナルを起動し、
> webnail2.exe
で webnail2 が起動すれば O.K.
1.確認
1-1.
cygwin のターミナルを起動し、
当フィルタ (webnail.rb) を置いたディレクトリに移動
1-2.
> ruby webnail.rb http://www.google.com
にて webnail2.exe が起動し、カレントディレクトリに
tn_www_google_coml.jpg
が出来ていれば成功。nDiary フィルタとしても動作するはず。
==================================================
PC-UNIX(Windows 以外の OS)での動作確認方法
==================================================
当フィルタ (webnail.rb) を置いたディレクトリに移動。
> ruby webnail.rb http://www.google.com
にて firefox が起動し、カレントディレクトリに
tn_www_google_coml.png
が出来ていれば成功。nDiary フィルタとしても動作するはず。
ブラウザが起動しない場合、
クラス Webnail において、
@browserName = "Mozilla Firefox" # Window ID 特定用
@browser = "/usr/local/firefox/firefox" # ブラウザフルパス
をご自分の環境に変更して下さい。
@browserName は、空ページ(about:blank)を開いた時の Window の名前
=end
require 'cgi'
class String
def escapeSpace
self.gsub(/\\/,'/').gsub(/ /,'\\ ')
end
end
class Webnail
attr_accessor :out_dir
attr_accessor :usewinShot
attr_accessor :image_prefix
attr_accessor :menubutton_h
attr_accessor :tn_w
attr_accessor :tn_h
attr_accessor :get_large
attr_accessor :timeout
attr_accessor :browser
def initialize(url)
# Windows / PC-UNIX 共通
@url = url
@tn = false
@out_dir = ""
@image_prefix= ""
@full_image = ""
@tn_image = ""
@image = ""
@tn_w = 200
@tn_h = 150
@get_large = false
# Windows(webnail2.exe / Winshot.exe) 用
@timeout = 5000
@usewinShot = false
@winShot = 'c:/Program Files/WinShot/WinShot.exe' # WinShot のフルパス
@winBrowser = 'c:/Program Files/Mozilla Firefox/firefox.exe'
@winConvert = 'c:/Program Files/ImageMagick-5.5.3-Q16/convert.exe' # ImageMagick convert コマンドのフルパス
# PC-UNIX 専用
# @processName = "firefox-bin"
@browserName = ["Mozilla Firefox","Deer Park"] # Window ID 特定用ブラウザ名リスト
@browser = "/usr/bin/firefox" # ブラウザフルパス
@user = ENV["USER"]
@blankpage = "about:blank"
@winid, @width, @height = "","",""
@winrootid = ""
@large_w,@large_h = @tn_w * 4 , @tn_h * 4
@scrollbar_w = 14 # スクロールバーの幅
@menubutton_h= 90 # メニュー + ボタン類の高さ
@statusbar_h = 36 # ステータスバーの高さ
# @google_bar_h = 35
# @tab_h = 28
end
def webnail2
case PLATFORM
when /win/i
imageInfo
if @usewinShot then
openResizedBrowser
pid = fork{
exec(@winBrowser, @url)
}
sleep @timeout.to_i / 1000
pwd_stack = Dir.pwd
Dir.chdir(@out_dir)
$stderr.puts "winshot start..."
`#{@winShot.escapeSpace} -J -R 100x100 -F #{@full_image} -A -X`
$stderr.puts "convert (large => thumbnail) start..."
$stderr.puts %Q!#{@winConvert.escapeSpace} -geometry #{@tn_w}x#{@tn_h} -quality 100 #{@full_image} #{@tn_image}!
`#{@winConvert.escapeSpace} -geometry #{@tn_w}x#{@tn_h} -quality 100 #{@full_image} #{@tn_image}`
Dir.chdir(pwd_stack)
begin
Process.kill(:TERM,pid)
rescue
#
end
else
site_txt = "sites.txt"
settingfile = File.open(File.join(@out_dir , site_txt),"w")
settingfile.puts @url + ',' + @tn_image
settingfile.close
if @get_large then
@get_large = "y"
else
@get_large = "n"
end
pwd_stack = Dir.pwd
Dir.chdir(@out_dir)
$stderr.puts "webnail2.exe start ..."
system("webnail2.exe #{site_txt} #{@tn_w} #{@tn_h} #{@timeout} #{@get_large}")
if @get_large == "y" then
File.rename("big" + @tn_image, @full_image)
end
Dir.chdir(pwd_stack)
end
when /linux/i
imageInfo
browserReady
sleep 0.5
if @get_large then
fullsizeCapture
end
thumbnailCapture
end
end
def browserReady
openResizedBrowser
waitDisplay
$stderr.puts "open URL #{@blankpage}"
openUrl(@blankpage)
sleep 0.5
getWindowInfo
# @winid, @width, @height = getWindowInfo
openUrl(@url)
waitDisplay
@crop_w = @width.to_i - @scrollbar_w
@crop_h = @height.to_i - (@menubutton_h + @statusbar_h)
@crop_offset = "+0+#{@menubutton_h}"
end
def imageInfo
case PLATFORM
when /win/i
@full_image = @image_prefix + ".jpg"
@tn_image = "tn_" + @image_prefix + ".jpg"
when /linux/i
@full_image = @image_prefix + ".png"
@tn_image = "tn_" + @image_prefix + ".png"
end
return @tn_image,@full_image
end
def fullsizeCapture
@image = @full_image
captureXwin
end
def thumbnailCapture
@tn = true
@image = @tn_image
captureXwin
end
def openResizedBrowser
openUrl = ""
case PLATFORM
when /win/i
=begin
resizeHtml = File.open(File.join(ENV["TEMP"],"_resize.html"),"w")
resizeHtmlStr = ""
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!
!
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!resize!
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!!
resizeHtmlStr += %Q!!
resizeHtml.puts resizeHtmlStr
resizeHtml.close
=end
resizeHtml = File.join(ENV["TEMP"],"_resize.html")
resizeHtmlgen(resizeHtml)
$stderr.puts "open browser with target url ..."
pid = fork{
exec(@winBrowser,`cygpath -w $TEMP/_resize.html`)
}
#sleep 1
#system(@winBrowser,`cygpath -w $TEMP/_resize.html`)
when /linux/i
proc = `ps -U #{@user} -u #{@user}`
if /#{File.basename(@browser)}/ !~ proc
# $stderr.puts "#{@browser} -P capture &"
# system("#{@browser} -P capture &")
system("#{@browser} &")
waitDisplay
end
$stderr.puts "open browser with target url ..."
resizeHtml = "/var/tmp/webnail_resize.html"
resizeHtmlgen(resizeHtml)
#system("#{@browser} -remote openURL\\(Javascript:resizeTo\\(900,810\\)\\) openURL\\(Javascript:moveTo\\(0,0\\)\\)")
#cmd = "#{@browser} -remote openURL\\(Javascript:resizeTo\\(#{@large_w + @scrollbar_w},#{@large_h + @menubutton_h + @statusbar_h}\\)\\) openURL\\(Javascript:moveTo\\(0,0\\)\\)"
cmd = "#{@browser} #{resizeHtml}"
puts ""
puts cmd
puts ""
system(cmd)
end
end
def resizeHtmlgen(html)
resizeHtml = File.open(html,"w")
resizeHtml.puts %Q''
resizeHtml.close
end
def openUrl(url)
system("#{@browser} -remote openURL\\(\'#{url}\'\\)")
end
def getWindowInfo
$stderr.puts "get xwininfo ..."
# about:blank なページでないとダメ
_browserName = ""
while _browserName = @browserName.shift
xwininfo = nil
#xwininfo = `xwininfo -int -name "#{@browserName}"`
xwininfo = `xwininfo -int -name "#{_browserName}"`
break if ! xwininfo.to_s.empty?
end
puts "="*50
puts _browserName = ""
puts xwininfo
puts "="*50
xwininfo.each{|line|
if /Window id: ([0-9]+)/ =~ line then
# @winrootid = $1
@winid = $1
end
if /Width: ([0-9]+)/ =~ line then
@width = $1
end
if /Height: ([0-9]+)/ =~ line then
@height = $1
end
}
$stderr.puts [@winid,@winrootid,@width,@height].join(" ")
=begin
xwininfo = `xwininfo -int -name "#{@browserName}"`
winid,width,height = "","",""
xwininfo.each{|line|
if /Window id: ([0-9]+)/ =~ line then
winid = $1
end
if /Width: ([0-9]+)/ =~ line then
width = $1
end
if /Height: ([0-9]+)/ =~ line then
height = $1
end
}
=end
end
def waitDisplay
monitor_line = 10
wait_time = 18
top_cmd = "top -b -n 1 -d 1 | grep #{@user} | head -#{monitor_line}"
top_result = `#{top_cmd}`
start = Time.now
$stderr.puts "now waiting ..."
while /#{File.basename(@browser)}/ =~ top_result
top_result = `#{top_cmd}`
if (Time.now - start).to_i > wait_time then
break
end
end
end
def captureXwin
geometry , quality = Array.new(2,""), Array.new(2,"")
if @tn then
tmpFile = "/var/tmp/nd_webnail.png" + $$.to_s
geometry = ["-geometry","#{@tn_w}x#{@tn_h}"]
quality = ["-quality","100"]
$stderr.puts "capture from xwin (thumbnail)..."
cmd = "import -window #{@winid} -crop #{@crop_w}x#{@crop_h}#{@crop_offset} #{quality.first} #{quality.last} -silent #{tmpFile}"
system(cmd)
cmd = "convert #{tmpFile} #{geometry.first} #{geometry.last} #{quality.first} #{quality.last} #{@out_dir}#{@image}"
system(cmd)
File.delete(tmpFile)
else
$stderr.puts "capture from xwin ..."
cmd = "import -window #{@winid} -crop #{@crop_w}x#{@crop_h}#{@crop_offset} #{geometry.first} #{geometry.last} #{quality.first} #{quality.last} -silent #{@out_dir}#{@image}"
system(cmd)
end
#system("import","-window","#{@winid}","-crop","#{@crop_w}x#{@crop_h}#{@crop_offset}","#{geometry.first}","#{geometry.last}","#{quality.first}","#{quality.last}","-silent",@out_dir + @image)
# ダミーキャプチャ @winrootid 対象に import コマンドたたくと前面に持ってきてくれる
#system("import","-window","#{@winrootid}","-silent","temp.jpg")
#File.delete("temp.jpg") if File.exist?("temp.jpg") # 掃除
#getXwinID
# メニューなど装飾部以外をキャプチャ
#p @crop_h p @crop_h
#puts @winid
#system("import","-window","#{@winid}",geometry.first,geometry.last,quality.first,quality.last,"-silent",File.join(@out_dir, @image))
end
def getXwinID
#0x1800029 "Google - Mozilla Firefox": ("Mozilla" "navigator:browser") 900x810+0+0 +177+56
# @browserName = `xwininfo -tree -root | grep -i mozilla | grep "navigator:browser"`.scan(/"(.+)":/).to_s
`xwininfo -tree -root`.each{|line|
if /"navigator:browser"/ =~ line
@browserName = line.scan(/"(.+)":/).to_s
break
end
}
xwininfo = `xwininfo -tree -name "#{@browserName}"`
xwininfo.each{|line|
if /(0x[0-9a-zA-Z]+?) /i =~ line then
@winid = $1
end
}
end
# def killBrowser
# begin
# `killall #{@processName}`
# rescue
# nil
# end
# end
#
end
class Filter
def webnail(str, type)
webnail_dir = @diary.outputDirectory + 'webnail/'
case type
when :P, :UL, :DL
use_inlineimage = false
use_inlineimage_ex = false
@diary.filter.methods.each{|m|
if /inlineimage.*/ =~ m
use_inlineimage = true
use_inlineimage_ex = true if /_ex/ =~ m
end
}
str.gsub!(/webnail\((.+?) (.+?)(( ap)| large)?\)/){
url = CGI::unescapeHTML($1)
ret_str = ""
alt = $2
ap = $3
capture = Webnail.new(url)
capture.out_dir = webnail_dir
if @diary.config['WEBNAIL_MENUBUTTON_HEIGHT'] then
capture.menubutton_h = @diary.config['WEBNAIL_MENUBUTTON_HEIGHT']
end
if @diary.config['WEBNAIL_TN_HEIGHT'] then
capture.tn_h = @diary.config['WEBNAIL_TN_HEIGHT']
end
if @diary.config['WEBNAIL_TN_WIDTH'] then
capture.tn_w = @diary.config['WEBNAIL_TN_WIDTH']
end
if @diary.config['WEBNAIL_TIME_OUT'] then
capture.timeout = @diary.config['WEBNAIL_TIME_OUT']
end
if @diary.config['WEBNAIL_BROWSER'] then
capture.browser = @diary.config['WEBNAIL_BROWSER']
end
# for Windows
if @diary.config['WEBNAIL_USE_WS'] then
capture.usewinShot = @diary.config['WEBNAIL_USE_WS']
if capture.usewinShot then
if @diary.config['WEBNAIL_WIN_SHOT'] then
capture.winShot = @diary.config['WEBNAIL_WIN_SHOT']
end
if @diary.config['WEBNAIL_WIN_BROWSER'] then
capture.winBrowser = @diary.config['WEBNAIL_WIN_BROWSER']
end
if @diary.config['WEBNAIL_WIN_CONVERT'] then
capture.winConvert = @diary.config['WEBNAIL_WIN_CONVERT']
end
end
end
capture.get_large = true if @diary.config['WEBNAIL_GET_LARGE']
capture.get_large = true if / large/ =~ ap
img_str = @diary.date + "_" + url.gsub(%r|.+?tps?://|,"").gsub(/[\W\s]/,"_").gsub(/_+$/,"")
get_image = true
tn_image , large_image = "",""
capture.image_prefix = img_str
dmy, get_img_str = capture.imageInfo
Dir.entries(webnail_dir).each{|imgfile|
if /#{get_img_str}/ =~ imgfile then
get_image = false
end
}
if get_image then
capture.webnail2
end
tn_image , large_image = capture.imageInfo
if use_inlineimage
imgstr = %Q'image(./webnail/#{tn_image} #{alt.gsub(/\ +/," ")})'
else
imgstr = %Q'
' : '>')
end
escape_url = url
if /\?/ =~ url then
escape_url = url.split("?").first + "?" + CGI::escapeHTML(url.split("?").last)
end
if @diary.config['WEBNAIL_WITH_AP'] || ap then
if / ap/ =~ ap then
ap_banner = %Q' ap:banner="./webnail/#{tn_image}"'
ret_str = %Q'#{alt}'
elsif / large/ =~ ap && capture.get_large then
ret_str = %Q'#{imgstr}#{alt}'
if use_inlineimage_ex
ret_str = %Q'image(#{escape_url}|./webnail/#{tn_image} #{alt.gsub(/\ +/," ")}|#{alt.gsub(/\ +/," ")})'
end
else
ap_banner = %Q' ap:banner="./webnail/#{tn_image}"'
ret_str = %Q'#{alt}'
end
else
ret_str = %Q'#{imgstr}'
if use_inlineimage_ex
ret_str = %Q'image(#{escape_url}|./webnail/#{tn_image} #{alt.gsub(/\ +/," ")}|#{alt.gsub(/\ +/," ")})'
end
end
ret_str << ""
}
end
end
end
# 単独で実行する
=begin
if ARGV.size == 1 and /^\d\d\d\d/ !~ ARGV.first then
if /http/ =~ ARGV.first then
url = ARGV.first
capture = Webnail.new(url)
img_str = url.gsub(%r|.+?tp://|,"").gsub(/[\W\s]/,"_").gsub(/_+$/,"")
capture.usewinShot = true
capture.get_large = true
capture.out_dir = Dir.pwd
capture.image_prefix = img_str
capture.webnail2
else
puts "webnail.rb URL sample: http://hoge.foo.bar/"
puts " ~~~~~~~"
exit 1
end
end
=end
=begin
Local Variables:
mode: ruby
coding: japanese-shift-jis-dos
End:
=end