色コード「#RRGGBB」をパースして,適当でいいので何色か判断するクラスを作りたい。ちょっとしたアレで使用したいので。
最初に思いついたもの
やっつけなのでろくにテストも書いていない。。
rgbcolor.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #!/usr/bin/env ruby # -*- coding: utf-8 -*- class RGBColor def initialize(r, g, b) raise ArgumentError unless [r, g, b].all?{|v| (0..255) === v} @r = r @g = g @b = b @color_type = detect_color end attr_accessor :r, :g, :b def inspect "#<RGBColor(#{@r}, #{@g}, #{@b}), @color_type=#{@color_type}>" end def detect_color cr = [(@r + 1).to_f / (@g + 1 ), (@g + 1).to_f / (@b + 1 ), (@b + 1).to_f / (@r + 1 )] if cr.all?{|v| (0.9..1.1) === v} if @r < 52 color_type = :black elsif @r < 188 color_type = :gray else color_type = :white end elsif cr[0] > cr[1] if cr[1] > cr[2] color_type = :red elsif cr[0] > cr[2] color_type = :purple else color_type = :blue end else if cr[0] > cr[2] color_type = :yellow elsif cr[1] > cr[2] color_type = :green else color_type = :cyan end end color_type end private :detect_color def self.parse_hex(str) raise ArgumentError unless /^#?([a-fA-F0-9]{6})$/ =~ str ccode = $1.to_i(16) r = (ccode >> 16) & 255 g = (ccode >> 8) & 255 b = ccode & 255 self.new(r, g, b) end end if __FILE__ == $0 case ARGV.size when 1 p RGBColor.parse_hex(ARGV[0]) when 3 p RGBColor.new(ARGV[0].to_i, ARGV[1].to_i, ARGV[2].to_i) else STDERR.puts "usage: colorhex.rb (R G B|RRGGBB)" end end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | udzura@ubuntu-vaio:~/dev$ irb -rrgbcolor irb(main):001:0> RGBColor.parse_hex("#aa66cc") => #<RGBColor(170, 102, 204), @color_type=:purple> irb(main):002:0> RGBColor.parse_hex("#dd0000") => #<RGBColor(221, 0, 0), @color_type=:red> irb(main):003:0> RGBColor.parse_hex("#000000") => #<RGBColor(0, 0, 0), @color_type=:black> irb(main):004:0> RGBColor.parse_hex("#888888") => #<RGBColor(136, 136, 136), @color_type=:gray> irb(main):005:0> RGBColor.parse_hex("#00aa88") => #<RGBColor(0, 170, 136), @color_type=:cyan> irb(main):006:0> RGBColor.parse_hex("#00aa44") => #<RGBColor(0, 170, 68), @color_type=:cyan> irb(main):007:0> RGBColor.parse_hex("#00aa00") => #<RGBColor(0, 170, 0), @color_type=:green> |
大体合ってなくはないけど,何かいいかげん。。。
アルゴリズム
色(r, g, b)(0≦r, g, b≦255)に対して,以下の条件が成り立つなら→で示す色であるとする。
r > g = b → 赤 r < g = b → 水色 g > r = b → 緑 g < r = b → 紫 b > r = g → 青 b < r = g → 黄色
以上を (A) とする。
また,以下を(1),(2),(3)とする。
r + 1 ------- … (1) g + 1 g + 1 ------- … (2) b + 1 b + 1 ------- … (3) r + 1
(A)と(1),(2),(3)から,以下が言える。
(1) > (2) > (3) → 赤 (3) > (2) > (1) → 水色 (2) > (3) > (1) → 緑 (1) > (3) > (2) → 紫 (3) > (1) > (2) → 青 (2) > (1) > (3) → 黄色
また,(1),(2),(3)すべてが1に近い場合は無彩色であろう。なので、rの値で黒,灰色,白を判断する。
これはひどい車輪の再発明
そもそもRubyにはRMagickと言う素晴らしいライブラリが用意されており,それはImageMagickというCUIの画像加工ツールのラッパーである(説明口調)。
色々調べたら,HSLという表現方法のほうが「結局お前何色よ?」が分かりやすくて,RMagickなら Pixcel#to_hlsa とかそういうメソッドで変換できるそうな。どう考えてもこっちの方がいいな……。
- 参考1: Wikipedia – HLS色空間
- 参考2: ImageMagickでHSLとHSV色空間を理解する
- 参考3: Pixcel#to_hlsa