#!/usr/bin/env ruby # # cairoを利用して時計盤を描画するRubyスクリプト # # ver. 0.0.1 2012/01/23 # # Windowsの場合、rcairo は # gem install cairo --platform x86-mingw32 # でインストールできる。(2012/01/23現在) # 拡張ライブラリは、mswin32版Rubyも、mingw32版Rubyも、 # mingw32版の拡張ライブラリバイナリで動くらしい。 require 'rubygems' require 'cairo' # ---------------------------------------- # 各種設定 outfilename = "watch_base.png" # 出力ファイル名 # 画像サイズ width, height = 480*1.5, 480*1.5 #width, height = 480, 480 #width, height = 640*2, 480*2 #width, height = 320, 320 # fps fpsv = 24 num_enable = true # 数字を描画する # num_enable = false # 数字を描画しない # trueなら画像作成後に関連付けしたアプリで開く、falseなら開かない dbg = false #dbg = true # 描画に使うフォント名 fontname = "Bitstream Vera Serif" format = Cairo::FORMAT_ARGB32 # アンチエイリアスの指定 # Cairo::ANTIALIAS_SUBPIXEL は未実装らしい? aa_mode = Cairo::ANTIALIAS_DEFAULT # aa_mode = Cairo::ANTIALIAS_GRAY # aa_mode = Cairo::ANTIALIAS_SUBPIXEL # aa_mode = Cairo::ANTIALIAS_NONE # 設定ここまで # ---------------------------------------- # 度からラジアンに変換する def radians(ang) return (ang.to_f * Math::PI / 180.0) end # 文字を描画する # cr サーフェイス操作用コンテキスト # s 描画する文字列 # x0,y0 表示位置 # fontsize 文字サイズ # fontname フォント名 # xs,ys 影をずらす量 def draw_text(cr, s, x0, y0, fontsize, fontname, xs, ys) # フォント種類を指定 cr.select_font_face(fontname, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD) # 文字サイズ指定 cr.set_font_size(fontsize) # 文字の縦横幅や描画開始位置を取得 cet = cr.text_extents(s) x_bearing = cet.x_bearing y_bearing = cet.y_bearing w = cet.width h = cet.height # 文字の描画位置を算出 x = x0 - w / 2 - x_bearing y = y0 - h / 2 - y_bearing # 文字の影を描画 if xs != 0.0 and ys != 0.0 then cr.set_source_rgb(0.8, 0.8, 0.8) # 色を指定 cr.move_to(x+xs, y+ys) cr.show_text(s) # 文字を描画 end # 文字を描画 cr.set_source_rgb(0.0, 0.0, 0.0) cr.move_to(x, y) cr.show_text(s) end # 時計盤を描画する # cr サーフェイス操作用コンテキスト # cx,cy 描画の中心位置 # r 半径 # fpsv FPS(24で固定) # num_enable trueなら数字を描画,falseなら数字は描画しない # fontname 描画に使うフォント名 def draw_watch(cr, cx, cy, r, fpsv, num_enable, fontname) rd = [0.97, 0.90, 0.87, 0.84, 0.82] # 円や目盛の位置(半径に対する割合) rdnum = [0.80, 0.76, 0.63] # 数字の表示位置決め用(小、大、大の横の小) lv = [0.0, 0.0, 0.0, 0.0] # 目盛の色の濃さ wd = 1.1 # 線の太さ # 円を描画 c = 0.0 # 線の明度(黒〜白を、0.0〜1.0で指定する) cr.set_source_rgb(c, c, c) # 描画色を指定 cr.set_line_width(wd) # 線の太さを指定 cr.arc( cx, cy, r * rd[0], 0, 2 * Math::PI) # 円を描画するよう指定 cr.arc( cx, cy, r * rd[1], 0, 2 * Math::PI) cr.arc( cx, cy, r * rd[2], 0, 2 * Math::PI) cr.stroke() # 実際に描画 # 目盛の線を描画 (6*fpsv).times do |i| ang = radians(360.0 * i / (6 * fpsv) - 90) # 角度算出 # 線の描画開始位置を算出 x0 = (r * rd[0]) * Math.cos(ang) + cx y0 = (r * rd[0]) * Math.sin(ang) + cy # カウントする数値によって線の太さや明度や描画距離を変える if ( i % fpsv ) == 0 then rr = r * rd[4] c = lv[3] # 線の明度 l = wd * 3.0 # 線の太さ elsif (i % (fpsv / 4) ) == 0 then rr = r * rd[3] c = lv[2] l = wd elsif (i % (fpsv/8) ) == 0 then rr = r * rd[2] c = lv[1] l = wd else rr = r * rd[1] c = lv[0] l = wd end # 線の描画終了位置を算出 x1 = rr.to_f * Math.cos(ang) + cx y1 = rr.to_f * Math.sin(ang) + cy cr.set_source_rgb(c, c, c) cr.set_line_width(l) cr.move_to(x0, y0) # 描画開始位置を指定 cr.line_to(x1, y1) # 描画終了位置を指定 cr.stroke() # 実際に描画 end # 目盛の数字を描画 if num_enable then # 影をずらす量 xs = r * 0.015 ys = r * 0.015 # 目盛につける数字を描画 (6*4).times do |i| ang = radians(360.0 * i / (6*4) - 90) if (i % 4) == 0 then # 大きい数字 s = [6,1,2,3,4,5][i/4] # 描画する文字 fsize = r * 0.13 r5 = r * rdnum[1] xss = xs yss = ys else # 小さい数字 s = [0,6,12,18][i%4] fsize = r * 0.07 r5 = r * rdnum[0] xss = 0 yss = 0 end s = s.to_s # 数値を文字列に変換 # 描画位置(文字の中心位置)を算出 x0 = r5 * Math.cos(ang) + cx y0 = r5 * Math.sin(ang) + cy draw_text(cr, s, x0, y0, fsize, fontname, xss, yss) # 文字描画 end # 大きい数字の横の小さい数字を描画 6.times do |i| ang = radians(360.0 * i / 6 - 90.0) s = [-1,7,8,9,10,11][i] next if s == -1 s = s.to_s fsize = r * 0.07 r5 = r * rdnum[2] x0 = r5 * Math.cos(ang) + cx y0 = r5 * Math.sin(ang) + cy xss = 0 yss = 0 draw_text(cr, s, x0, y0, fsize, fontname, xss, yss) end end end surface = Cairo::ImageSurface.new(format, width, height) context = Cairo::Context.new(surface) # アンチエイリアスの設定 context.set_antialias(aa_mode) #puts context.antialias() # 白で全面を塗り潰す context.set_source_rgb(1, 1, 1) # 描画色を指定 context.rectangle(0, 0, width, height) # 四角形を描画するように指定 context.fill # 塗り潰し # 中心点と基準となる半径を求める cx = width / 2 cy = height / 2 rb = ([width,height].min) / 2 # 時計盤を描画 draw_watch(context, cx, cy, rb, fpsv, num_enable, fontname) # ファイル保存 surface.write_to_png(outfilename) puts "#{outfilename} output." # 画像と関連付けしたアプリで開く system("start #{outfilename}") if dbg