module ChunkyPNG::Color

The Color module defines methods for handling colors. Within the ChunkyPNG library, the concepts of pixels and colors are both used, and they are both represented by a Integer.

Pixels/colors are represented in RGBA components. Each of the four components is stored with a depth of 8 bits (maximum value = 255 = {ChunkyPNG::Color::MAX}). Together, these components are stored in a 4-byte Integer.

A color will always be represented using these 4 components in memory. When the image is encoded, a more suitable representation can be used (e.g. rgb, grayscale, palette-based), for which several conversion methods are provided in this module.

Constants

BLACK

@return [Integer] Black pixel/color

HEX3_COLOR_REGEXP

@private @return [Regexp] The regexp to parse 3-digit hex color values.

HEX6_COLOR_REGEXP

@private @return [Regexp] The regexp to parse 6- and 8-digit hex color values.

HTML_COLOR_REGEXP

@private @return [Regexp] The regexp to parse named color values.

MAX

@return [Integer] The maximum value of each color component.

MAX_EUCLIDEAN_DISTANCE_RGBA

Could be simplified as MAX * 2, but this format mirrors the math in {#euclidean_distance_rgba} @return [Float] The maximum Euclidean distance of two RGBA colors.

PREDEFINED_COLORS

@return [Hash<Symbol, Integer>] All the predefined color names in HTML.

TRANSPARENT

@return [Integer] Fully transparent pixel/color

WHITE

@return [Integer] White pixel/color

Public Instance Methods

a(value) click to toggle source

Returns the alpha channel value for the color value.

@param [Integer] value The color value. @return [Integer] A value between 0 and MAX.

    # File lib/chunky_png/color.rb
299 def a(value)
300   value & 0x000000ff
301 end
alpha_decomposable?(color, mask, bg, tolerance = 1) click to toggle source

Checks whether an alpha channel value can successfully be composed given the resulting color, the mask color and a background color, all of which should be opaque.

@param [Integer] color The color that was the result of compositing. @param [Integer] mask The opaque variant of the color that was being

composed

@param [Integer] bg The background color on which the color was composed. @param [Integer] tolerance The decomposition tolerance level, a value

between 0 and 255.

@return [Boolean] True if the alpha component can be decomposed

successfully.

@see decompose_alpha

    # File lib/chunky_png/color.rb
503 def alpha_decomposable?(color, mask, bg, tolerance = 1)
504   components = decompose_alpha_components(color, mask, bg)
505   sum = components.inject(0) { |a, b| a + b }
506   max = components.max * 3
507   components.max <= 255 && components.min >= 0 && (sum + tolerance * 3) >= max
508 end
b(value) click to toggle source

Returns the blue-component from the color value.

@param [Integer] value The color value. @return [Integer] A value between 0 and MAX.

    # File lib/chunky_png/color.rb
291 def b(value)
292   (value & 0x0000ff00) >> 8
293 end
blend(fg, bg) click to toggle source

Blends the foreground and background color by taking the average of the components.

@param [Integer] fg The foreground color. @param [Integer] bg The foreground color. @return [Integer] The blended color.

    # File lib/chunky_png/color.rb
406 def blend(fg, bg)
407   (fg + bg) >> 1
408 end
compose(fg, bg)
Alias for: compose_quick
compose_precise(fg, bg) click to toggle source

Composes two colors with an alpha channel using floating point math.

This method uses more precise floating point math, but this precision is lost when the result is converted back to an integer. Because it is slower than the version based on integer math, that version is preferred.

@param [Integer] fg The foreground color. @param [Integer] bg The background color. @return [Integer] The composited color. @see ChunkyPNG::Color#compose_quick

    # File lib/chunky_png/color.rb
383 def compose_precise(fg, bg)
384   return fg if opaque?(fg) || fully_transparent?(bg)
385   return bg if fully_transparent?(fg)
386 
387   fg_a  = a(fg).to_f / MAX
388   bg_a  = a(bg).to_f / MAX
389   a_com = (1.0 - fg_a) * bg_a
390 
391   new_r = (fg_a * r(fg) + a_com * r(bg)).round
392   new_g = (fg_a * g(fg) + a_com * g(bg)).round
393   new_b = (fg_a * b(fg) + a_com * b(bg)).round
394   new_a = ((fg_a + a_com) * MAX).round
395   rgba(new_r, new_g, new_b, new_a)
396 end
compose_quick(fg, bg) click to toggle source

Composes two colors with an alpha channel using integer math.

This version is faster than the version based on floating point math, so this compositing function is used by default.

@param [Integer] fg The foreground color. @param [Integer] bg The background color. @return [Integer] The composited color. @see ChunkyPNG::Color#compose_precise

    # File lib/chunky_png/color.rb
361 def compose_quick(fg, bg)
362   return fg if opaque?(fg) || fully_transparent?(bg)
363   return bg if fully_transparent?(fg)
364 
365   a_com = int8_mult(0xff - a(fg), a(bg))
366   new_r = int8_mult(a(fg), r(fg)) + int8_mult(a_com, r(bg))
367   new_g = int8_mult(a(fg), g(fg)) + int8_mult(a_com, g(bg))
368   new_b = int8_mult(a(fg), b(fg)) + int8_mult(a_com, b(bg))
369   new_a = a(fg) + a_com
370   rgba(new_r, new_g, new_b, new_a)
371 end
Also aliased as: compose
decompose_alpha(color, mask, bg) click to toggle source

Decomposes the alpha channel value given the resulting color, the mask color and a background color, all of which should be opaque.

Make sure to call {#alpha_decomposable?} first to see if the alpha channel value can successfully decomposed with a given tolerance, otherwise the return value of this method is undefined.

@param [Integer] color The color that was the result of compositing. @param [Integer] mask The opaque variant of the color that was being

composed

@param [Integer] bg The background color on which the color was composed. @return [Integer] The best fitting alpha channel, a value between 0 and

255.

@see alpha_decomposable?

    # File lib/chunky_png/color.rb
524 def decompose_alpha(color, mask, bg)
525   components = decompose_alpha_components(color, mask, bg)
526   (components.inject(0) { |a, b| a + b } / 3.0).round
527 end
decompose_alpha_component(channel, color, mask, bg) click to toggle source

Decomposes an alpha channel for either the r, g or b color channel. @param [:r, :g, :b] channel The channel to decompose the alpha channel

from.

@param [Integer] color The color that was the result of compositing. @param [Integer] mask The opaque variant of the color that was being

composed

@param [Integer] bg The background color on which the color was composed. @return [Integer] The decomposed alpha value for the channel.

    # File lib/chunky_png/color.rb
537 def decompose_alpha_component(channel, color, mask, bg)
538   cc, mc, bc = send(channel, color), send(channel, mask), send(channel, bg)
539 
540   return 0x00 if bc == cc
541   return 0xff if bc == mc
542   return 0xff if cc == mc
543 
544   (((bc - cc).to_f / (bc - mc).to_f) * MAX).round
545 end
decompose_alpha_components(color, mask, bg) click to toggle source

Decomposes the alpha channels for the r, g and b color channel. @param [Integer] color The color that was the result of compositing. @param [Integer] mask The opaque variant of the color that was being

composed

@param [Integer] bg The background color on which the color was composed. @return [Array<Integer>] The decomposed alpha values for the r, g and b

channels.
    # File lib/chunky_png/color.rb
554 def decompose_alpha_components(color, mask, bg)
555   [
556     decompose_alpha_component(:r, color, mask, bg),
557     decompose_alpha_component(:g, color, mask, bg),
558     decompose_alpha_component(:b, color, mask, bg),
559   ]
560 end
decompose_color(color, mask, bg, tolerance = 1) click to toggle source

Decomposes a color, given a color, a mask color and a background color. The returned color will be a variant of the mask color, with the alpha channel set to the best fitting value. This basically is the reverse operation if alpha composition.

If the color cannot be decomposed, this method will return the fully transparent variant of the mask color.

@param [Integer] color The color that was the result of compositing. @param [Integer] mask The opaque variant of the color that was being

composed

@param [Integer] bg The background color on which the color was composed. @param [Integer] tolerance The decomposition tolerance level, a value

between 0 and 255.

@return [Integer] The decomposed color, a variant of the masked color

with the alpha channel set to an appropriate value.
    # File lib/chunky_png/color.rb
482 def decompose_color(color, mask, bg, tolerance = 1)
483   if alpha_decomposable?(color, mask, bg, tolerance)
484     mask & 0xffffff00 | decompose_alpha(color, mask, bg)
485   else
486     mask & 0xffffff00
487   end
488 end
euclidean_distance_rgba(pixel_after, pixel_before) click to toggle source

Compute the Euclidean distance between 2 colors in RGBA

This method simply takes the Euclidean distance between the RGBA channels of 2 colors, which gives us a measure of how different the two colors are.

Although it would be more perceptually accurate to calculate a proper Delta E in Lab colorspace, this method should serve many use-cases while avoiding the overhead of converting RGBA to Lab.

@param pixel_after [Integer] @param pixel_before [Integer] @return [Float]

    # File lib/chunky_png/color.rb
722 def euclidean_distance_rgba(pixel_after, pixel_before)
723   return 0.0 if pixel_after == pixel_before
724 
725   Math.sqrt(
726     (r(pixel_after) - r(pixel_before))**2 +
727     (g(pixel_after) - g(pixel_before))**2 +
728     (b(pixel_after) - b(pixel_before))**2 +
729     (a(pixel_after) - a(pixel_before))**2
730   )
731 end
fade(color, factor) click to toggle source

Lowers the intensity of a color, by lowering its alpha by a given factor. @param [Integer] color The color to adjust. @param [Integer] factor Fade factor as an integer between 0 and 255. @return [Integer] The faded color.

    # File lib/chunky_png/color.rb
461 def fade(color, factor)
462   new_alpha = int8_mult(a(color), factor)
463   (color & 0xffffff00) | new_alpha
464 end
from_hex(hex_value, opacity = nil) click to toggle source

Creates a color by converting it from a string in hex notation.

It supports colors with (rrggbbaa) or without (rrggbb) alpha channel as well as the 3-digit short format (rgb) for those without. Color strings may include the prefix “0x” or “#”.

@param [String] hex_value The color in hex notation. @param [Integer] opacity The opacity value for the color. Overrides any

opacity value given in the hex value if given.

@return [Integer] The color value. @raise [ArgumentError] if the value given is not a hex color notation.

    # File lib/chunky_png/color.rb
167 def from_hex(hex_value, opacity = nil)
168   base_color = case hex_value
169     when HEX3_COLOR_REGEXP
170       $1.gsub(/([0-9a-f])/i, '\1\1').hex << 8
171     when HEX6_COLOR_REGEXP
172       $1.hex << 8
173     else
174       raise ArgumentError, "Not a valid hex color notation: #{hex_value.inspect}!"
175   end
176   opacity ||= $2 ? $2.hex : 0xff
177   base_color | opacity
178 end
from_hsb(hue, saturation, value, alpha = 255)
Alias for: from_hsv
from_hsl(hue, saturation, lightness, alpha = 255) click to toggle source

Creates a new color from an HSL triple.

This implementation follows the modern convention of 0 degrees hue indicating red.

@param [Fixnum] hue The hue component (0-360) @param [Fixnum] saturation The saturation component (0-1) @param [Fixnum] lightness The lightness component (0-1) @param [Fixnum] alpha Defaults to opaque (255). @return [Integer] The newly constructed color value. @raise [ArgumentError] if the hsl triple is invalid. @see en.wikipedia.org/wiki/HSL_and_HSV

    # File lib/chunky_png/color.rb
220 def from_hsl(hue, saturation, lightness, alpha = 255)
221   raise ArgumentError, "Hue #{hue} was not between 0 and 360" unless (0..360).cover?(hue)
222   raise ArgumentError, "Saturation #{saturation} was not between 0 and 1" unless (0..1).cover?(saturation)
223   raise ArgumentError, "Lightness #{lightness} was not between 0 and 1" unless (0..1).cover?(lightness)
224 
225   chroma = (1 - (2 * lightness - 1).abs) * saturation
226   rgb    = cylindrical_to_cubic(hue, saturation, lightness, chroma)
227   rgb.map! { |component| ((component + lightness - 0.5 * chroma) * 255).to_i }
228   rgb << alpha
229   rgba(*rgb)
230 end
from_hsv(hue, saturation, value, alpha = 255) click to toggle source

Creates a new color from an HSV triple.

Create a new color using an HSV (sometimes also called HSB) triple. The words ‘value` and `brightness` are used interchangeably and synonymously in descriptions of this colorspace. This implementation follows the modern convention of 0 degrees hue indicating red.

@param [Fixnum] hue The hue component (0-360) @param [Fixnum] saturation The saturation component (0-1) @param [Fixnum] value The value (brightness) component (0-1) @param [Fixnum] alpha Defaults to opaque (255). @return [Integer] The newly constructed color value. @raise [ArgumentError] if the hsv triple is invalid. @see en.wikipedia.org/wiki/HSL_and_HSV

    # File lib/chunky_png/color.rb
194 def from_hsv(hue, saturation, value, alpha = 255)
195   raise ArgumentError, "Hue must be between 0 and 360" unless (0..360).cover?(hue)
196   raise ArgumentError, "Saturation must be between 0 and 1" unless (0..1).cover?(saturation)
197   raise ArgumentError, "Value/brightness must be between 0 and 1" unless (0..1).cover?(value)
198 
199   chroma = value * saturation
200   rgb    = cylindrical_to_cubic(hue, saturation, value, chroma)
201   rgb.map! { |component| ((component + value - chroma) * 255).to_i }
202   rgb << alpha
203   rgba(*rgb)
204 end
Also aliased as: from_hsb
from_rgb_stream(stream, pos = 0) click to toggle source

Creates a color by unpacking an rgb triple from a string.

@param [String] stream The string to load the color from. It should be

at least 3 + pos bytes long.

@param [Integer] pos The position in the string to load the triple from. @return [Integer] The newly constructed color value.

    # File lib/chunky_png/color.rb
142 def from_rgb_stream(stream, pos = 0)
143   rgb(*stream.unpack("@#{pos}C3"))
144 end
from_rgba_stream(stream, pos = 0) click to toggle source

Creates a color by unpacking an rgba triple from a string

@param [String] stream The string to load the color from. It should be

at least 4 + pos bytes long.

@param [Integer] pos The position in the string to load the triple from. @return [Integer] The newly constructed color value.

    # File lib/chunky_png/color.rb
152 def from_rgba_stream(stream, pos = 0)
153   rgba(*stream.unpack("@#{pos}C4"))
154 end
fully_transparent?(value) click to toggle source

Returns true if this color is fully transparent.

@param [Integer] value The color to test. @return [true, false] True if the alpha channel equals 0.

    # File lib/chunky_png/color.rb
330 def fully_transparent?(value)
331   a(value) == 0x00000000
332 end
g(value) click to toggle source

Returns the green-component from the color value.

@param [Integer] value The color value. @return [Integer] A value between 0 and MAX.

    # File lib/chunky_png/color.rb
283 def g(value)
284   (value & 0x00ff0000) >> 16
285 end
grayscale(teint) click to toggle source

Creates a new color using a grayscale teint. @param [Integer] teint The grayscale teint (0-255), will be used as r, g,

and b value.

@return [Integer] The newly constructed color value.

    # File lib/chunky_png/color.rb
119 def grayscale(teint)
120   teint << 24 | teint << 16 | teint << 8 | 0xff
121 end
grayscale?(value) click to toggle source

Returns true if this color is fully transparent.

@param [Integer] value The color to test. @return [true, false] True if the r, g and b component are equal.

    # File lib/chunky_png/color.rb
322 def grayscale?(value)
323   r(value) == b(value) && b(value) == g(value)
324 end
grayscale_alpha(teint, a) click to toggle source

Creates a new color using a grayscale teint and alpha value. @param [Integer] teint The grayscale teint (0-255), will be used as r, g,

and b value.

@param [Integer] a The opacity (0-255) @return [Integer] The newly constructed color value.

    # File lib/chunky_png/color.rb
128 def grayscale_alpha(teint, a)
129   teint << 24 | teint << 16 | teint << 8 | a
130 end
grayscale_teint(color) click to toggle source

Calculates the grayscale teint of an RGB color.

@param [Integer] color The color to convert. @return [Integer] The grayscale teint of the input color, 0-255.

    # File lib/chunky_png/color.rb
438 def grayscale_teint(color)
439   (r(color) * 0.3 + g(color) * 0.59 + b(color) * 0.11).round
440 end
html_color(color_name, opacity = nil) click to toggle source

Gets a color value based on a HTML color name.

The color name is flexible. E.g. 'yellowgreen', 'Yellow green', 'YellowGreen', 'YELLOW_GREEN' and :yellow_green will all return the same color value.

You can include a opacity level in the color name (e.g. 'red @ 0.5') or give an explicit opacity value as second argument. If no opacity value is given, the color will be fully opaque.

@param [Symbol, String] color_name The color name. It may include an

opacity specifier like <tt>@ 0.8</tt> to set the color's opacity.

@param [Integer] opacity The opacity value for the color between 0 and

255. Overrides any opacity value given in the color name.

@return [Integer] The color value. @raise [ChunkyPNG::Exception] If the color name was not recognized.

    # File lib/chunky_png/color.rb
909 def html_color(color_name, opacity = nil)
910   if color_name.to_s =~ HTML_COLOR_REGEXP
911     opacity ||= $2 ? ($2.to_f * 255.0).round : 0xff
912     base_color_name = $1.gsub(/[^a-z]+/i, "").downcase.to_sym
913     return PREDEFINED_COLORS[base_color_name] | opacity if PREDEFINED_COLORS.key?(base_color_name)
914   end
915   raise ArgumentError, "Unknown color name #{color_name}!"
916 end
int8_mult(a, b) click to toggle source

Multiplies two fractions using integer math, where the fractions are stored using an integer between 0 and 255. This method is used as a helper method for compositing colors using integer math.

This is a quicker implementation of ((a * b) / 255.0).round.

@param [Integer] a The first fraction. @param [Integer] b The second fraction. @return [Integer] The result of the multiplication.

    # File lib/chunky_png/color.rb
347 def int8_mult(a, b)
348   t = a * b + 0x80
349   ((t >> 8) + t) >> 8
350 end
interpolate_quick(fg, bg, alpha) click to toggle source

Interpolates the foreground and background colors by the given alpha value. This also blends the alpha channels themselves.

A blending factor of 255 will give entirely the foreground, while a blending factor of 0 will give the background.

@param [Integer] fg The foreground color. @param [Integer] bg The background color. @param [Integer] alpha The blending factor (fixed 8bit) @return [Integer] The interpolated color.

    # File lib/chunky_png/color.rb
420 def interpolate_quick(fg, bg, alpha)
421   return fg if alpha >= 255
422   return bg if alpha <= 0
423 
424   alpha_com = 255 - alpha
425 
426   new_r = int8_mult(alpha, r(fg)) + int8_mult(alpha_com, r(bg))
427   new_g = int8_mult(alpha, g(fg)) + int8_mult(alpha_com, g(bg))
428   new_b = int8_mult(alpha, b(fg)) + int8_mult(alpha_com, b(bg))
429   new_a = int8_mult(alpha, a(fg)) + int8_mult(alpha_com, a(bg))
430 
431   rgba(new_r, new_g, new_b, new_a)
432 end
opaque!(value) click to toggle source

Returns the opaque value of this color by removing the alpha channel. @param [Integer] value The color to transform. @return [Integer] The opaque color

    # File lib/chunky_png/color.rb
314 def opaque!(value)
315   value | 0x000000ff
316 end
opaque?(value) click to toggle source

Returns true if this color is fully opaque.

@param [Integer] value The color to test. @return [true, false] True if the alpha channel equals MAX.

    # File lib/chunky_png/color.rb
307 def opaque?(value)
308   a(value) == 0x000000ff
309 end
parse(source) click to toggle source

Parses a color value given a numeric or string argument.

It supports color numbers, colors in hex notation and named HTML colors.

@param [Integer, String] source The color value. @return [Integer] The color value, with the opacity applied if one was

given.
   # File lib/chunky_png/color.rb
86 def parse(source)
87   return source if source.is_a?(Integer)
88   case source.to_s
89     when /^\d+$/ then source.to_s.to_i
90     when HEX3_COLOR_REGEXP, HEX6_COLOR_REGEXP then from_hex(source.to_s)
91     when HTML_COLOR_REGEXP then html_color(source.to_s)
92     else raise ArgumentError, "Don't know how to create a color from #{source.inspect}!"
93   end
94 end
pass_bytesize(color_mode, depth, width, height) click to toggle source

Returns the number of bytes used for an image pass @param [Integer] color_mode The color mode in which the pixels are

stored.

@param [Integer] depth The color depth of the pixels. @param [Integer] width The width of the image pass. @param [Integer] height The height of the image pass. @return [Integer] The number of bytes used per scanline in a datastream.

    # File lib/chunky_png/color.rb
984 def pass_bytesize(color_mode, depth, width, height)
985   return 0 if width == 0 || height == 0
986   (scanline_bytesize(color_mode, depth, width) + 1) * height
987 end
pixel_bitsize(color_mode, depth = 8) click to toggle source

Returns the size in bits of a pixel when it is stored using a given color mode.

@param [Integer] color_mode The color mode in which the pixels are

stored.

@param [Integer] depth The color depth of the pixels. @return [Integer] The number of bytes used per pixel in a datastream.

    # File lib/chunky_png/color.rb
963 def pixel_bitsize(color_mode, depth = 8)
964   samples_per_pixel(color_mode) * depth
965 end
pixel_bytesize(color_mode, depth = 8) click to toggle source

Returns the size in bytes of a pixel when it is stored using a given color mode.

@param [Integer] color_mode The color mode in which the pixels are

stored.

@return [Integer] The number of bytes used per pixel in a datastream.

    # File lib/chunky_png/color.rb
951 def pixel_bytesize(color_mode, depth = 8)
952   return 1 if depth < 8
953   (pixel_bitsize(color_mode, depth) + 7) >> 3
954 end
r(value) click to toggle source

Returns the red-component from the color value.

@param [Integer] value The color value. @return [Integer] A value between 0 and MAX.

    # File lib/chunky_png/color.rb
275 def r(value)
276   (value & 0xff000000) >> 24
277 end
rgb(r, g, b) click to toggle source

Creates a new color using an r, g, b triple. @param [Integer] r The r-component (0-255) @param [Integer] g The g-component (0-255) @param [Integer] b The b-component (0-255) @return [Integer] The newly constructed color value.

    # File lib/chunky_png/color.rb
111 def rgb(r, g, b)
112   r << 24 | g << 16 | b << 8 | 0xff
113 end
rgba(r, g, b, a) click to toggle source

Creates a new color using an r, g, b triple and an alpha value. @param [Integer] r The r-component (0-255) @param [Integer] g The g-component (0-255) @param [Integer] b The b-component (0-255) @param [Integer] a The opacity (0-255) @return [Integer] The newly constructed color value.

    # File lib/chunky_png/color.rb
102 def rgba(r, g, b, a)
103   r << 24 | g << 16 | b << 8 | a
104 end
samples_per_pixel(color_mode) click to toggle source

Returns the number of sample values per pixel. @param [Integer] color_mode The color mode being used. @return [Integer] The number of sample values per pixel.

    # File lib/chunky_png/color.rb
934 def samples_per_pixel(color_mode)
935   case color_mode
936     when ChunkyPNG::COLOR_INDEXED         then 1
937     when ChunkyPNG::COLOR_TRUECOLOR       then 3
938     when ChunkyPNG::COLOR_TRUECOLOR_ALPHA then 4
939     when ChunkyPNG::COLOR_GRAYSCALE       then 1
940     when ChunkyPNG::COLOR_GRAYSCALE_ALPHA then 2
941     else raise ChunkyPNG::NotSupported, "Don't know the number of samples for this colormode: #{color_mode}!"
942   end
943 end
scanline_bytesize(color_mode, depth, width) click to toggle source

Returns the number of bytes used per scanline. @param [Integer] color_mode The color mode in which the pixels are

stored.

@param [Integer] depth The color depth of the pixels. @param [Integer] width The number of pixels per scanline. @return [Integer] The number of bytes used per scanline in a datastream.

    # File lib/chunky_png/color.rb
973 def scanline_bytesize(color_mode, depth, width)
974   ((pixel_bitsize(color_mode, depth) * width) + 7) >> 3
975 end
to_grayscale(color) click to toggle source

Converts a color to a fiting grayscale value. It will conserve the alpha channel.

This method will return a full color value, with the R, G, and B value set to the grayscale teint calcuated from the input color’s R, G and B values.

@param [Integer] color The color to convert. @return [Integer] The input color, converted to the best fitting

grayscale.

@see grayscale_teint

    # File lib/chunky_png/color.rb
453 def to_grayscale(color)
454   grayscale_alpha(grayscale_teint(color), a(color))
455 end
to_grayscale_alpha_bytes(color) click to toggle source

Returns an array with the grayscale teint and alpha channel values for this color.

This method expects the color to be grayscale, i.e. r, g, and b value to be equal and uses only the B channel. If you need to convert a color to grayscale first, see {#to_grayscale}.

@param [Integer] color The grayscale color to convert. @return [Array<Integer>] An array with 2 Integer elements. @see to_grayscale

    # File lib/chunky_png/color.rb
701 def to_grayscale_alpha_bytes(color)
702   [b(color), a(color)] # assumption r == g == b
703 end
to_grayscale_bytes(color) click to toggle source

Returns an array with the grayscale teint value for this color.

This method expects the r, g, and b value to be equal, and the alpha channel will be discarded.

@param [Integer] color The grayscale color to convert. @return [Array<Integer>] An array with 1 Integer element.

    # File lib/chunky_png/color.rb
687 def to_grayscale_bytes(color)
688   [b(color)] # assumption r == g == b
689 end
to_hex(color, include_alpha = true) click to toggle source

Returns a string representing this color using hex notation (i.e. rrggbbaa).

@param [Integer] color The color to convert. @param [Boolean] include_alpha @return [String] The color in hex notation, starting with a pound sign.

    # File lib/chunky_png/color.rb
572 def to_hex(color, include_alpha = true)
573   include_alpha ? ("#%08x" % color) : ("#%06x" % [color >> 8])
574 end
to_hsb(color, include_alpha = false)
Alias for: to_hsv
to_hsl(color, include_alpha = false) click to toggle source

Returns an array with the separate HSL components of a color.

Because ChunkyPNG internally handles colors as Integers for performance reasons, some rounding occurs when importing or exporting HSL colors whose coordinates are float-based. Because of this rounding, to_hsl and from_hsl may not be perfect inverses.

This implementation follows the modern convention of 0 degrees hue indicating red.

@param [Integer] color The ChunkyPNG color to convert. @param [Boolean] include_alpha Flag indicates whether a fourth element

representing alpha channel should be included in the returned array.

@return [Array<Fixnum>] The hue of the color (0-360) @return [Array<Fixnum>] The saturation of the color (0-1) @return [Array<Fixnum>] The lightness of the color (0-1) @return [Array<Fixnum>] Optional fourth element for alpha, included if

include_alpha=true (0-255)

@see en.wikipedia.org/wiki/HSL_and_HSV

    # File lib/chunky_png/color.rb
624 def to_hsl(color, include_alpha = false)
625   hue, chroma, max, min = hue_and_chroma(color)
626   lightness  = 0.5 * (max + min)
627   saturation = chroma.zero? ? 0.0 : chroma.fdiv(1 - (2 * lightness - 1).abs)
628 
629   include_alpha ? [hue, saturation, lightness, a(color)] :
630                   [hue, saturation, lightness]
631 end
to_hsv(color, include_alpha = false) click to toggle source

Returns an array with the separate HSV components of a color.

Because ChunkyPNG internally handles colors as Integers for performance reasons, some rounding occurs when importing or exporting HSV colors whose coordinates are float-based. Because of this rounding, to_hsv and from_hsv may not be perfect inverses.

This implementation follows the modern convention of 0 degrees hue indicating red.

@param [Integer] color The ChunkyPNG color to convert. @param [Boolean] include_alpha Flag indicates whether a fourth element

representing alpha channel should be included in the returned array.

@return [Array] The hue of the color (0-360) @return [Array] The saturation of the color (0-1) @return [Array] The value of the color (0-1) @return [Array] Optional fourth element for alpha, included if

include_alpha=true (0-255)

@see en.wikipedia.org/wiki/HSL_and_HSV

    # File lib/chunky_png/color.rb
595 def to_hsv(color, include_alpha = false)
596   hue, chroma, max, _ = hue_and_chroma(color)
597   value      = max
598   saturation = chroma.zero? ? 0.0 : chroma.fdiv(value)
599 
600   include_alpha ? [hue, saturation, value, a(color)] :
601                   [hue, saturation, value]
602 end
Also aliased as: to_hsb
to_truecolor_alpha_bytes(color) click to toggle source

Returns an array with the separate RGBA values for this color.

@param [Integer] color The color to convert. @return [Array<Integer>] An array with 4 Integer elements.

    # File lib/chunky_png/color.rb
667 def to_truecolor_alpha_bytes(color)
668   [r(color), g(color), b(color), a(color)]
669 end
to_truecolor_bytes(color) click to toggle source

Returns an array with the separate RGB values for this color. The alpha channel will be discarded.

@param [Integer] color The color to convert. @return [Array<Integer>] An array with 3 Integer elements.

    # File lib/chunky_png/color.rb
676 def to_truecolor_bytes(color)
677   [r(color), g(color), b(color)]
678 end

Private Instance Methods

cylindrical_to_cubic(hue, saturation, y_component, chroma) click to toggle source

Convert one HSL or HSV triple and associated chroma to a scaled rgb triple

This method encapsulates the shared mathematical operations needed to convert coordinates from a cylindrical colorspace such as HSL or HSV into coordinates of the RGB colorspace.

Even though chroma values are derived from the other three coordinates, the formula for calculating chroma differs for each colorspace. Since it is calculated differently for each colorspace, it must be passed in as a parameter.

@param [Fixnum] hue The hue-component (0-360) @param [Fixnum] saturation The saturation-component (0-1) @param [Fixnum] y_component The y_component can represent either lightness

or brightness/value (0-1) depending on which scheme (HSV/HSL) is being used.

@param [Fixnum] chroma The associated chroma value. @return [Array<Fixnum>] A scaled r,g,b triple. Scheme-dependent

adjustments are still needed to reach the true r,g,b values.

@see en.wikipedia.org/wiki/HSL_and_HSV @private

    # File lib/chunky_png/color.rb
252 def cylindrical_to_cubic(hue, saturation, y_component, chroma)
253   hue_prime = hue.fdiv(60)
254   x = chroma * (1 - (hue_prime % 2 - 1).abs)
255 
256   case hue_prime
257   when (0...1) then [chroma, x, 0]
258   when (1...2) then [x, chroma, 0]
259   when (2...3) then [0, chroma, x]
260   when (3...4) then [0, x, chroma]
261   when (4...5) then [x, 0, chroma]
262   when (5..6)  then [chroma, 0, x]
263   end
264 end
hue_and_chroma(color) click to toggle source

This method encapsulates the logic needed to extract hue and chroma from a ChunkPNG color. This logic is shared by the cylindrical HSV/HSB and HSL color space models.

@param [Integer] color A ChunkyPNG color. @return [Fixnum] hue The hue of the color (0-360) @return [Fixnum] chroma The chroma of the color (0-1) @return [Fixnum] max The magnitude of the largest scaled rgb component (0-1) @return [Fixnum] min The magnitude of the smallest scaled rgb component (0-1) @private

    # File lib/chunky_png/color.rb
643 def hue_and_chroma(color)
644   scaled_rgb = to_truecolor_bytes(color)
645   scaled_rgb.map! { |component| component.fdiv(255) }
646   min, max = scaled_rgb.minmax
647   chroma   = max - min
648 
649   r, g, b   = scaled_rgb
650   hue_prime = chroma.zero? ? 0 : case max
651                                  when r then (g - b).fdiv(chroma)
652                                  when g then (b - r).fdiv(chroma) + 2
653                                  when b then (r - g).fdiv(chroma) + 4
654                                  else 0
655                                  end
656   hue = 60 * hue_prime
657 
658   [hue.round, chroma, max, min]
659 end