Module: Colors::Convert
- Defined in:
- lib/colors/convert.rb
Constant Summary collapse
- RGB2XYZ =
RGB -> ???
[ [ 0.41239079926595948129, 0.35758433938387796373, 0.18048078840183428751 ], [ 0.21263900587151035754, 0.71516867876775592746, 0.07219231536073371500 ], [ 0.01933081871559185069, 0.11919477979462598791, 0.95053215224966058086 ] ]
- R_xyY =
sRGB reference points
[0.64r, 0.33r, 1r]
- G_xyY =
[0.30r, 0.60r, 1r]
- B_xyY =
[0.15r, 0.06r, 1r]
- D65_xyY =
[0.3127r, 0.3290r, 1r]
- R_XYZ =
xyy_to_xyz(*R_xyY)
- G_XYZ =
xyy_to_xyz(*G_xyY)
- B_XYZ =
xyy_to_xyz(*B_xyY)
- D65_XYZ =
xyy_to_xyz(*D65_xyY)
- M_P =
[ [R_XYZ[0], G_XYZ[0], B_XYZ[0]], [R_XYZ[1], G_XYZ[1], B_XYZ[1]], [R_XYZ[2], G_XYZ[2], B_XYZ[2]] ]
- M_S =
dot_product(matrix_inv(M_P), D65_XYZ)
- M_RGB_XYZ =
(0 ... 3).map do |i| (0 ... 3).map {|j| (M_S[j] * M_P[i][j]).round(4) } end
- M_XYZ_RGB =
matrix_inv(M_RGB_XYZ).map do |row| row.map {|v| v.round(4) } end
Class Method Summary collapse
- .closest_xterm256_gray_index(r, g, b) ⇒ Object
- .closest_xterm256_rgb_index(x) ⇒ Object
-
.degree_to_radian(d) ⇒ Object
2 * pi / 360.
-
.lch_to_husl(l, c, h) ⇒ Object
LCh -> ???.
- .lch_to_luv(l, c, h) ⇒ Object
- .lch_to_xyz(l, c, h) ⇒ Object
-
.linear_srgb_to_srgb(r, g, b) ⇒ Object
linear-sRGB -> ???.
-
.luv_to_husl(l, u, v) ⇒ Object
Luv -> ???.
- .luv_to_lch(l, u, v) ⇒ Object
- .luv_to_xyz(l, u, v) ⇒ Object
- .max_chroma(l, h) ⇒ Object
- .rgb_to_greyscale(r, g, b) ⇒ Object
- .rgb_to_xterm256(r, g, b) ⇒ Object
- .rgb_to_xyz(r, g, b) ⇒ Object
-
.srgb_from_linear_srgb(r, g, b) ⇒ Object
sRGB -> ???.
- .srgb_to_linear_srgb(r, g, b) ⇒ Object
- .xterm256_gray_index_to_code(i) ⇒ Object
- .xterm256_gray_index_to_gray_level(i) ⇒ Object
- .xterm256_rgb_index_to_rgb_value(i) ⇒ Object
- .xterm256_rgb_indices_to_code(i, j, k) ⇒ Object
-
.xyy_to_xyz(x, y, large_y) ⇒ Object
xyY -> ???.
- .xyz_to_rgb(x, y, z) ⇒ Object
Class Method Details
.closest_xterm256_gray_index(r, g, b) ⇒ Object
192 193 194 |
# File 'lib/colors/convert.rb', line 192 def closest_xterm256_gray_index(r, g, b) ((255*(r + g + b) - 24)/30.0).round.clamp(0, 23) end |
.closest_xterm256_rgb_index(x) ⇒ Object
184 185 186 |
# File 'lib/colors/convert.rb', line 184 def closest_xterm256_rgb_index(x) ([x*255 - 55, 0].max / 40.0).round end |
.degree_to_radian(d) ⇒ Object
2 * pi / 360
64 65 66 |
# File 'lib/colors/convert.rb', line 64 def degree_to_radian(d) d * DEG2RAD end |
.lch_to_husl(l, c, h) ⇒ Object
LCh -> ???
70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/colors/convert.rb', line 70 def lch_to_husl(l, c, h) if l > 99.9999999 || l < 1e-8 s = 0r else mx = max_chroma(l, h) s = c / mx * 100r end h = 0r if c < 1e-8 [h, s/100r, l/100r] end |
.lch_to_luv(l, c, h) ⇒ Object
83 84 85 86 87 88 |
# File 'lib/colors/convert.rb', line 83 def lch_to_luv(l, c, h) h_rad = degree_to_radian(h) u = Math.cos(h_rad).to_r * c v = Math.sin(h_rad).to_r * c [l, u, v] end |
.lch_to_xyz(l, c, h) ⇒ Object
90 91 92 |
# File 'lib/colors/convert.rb', line 90 def lch_to_xyz(l, c, h) luv_to_xyz(*lch_to_luv(l, c, h)) end |
.linear_srgb_to_srgb(r, g, b) ⇒ Object
linear-sRGB -> ???
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/colors/convert.rb', line 96 def linear_srgb_to_srgb(r, g, b) [r, g, b].map do |v| # the following is an optimization technique for `1.055*v**(1/2.4) - 0.055`. # x^y ~= exp(y*log(x)) ~= exp2(y*log2(y)); the middle form is faster # # See https://github.com/JuliaGraphics/Colors.jl/issues/351#issuecomment-532073196 # for more detail benchmark in Julia language. if v <= 0.0031308 12.92*v else 1.055 * Math.exp(1/2.4 * Math.log(v)) - 0.055 end end end |
.luv_to_husl(l, u, v) ⇒ Object
Luv -> ???
113 114 115 |
# File 'lib/colors/convert.rb', line 113 def luv_to_husl(l, u, v) lch_to_husl(*luv_to_lch(l, u, v)) end |
.luv_to_lch(l, u, v) ⇒ Object
117 118 119 120 121 122 123 |
# File 'lib/colors/convert.rb', line 117 def luv_to_lch(l, u, v) c = Math.sqrt(u*u + v*v).to_r hard = Math.atan2(v, u).to_r h = hard * 180 / Math::PI.to_r h += 360r if h < 0 [l, c, h] end |
.luv_to_xyz(l, u, v) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/colors/convert.rb', line 125 def luv_to_xyz(l, u, v) return [0r, 0r, 0r] if l <= 1e-8 wp_u, wp_v = WHITE_POINT_D65.uv_values var_u = u / (13 * l) + wp_u var_v = v / (13 * l) + wp_v y = if l < 8 l / XYZ::KAPPA else ((l + 16r) / 116r)**3 end x = -(9 * y * var_u) / ((var_u - 4) * var_v - var_u * var_v) z = (9 * y - (15 * var_v * y) - (var_v * x)) / (3 * var_v) [x, y, z] end |
.max_chroma(l, h) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/colors/convert.rb', line 26 def max_chroma(l, h) h_rad = degree_to_radian(h) sin_h = Math.sin(h_rad).to_r cos_h = Math.cos(h_rad).to_r max = Float::INFINITY luminance_bounds(l).each do |line| len = line[1] / (sin_h - line[0] * cos_h) max = len if 0 <= len && len < max end max end |
.rgb_to_greyscale(r, g, b) ⇒ Object
153 154 155 156 157 |
# File 'lib/colors/convert.rb', line 153 def rgb_to_greyscale(r, g, b) r, g, b = srgb_to_linear_srgb(r, g, b) a = RGB2XYZ[1] (a[0]*r + a[1]*g + a[2]*b).clamp(0, 1) end |
.rgb_to_xterm256(r, g, b) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/colors/convert.rb', line 159 def rgb_to_xterm256(r, g, b) i = closest_xterm256_rgb_index(r) j = closest_xterm256_rgb_index(g) k = closest_xterm256_rgb_index(b) r0 = xterm256_rgb_index_to_rgb_value(i) g0 = xterm256_rgb_index_to_rgb_value(j) b0 = xterm256_rgb_index_to_rgb_value(k) d0 = (r - r0)**2 + (g - g0)**2 + (b - b0)**2 l = closest_xterm256_gray_index(r, g, b) gr = xterm256_gray_index_to_gray_level(l) d1 = (r - gr)**2 + (g - gr)**2 + (b - gr)**2 if d0 > d1 xterm256_gray_index_to_code(l) else xterm256_rgb_indices_to_code(i, j, k) end end |
.rgb_to_xyz(r, g, b) ⇒ Object
149 150 151 |
# File 'lib/colors/convert.rb', line 149 def rgb_to_xyz(r, g, b) dot_product(RGB2XYZ, srgb_to_linear_srgb(r, g, b)) end |
.srgb_from_linear_srgb(r, g, b) ⇒ Object
sRGB -> ???
206 207 208 209 210 211 212 213 214 215 |
# File 'lib/colors/convert.rb', line 206 def srgb_from_linear_srgb(r, g, b) a = 0.055r [r, g, b].map do |v| if v < 0.0031308 12.92r * v else (1 + a) * v**(1/2.4r) - a end end end |
.srgb_to_linear_srgb(r, g, b) ⇒ Object
217 218 219 220 221 222 223 224 225 226 |
# File 'lib/colors/convert.rb', line 217 def srgb_to_linear_srgb(r, g, b) a = 0.055r [r, g, b].map do |v| if v > 0.04045 ((v + a) / (1 + a)) ** 2.4r else v / 12.92r end end end |
.xterm256_gray_index_to_code(i) ⇒ Object
200 201 202 |
# File 'lib/colors/convert.rb', line 200 def xterm256_gray_index_to_code(i) i + 232 end |
.xterm256_gray_index_to_gray_level(i) ⇒ Object
188 189 190 |
# File 'lib/colors/convert.rb', line 188 def xterm256_gray_index_to_gray_level(i) (10*i + 8)/255.0 end |
.xterm256_rgb_index_to_rgb_value(i) ⇒ Object
180 181 182 |
# File 'lib/colors/convert.rb', line 180 def xterm256_rgb_index_to_rgb_value(i) (i == 0) ? 0 : (40*i + 55)/255.0 end |
.xterm256_rgb_indices_to_code(i, j, k) ⇒ Object
196 197 198 |
# File 'lib/colors/convert.rb', line 196 def xterm256_rgb_indices_to_code(i, j, k) 6*(6*i + j) + k + 16 end |
.xyy_to_xyz(x, y, large_y) ⇒ Object
xyY -> ???
230 231 232 233 234 |
# File 'lib/colors/convert.rb', line 230 def xyy_to_xyz(x, y, large_y) large_x = large_y*x/y large_z = large_y*(1 - x - y)/y [large_x, large_y, large_z] end |
.xyz_to_rgb(x, y, z) ⇒ Object
265 266 267 268 269 270 271 272 273 |
# File 'lib/colors/convert.rb', line 265 def xyz_to_rgb(x, y, z) r, g, b = dot_product(M_XYZ_RGB, [x, y, z]) r, g, b = srgb_from_linear_srgb(r, g, b) [ r.clamp(0r, 1r), g.clamp(0r, 1r), b.clamp(0r, 1r) ] end |