iT邦幫忙

DAY 23
9

Rails 的簡單任務系列 第 24

[RoR] 有趣畫出 MonsterID 怪物分身

什麼是 MonsterID ?其實我的頭像,就是用 MonsterID 的其中一個實例,完全沒有用 photoshop 之類的圖形處理軟體,而是利用 ImageMagick 為指令工具把 這些身體部位的圖型,再加上不同的顏色,以隨機排列組合的方式,所疊出來的其中一個圖型。
上一篇文章提及 Don Park 提及利用基本圖型來做 IP 來源的辨識(好像也有提供是 java 的 source code ?),之後在這篇文章裡,提及利用同一觀念,而在其他程式語言環境做相關建置或延伸的連結:
http://www.docuverse.com/blog/donpark/2007/01/20/identicon-third-party-implementations
其中最有趣的是 Andi 利用 Combinatoric Critters version 裡(會走路的臉?組合而來的創造物?)的概念與做法,以 PHP 實作出 MonsterID 這個 Project 出來。

為什麼是 Monster 怪物
在最初的原型,是利用這些身體的部位,再加上顏色的不同,互相以排列組合的方式,就可畫出無數種的 critter (創造物?):

而這些是組合的順序:

就可畫出無數多的 critter:

且個個都不一樣的。這個原型,看起來是在 flash 上建置的;所以 Andi 把各個身體部位改為以圖型檔為元件,再加上顏色來做隨機的排列組合,基本上就可以為該身份畫出一個不會與其他重覆的 MonsterID 出來。

實作 MonsterID
Word Press 早就有了此 plugins,而網路上也找不到 ruby 版的 MonsterID 的實作,所以就只得利用 PHP + GD 的版本,想辦法改成 Ruby + ImageMagick 的版本。
先利用 command-line 端,做一個能隨機產生一個 MonsterID 出來試試:

# 編輯一個 monster.rb 
require 'RMagick'
include Magick

# 刪掉之前產生的測試圖形檔
`rm test.png`
# 亂數取各身體部位的某一個
partno = [ rand(4) + 1 , rand(4) + 1, rand(4) + 1, rand(14) + 1, rand(14) + 1, rand(9) + 1 ]

image = Image.new(120,120) { self.background_color = "white" }
# 順序要對,不然把圖組合起來的時候,蓋圖形的時候會不順眼
@parts = ["legs_#{partno[0]}.png","hair_#{partno[1]}.png","arms_#{partno[2]}.png","body_#{partno[3]}.png","eyes_#{partno[4]}.png","mouth_#{partno[5]}.png"]
# 這個是在還沒以亂數取部位的測試,comment起來了
#images = ImageList.new('legs_1.png','hair_1.png','arms_1.png','body_2.png','eyes_2.png','mouth_1.png')
# 用 Rmagick 把各部位的圖疊起來,
@parts.each do |part|
  imagepart = ImageList.new(part)
  image=image.composite(imagepart,Magick::CenterGravity, Magick::OverCompositeOp)
end
image.write('test.png')

上述的程式碼就可以將身體個部位以亂數的方式,組合成一個圖;但問題是 body 的顏色卻沒變化,在以下就會也把 body 的顏色,也透過亂數來做不同顏色的配置。

在 RoR 上建置 MonsterID
先下載http://www.splitbrain.org/\_media/projects/monsterid.tgz裡面有 monsterid 的 php 的程式碼,以及 parts 目錄,將 parts 目錄中的各身體部位的圖,放在 public/monster 裡頭就可開始實作看看。

  def monster
   require 'RMagick'
#算出各部位之亂數
   srand Time.now.to_f
   partno = [ rand(5) + 1 , rand(5) + 1, rand(5) + 1, rand(15) + 1, rand(15) + 1, rand(10) + 1 ]
   image = Magick::Image.new(120,120) { self.background_color = "white" }
   @parts = ["legs_#{partno[0]}.png","hair_#{partno[1]}.png","arms_#{partno[2]}.png","body_#{partno[3]}.png","eyes_#{partno[4]}.png","mouth_#{partno[5]}.png"]
# 各部位逐一畫上
   @parts.each do |part|
    file = 'public/monster/' + part
    imagepart = Magick::ImageList.new(file)
# 若是body則再亂數上色
    if part =~ /body/
      rgb = random_rgb
      imagepart=imagepart.color_floodfill(60,60,"##{rgb}")
    end
    image=image.composite(imagepart,Magick::CenterGravity, Magick::OverCompositeOp)
   end
#image.write('monster.png') 把檔案寫到硬碟的測試
#send_file('monster.png', :type => 'image/png', :disposition => 'inline') 這個語法無效
# 不用寫到硬碟的方法:
# http://furui.org/blog/2006/12/18/rounded-corners-in-rails/
# http://furui.org/tools_controller.rb
# 將做出來的圖型以 blob 產生
      blob = image.to_blob() {
        self.format = 'PNG'
        self.depth = 8
      }
# 再將圖形寫到 chache 中再送出來
      write_fragment(params, blob)
      fragment = blob
    send_data fragment, :type => 'image/png', :disposition => 'inline'
  end

然後要在 private 中,加上 random_rgb 亂數隨機取 RGB 的數字出來 的子程式

  def random_rgb
  rgb = ''
  rgbarray = %w[ 0 3 6 9 c f]
        1.step(6,1) do
                tmp = rand(6)
                rgb = rgb + rgbarray[tmp]
        end
   return rgb
  end
# 如果要符 216 安全色的話,則改為
#        1.step(3,1) do
#                tmp = rand(6)
#                rgb = rgb + rgbarray[tmp] + rgbarray[tmp]
#        end

利用此程式碼,最後完成的隨機 Monster ID,就會是

每次 Reload 一下,就會畫出不一樣的 MonsterID ;後來也有 Wavatars ,也是 WordPress 的 plugins,用同樣的原理,及另外製作的身體部位所畫出另一種風格的 MonsterID,在我的 Blog 普連鐵克斯 的頭像 也是利用上述 Rmagick 所畫出的例子。

所以這也是讓網站 user 註冊時,自動提供預設的圖像,又不會互相重覆的有趣解決方案。

參考資料
Monster 的最早原型來源,太有趣的網頁,flash 圖都點一點看看,包括樹
http://www.levitated.net/bones/walkingFaces/

MonsterID 的 Project 的網頁
http://www.splitbrain.org/projects/monsterid
http://www.splitbrain.org/blog/2007-01/20\_monsterid\_as\_gravatar\_fallback

WordPress 的 MonsterID 的 plugins
http://scott.sherrillmix.com/blog/blogger/wp\_monsterid/


上一篇
[RoR] 簡單產生 Identicon 識別圖像
下一篇
[RoR] 簡單畫出 Web 2.0 特色圖形 Badges 徽章 標記
系列文
Rails 的簡單任務33

1 則留言

0
gric
iT邦高手 1 級 ‧ 2009-03-14 13:21:54

感恩分享咯!

我要留言

立即登入留言