Class: Color::XYZ
- Inherits:
-
Data
- Object
- Data
- Color::XYZ
- Includes:
- Color
- Defined in:
- lib/color/xyz.rb,
lib/color.rb
Overview
A Color object for the CIE 1931 XYZ color space derived from the original CIE RGB color space as linear transformation functions x̅(λ), y̅(λ), and z̅(λ) that describe the device-independent CIE standard observer. It underpins most other CIE color systems (such as CIELAB), but is directly used mostly for color instrument readings and color space transformations particularly in color profiles.
The XYZ color space ranges describe the mixture of wavelengths of light required to stimulate cone cells in the human eye, as well as the luminance (brightness) required. The ‘Y` component describes the luminance while the `X` and `Z` components describe two axes of chromaticity. Definitionally, the minimum value for any XYZ color component is 0.
As XYZ describes imaginary colors, the color gamut is usually expressed in relation to a reference white of an illuminant (frequently often D65 or D50) and expressed as the ‘xyY` color space, computed as:
“‘ x = X / (X + Y + Z) y = Y / (X + Y + Z) Y = Y “`
The range of ‘Y` values is conventionally clamped to 0..100, whereas the `X` and `Z` values must be no lower than 0 and on the same scale.
For more details, see [CIE XYZ color space].
[ciexyz]: en.wikipedia.org/wiki/CIE_1931_color_space#CIE_XYZ_color_space
XYZ colors are immutable Data class instances. Array deconstruction is ‘[x * 100, y * 100, z * 100]` and hash deconstruction is `y:, z:` (see #x, #y, #z).
Constant Summary collapse
- E =
:stopdoc: NOTE: This should be using Rational instead of floating point values, otherwise there will be discontinuities. www.brucelindbloom.com/LContinuity.html :startdoc:
- K =
:nodoc:
- EK =
:nodoc:
E * K
- WP2 =
White points for standard illuminants at 2° (CIE 1931).
{ A: new(1.09849161234507, 1.0, 0.355798257454902), B: new(0.9909274480248, 1.0, 0.853132732288615), C: new(0.980705971659919, 1.0, 1.18224949392713), D50: new(0.964211994421199, 1.0, 0.825188284518828), D55: new(0.956797052643698, 1.0, 0.921480586017327), D65: new(0.950430051970945, 1.0, 1.08880649180926), D75: new(0.949722089884072, 1.0, 1.22639352072415), D93: new(0.953014035205816, 1.0, 1.41274275520851), E: new(1, 1.0, 1.0000300003), F1: new(0.92833634773327, 1.0, 1.03664719660806), F2: new(0.991446614618029, 1.0, 0.673159423379253), F3: new(1.03753487192493, 1.0, 0.49860512300279), F4: new(1.0914726375561, 1.0, 0.388132609288601), F5: new(0.908719701138108, 1.0, 0.987228866815325), F6: new(0.973091283635895, 1.0, 0.601905497618128), F7: new(0.950171560440895, 1.0, 1.08629642000425), F8: new(0.96412543554007, 1.0, 0.823331010452962), F9: new(1.00364797081623, 1.0, 0.678683511708377), F10: new(0.961735119213027, 1.0, 0.817123325737787), F11: new(1.00898894280487, 1.0, 0.642616604353936), F12: new(1.08046289656537, 1.0, 0.392275166291635), "FL3.0": new(1.09273493677163, 1.0, 0.3868088271758), "FL3.1": new(1.01981788966256, 1.0, 0.658275307980718), "FL3.2": new(0.916836289619075, 1.0, 0.990985751671998), "FL3.3": new(1.09547365817462, 1.0, 0.377937175364828), "FL3.4": new(1.02096949891068, 1.0, 0.702342047930283), "FL3.5": new(0.968888888888889, 1.0, 0.808888888888889), "FL3.6": new(1.08380716934487, 1.0, 0.388380716934487), "FL3.7": new(0.996868475991649, 1.0, 0.612734864300626), "FL3.8": new(0.974380395433027, 1.0, 0.810359231411863), "FL3.9": new(0.970505617977528, 1.0, 0.838483146067416), "FL3.10": new(0.944962143273151, 1.0, 0.967093768200349), "FL3.11": new(1.08422095615556, 1.0, 0.392865989596235), "FL3.12": new(1.02846401718582, 1.0, 0.656820622986037), "FL3.13": new(0.955112219451372, 1.0, 0.815738431698531), "FL3.14": new(0.951034063260341, 1.0, 1.09032846715328), HP1: new(1.28433734939759, 1.0, 0.125301204819277), HP2: new(1.14911014911015, 1.0, 0.255892255892256), HP3: new(1.05570552147239, 1.0, 0.398282208588957), HP4: new(1.00395048722676, 1.0, 0.62970766394522), HP5: new(1.01696741179639, 1.0, 0.676272555884729), "LED-B1": new(1.11819519372241, 1.0, 0.3339872486513), "LED-B2": new(1.08599202392822, 1.0, 0.406530408773679), "LED-B3": new(1.0088638195004, 1.0, 0.677142089712597), "LED-B4": new(0.977155910908053, 1.0, 0.87835522558538), "LED-B5": new(0.963535228677379, 1.0, 1.12669962917182), "LED-BH1": new(1.10034431874078, 1.0, 0.359075258239056), "LED-RGB1": new(1.08216575635241, 1.0, 0.292567086202802), "LED-V1": new(1.12462908011869, 1.0, 0.348170128585559), "LED-V2": new(1.00158940397351, 1.0, 0.647417218543046), ID50: new(0.952803997779012, 1.0, 0.823431426985008), ID65: new(0.939522225582099, 1.0, 1.08436649531297) }.freeze
- D50 =
The D50 standard illuminant white point at 2° (CIE 1931).
- D65 =
The D65 standard illuminant white point at 2° (CIE 1931).
Constants included from Color
Instance Attribute Summary collapse
-
#x ⇒ Object
readonly
Returns the value of attribute x.
-
#y ⇒ Object
readonly
Returns the value of attribute y.
-
#z ⇒ Object
readonly
Returns the value of attribute z.
Class Method Summary collapse
-
.from_values(*args, **kwargs) ⇒ Object
Creates a XYZ color representation from native values.
Instance Method Summary collapse
-
#coerce(other) ⇒ Object
Coerces the other Color object into XYZ.
-
#deconstruct ⇒ Object
(also: #to_a)
:nodoc:.
-
#initialize(x:, y:, z:) ⇒ XYZ
constructor
Creates a XYZ color representation from native values.
-
#inspect ⇒ Object
:nodoc:.
-
#pretty_print(q) ⇒ Object
:nodoc:.
-
#to_cmyk ⇒ Object
Converts XYZ to Color::CMYK via Color::RGB.
-
#to_grayscale ⇒ Object
Converts XYZ to Color::Grayscale using the #y value.
-
#to_hsl ⇒ Object
Converts XYZ to Color::HSL via Color::RGB.
-
#to_internal ⇒ Object
:nodoc:.
-
#to_lab(*args, **kwargs) ⇒ Object
Converts XYZ to Color::CIELAB.
-
#to_rgb ⇒ Object
Converts XYZ to Color::RGB.
- #to_xyz ⇒ Object
-
#to_yiq ⇒ Object
Converts XYZ to Color::YIQ via Color::RGB.
Methods included from Color
#==, #components, #css_value, #map, #map_with, normalize, #scale, translate_range, #zip
Constructor Details
#initialize(x:, y:, z:) ⇒ XYZ
Creates a XYZ color representation from native values. The ‘y` value must be between 0 and 1 and `x` and `z` must be fractional valiues greater than or equal to 0.
“‘ruby Color::XYZ.from_fraction(0.95047, 1.0, 1.0883) Color::XYZ.new(0.95047, 1.0, 1.08883) Color::XYZ[x: 0.95047, y: 1.0, z: 1.08883] “`
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/color/xyz.rb', line 90 def initialize(x:, y:, z:) # The X and Z values in the XYZ color model are technically unbounded. With Y scaled # to 1.0, we will clamp X to 0.0..2.2 and Z to 0.0..2.8. super( x: normalize(x, 0.0..2.2), y: normalize(y), z: normalize(z, 0.0..2.8) ) end |
Instance Attribute Details
#x ⇒ Object (readonly)
Returns the value of attribute x
49 50 51 |
# File 'lib/color.rb', line 49 def x @x end |
#y ⇒ Object (readonly)
Returns the value of attribute y
49 50 51 |
# File 'lib/color.rb', line 49 def y @y end |
#z ⇒ Object (readonly)
Returns the value of attribute z
49 50 51 |
# File 'lib/color.rb', line 49 def z @z end |
Class Method Details
.from_values(*args, **kwargs) ⇒ Object
Creates a XYZ color representation from native values. ‘y` must be between 0 and 100 and `x` and `z` values must be scaled to `y`.
“‘ruby Color::XYZ.from_values(95.047, 100.00, 108.883) Color::XYZ.from_values(x: 95.047, y: 100.00, z: 108.883) “`
call-seq:
Color::XYZ.from_values(x, y, z)
Color::XYZ.from_values(x:, y:, z:)
62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/color/xyz.rb', line 62 def self.from_values(*args, **kwargs) x, y, z = case [args, kwargs] in [[_, _, _], {}] args in [[], {x:, y:, z:}] [x, y, z] else new(*args, **kwargs) end new(x: x / 100.0, y: y / 100.0, z: z / 100.0) end |
Instance Method Details
#coerce(other) ⇒ Object
Coerces the other Color object into XYZ.
178 |
# File 'lib/color/xyz.rb', line 178 def coerce(other) = other.to_xyz |
#deconstruct ⇒ Object Also known as: to_a
:nodoc:
258 |
# File 'lib/color/xyz.rb', line 258 def deconstruct = [x * 100.0, y * 100.0, z * 100.0] # :nodoc: |
#inspect ⇒ Object
:nodoc:
263 |
# File 'lib/color/xyz.rb', line 263 def inspect = "XYZ [#{x} #{y} #{z}]" # :nodoc: |
#pretty_print(q) ⇒ Object
:nodoc:
265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/color/xyz.rb', line 265 def pretty_print(q) # :nodoc: q.text "XYZ" q.breakable q.group 2, "[", "]" do q.text "%.4f" % x q.fill_breakable q.text "%.4f" % y q.fill_breakable q.text "%.4f" % z end end |
#to_cmyk ⇒ Object
Converts XYZ to Color::CMYK via Color::RGB.
See #to_rgb and Color::RGB#to_cmyk.
187 |
# File 'lib/color/xyz.rb', line 187 def to_cmyk(...) = to_rgb(...).to_cmyk(...) |
#to_grayscale ⇒ Object
Converts XYZ to Color::Grayscale using the #y value
191 |
# File 'lib/color/xyz.rb', line 191 def to_grayscale(...) = Color::Grayscale.from_fraction(y) |
#to_hsl ⇒ Object
Converts XYZ to Color::HSL via Color::RGB.
See #to_rgb and Color::RGB#to_hsl.
197 |
# File 'lib/color/xyz.rb', line 197 def to_hsl(...) = to_rgb(...).to_hsl(...) |
#to_internal ⇒ Object
:nodoc:
261 |
# File 'lib/color/xyz.rb', line 261 def to_internal = [x, y, z] # :nodoc: |
#to_lab(*args, **kwargs) ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/color/xyz.rb', line 210 def to_lab(*args, **kwargs) ref = kwargs[:white] || args.first || Color::XYZ::D65 # Calculate the ratio of the XYZ values to the reference white. # http://www.brucelindbloom.com/index.html?Equations.html rel = scale(1.0 / ref.x, 1.0 / ref.y, 1.0 / ref.z) # And now transform # http://en.wikipedia.org/wiki/Lab_color_space#Forward_transformation # There is a brief explanation there as far as the nature of the calculations, # as well as a much nicer looking modeling of the algebra. f = rel.map { |t| if t > E t**(1.0 / 3) else # t <= E ((K * t) + 16) / 116.0 # The 4/29 here is for when t = 0 (black). 4/29 * 116 = 16, and 16 - # 16 = 0, which is the correct value for L* with black. # ((1.0/3)*((29.0/6)**2) * t) + (4.0/29) end } Color::CIELAB.from_values( (116 * f.y) - 16, 500 * (f.x - f.y), 200 * (f.y - f.z) ) end |
#to_rgb ⇒ Object
Converts XYZ to Color::RGB.
This always assumes an sRGB target color space and a D65 white point.
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/color/xyz.rb', line 241 def to_rgb(...) # sRGB companding from linear values linear = [ x * 3.2406255 + y * -1.5372080 + z * -0.4986286, x * -0.9689307 + y * 1.8757561 + z * 0.0415175, x * 0.0557101 + y * -0.2040211 + z * 1.0569959 ].map { if _1.abs <= 0.0031308 _1 * 12.92 else 1.055 * (_1**(1 / 2.4)) - 0.055 end } Color::RGB.from_fraction(*linear) end |
#to_xyz ⇒ Object
181 |
# File 'lib/color/xyz.rb', line 181 def to_xyz(...) = self |
#to_yiq ⇒ Object
Converts XYZ to Color::YIQ via Color::RGB.
See #to_rgb and Color::RGB#to_yiq.
203 |
# File 'lib/color/xyz.rb', line 203 def to_yiq(...) = to_rgb(...).to_yiq(...) |