💎️

color gem v2 の使い方

に公開

https://github.com/halostatue/color

Version

require "color"
Color::VERSION  # => "2.1.1"

生成する

Color::HSL.new(h: 0.5, s: 0.6, l: 0.7)  # => HSL [180.00deg 60.00% 70.00%]
Color::HSL.new(0.5, 0.6, 0.7)           # => HSL [180.00deg 60.00% 70.00%]
Color::HSL[0.5, 0.6, 0.7]               # => HSL [180.00deg 60.00% 70.00%]

整数から生成する

Color::HSL.from_values(180, 60, 70)           # => HSL [180.00deg 60.00% 70.00%]
Color::HSL.from_values(h: 180, s: 60, l: 70)  # => HSL [180.00deg 60.00% 70.00%]

属性値を参照する

1文字だと正規化色で、

hsl.h  # => 0.5
hsl.s  # => 0.6
hsl.l  # => 0.7

長い名前だと整数色になっていてわかりやすい。

hsl.hue         # => 180.0
hsl.saturation  # => 60.0
hsl.lightness   # => 70.0

不変である

v2 から不変に変わった。すべての色空間クラスは Data を継承しているので、

Color::HSL < Data  # => true

どうしてもあとから変更したければ作法に従って新しい値オブジェクトを生成する。

hsl = Color::HSL[0.5, 0.6, 0.7]  # => HSL [180.00deg 60.00% 70.00%]
hsl.with(h: 0.51)                # => HSL [183.60deg 60.00% 70.00%]

CSS 用に変換する

hsl.css              # => "hsl(180.00deg 60.00% 70.00%)"
hsl.css(alpha: 0.8)  # => "hsl(180.00deg 60.00% 70.00% / 0.80)"
rgb = hsl.to_rgb
rgb.html             # => "#85e0e0"
rgb.css              # => "rgb(52.00% 88.00% 88.00%)"
rgb.css(alpha: 0.8)  # => "rgb(52.00% 88.00% 88.00% / 0.80)"

非透明度は内部に持たない設計なので必要なら文字列化の際にそっと付け加える。

他の色空間に変換する

hsl.to_hsl        # => HSL [180.00deg 60.00% 70.00%]
hsl.to_cmyk       # => CMYK [45.27% 9.27% 9.27% 2.73%]
hsl.to_grayscale  # => Grayscale [70.00%]
hsl.to_rgb        # => RGB [#85e0e0]
hsl.to_xyz        # => XYZ [0.4987683810671427 0.6388042449039046 0.8049311889098675]
hsl.to_yiq        # => YIQ [77.24% 0.00% 0.00%]

明るさは共通して brightness で取れる

hsl.to_hsl.brightness rescue $!        # => 0.7
hsl.to_cmyk.brightness rescue $!       # => #<NoMethodError: undefined method 'brightness' for an instance of Color::CMYK>
hsl.to_grayscale.brightness rescue $!  # => 0.7
hsl.to_rgb.brightness rescue $!        # => 0.7723599999999999
hsl.to_xyz.brightness rescue $!        # => #<NoMethodError: undefined method 'brightness' for an instance of Color::XYZ>
hsl.to_yiq.brightness rescue $!        # => 0.7723599999999999

のかと思ったら取れないのもあった。

色名定数を使うには?

Color::RGB::Red rescue $!   # => #<NameError: uninitialized constant Color::RGB::Red>
require "color/rgb/colors"  # => true
Color::RGB::Red             # => RGB [#ff0000]

別のファイルを require すると使えるようになる。

このファイルは Color::RGB.by_* メソッドを呼ぶタイミングで読み込まれるが、色名定数だけを参照したいのであれば自分で読み込む必要がある。

Color::RGB.by_* メソッドとは? (重要)

定義済みの色テーブル (GoF でいうところのショーケース) のなかから探す。

文字列から生成する

Color::RGB.by_css("red")      # => RGB [#ff0000]
Color::RGB.by_css("#ff0000")  # => RGB [#ff0000]
Color::RGB.by_css("#f00")     # => RGB [#ff0000]
Color::RGB.by_css("f00")      # => RGB [#ff0000]

色名から生成する

Color::RGB.by_name("red")  # => RGB [#ff0000]

引数が色名だとわかっている場合に使うと意図が明確になる。

16進数文字列から生成する

Color::RGB.by_hex("#ff0000")  # => RGB [#ff0000]
Color::RGB.by_hex("ff0000")   # => RGB [#ff0000]

引数が16進数文字列だとわかっている場合に使うと意図が明確になる。

CSS特有の表記から生成する

Color::RGB.by_css("hsl(180.00deg 60.00% 70.00%)") rescue $!  # => #<ArgumentError: Not a supported HTML color type.>
Color::RGB.by_css("rgb(52.00% 88.00% 88.00%)") rescue $!     # => #<ArgumentError: Not a supported HTML color type.>

そういうのはできない。

色名を調べるには?

Color::RGB.by_css("#ff0000").name  # => "red"

でいいのだけど by_* を使わずに生成すると

Color::RGB[1.0, 0.0, 0.0].name  # => nil

色名が取れない罠がある。

その理由は ショーケース内の値オブジェクトだけが色名を知っている から。

Color::RGB[1.0, 0.0, 0.0].names     # => nil
Color::RGB.by_css("#ff0000").names  # => ["red"]
Color::RGB::Red.names               # => ["red"]

したがって通常のコンストラクタで生成した場合は、

rgb = Color::RGB[1.0, 0.0, 0.0]  # => RGB [#ff0000]
hex = rgb.hex                    # => "ff0000"
Color::RGB.by_hex(hex).name      # => "red"

いったんショーケースの方を探す必要がある。

テキストから色を抽出する

text = "Color is RED, #00ff00, #00ff01 and blue"
colors = Color::RGB.extract_colors(text)  # => [RGB [#ff0000], RGB [#00ff00], RGB [#0000ff]]
colors.collect(&:name)                    # => ["red", "lime", "blue"]

ショーケースに含まれない色は除外されていたりする。

lighten_by(100) でなぜ白にならない?

このメソッド名から挙動を見抜くのは難しい。

rgb = Color::RGB[0.0, 0.5, 1.0]  # => RGB [#0080ff]
rgb.lighten_by(0)                # => RGB [#ffffff]
rgb.lighten_by(50)               # => RGB [#80bfff]
rgb.lighten_by(100)              # => RGB [#0080ff]

lighten_by(100) は「100% 白にする」と読めるが、実際は白と混ぜるとき元の色を指定パーセント維持するという逆の挙動になっている。つまり 100% なら元の色のままで、0% なら真っ白になる。

rgb.darken_by(0)    # => RGB [#000000]
rgb.darken_by(50)   # => RGB [#004080]
rgb.darken_by(100)  # => RGB [#0080ff]

同様に darken_by の場合は 0 なら元の色が 0% なので黒になる。

1 系から 2 系にアップデートするときの主な差分

-  color.html
+  color.to_rgb.html

-  color.css_rgba(0.1)
+  color.css(alpha: 0.1)

-  Color::HSL.new(*hsl)
+  Color::HSL.from_values(*hsl)

Discussion