Module: ChunkyPNG::Color

Extended by:
Color
Included in:
Color
Defined in:
lib/chunky_png/color.rb

Overview

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 Fixnum.

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

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.

Constant Summary collapse

MAX =

The maximum value of each color component.

0xff
BLACK =

Black pixel/color

rgb(  0,   0,   0)
WHITE =

White pixel/color

rgb(255, 255, 255)
TRANSPARENT =

Fully transparent pixel/color

rgba(255, 255, 255, 0)

Instance Method Summary collapse

Instance Method Details

#a(value) ⇒ Fixnum

Returns the alpha channel value for the color value.

Parameters:

  • value (Fixnum)

    The color value.

Returns:

  • (Fixnum)

    A value between 0 and MAX.



121
122
123
# File 'lib/chunky_png/color.rb', line 121

def a(value)
  value & 0x000000ff
end

#b(value) ⇒ Fixnum

Returns the blue-component from the color value.

Parameters:

  • value (Fixnum)

    The color value.

Returns:

  • (Fixnum)

    A value between 0 and MAX.



113
114
115
# File 'lib/chunky_png/color.rb', line 113

def b(value)
  (value & 0x0000ff00) >> 8
end

#blend(fg, bg) ⇒ Fixnum

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

Parameters:

  • fg (Fixnum)

    The foreground color.

  • bg (Fixnum)

    The foreground color.

Returns:

  • (Fixnum)

    The blended color.



221
222
223
# File 'lib/chunky_png/color.rb', line 221

def blend(fg, bg)
  (fg + bg) >> 1
end

#bytesize(color_mode) ⇒ Fixnum

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

Parameters:

  • color_mode (Fixnum)

    The color mode in which the pixels are stored.

Returns:

  • (Fixnum)

    The number of bytes used per pixel in a datastream.



296
297
298
299
300
301
302
303
304
305
# File 'lib/chunky_png/color.rb', line 296

def bytesize(color_mode)
  case color_mode
    when ChunkyPNG::COLOR_INDEXED         then 1
    when ChunkyPNG::COLOR_TRUECOLOR       then 3
    when ChunkyPNG::COLOR_TRUECOLOR_ALPHA then 4
    when ChunkyPNG::COLOR_GRAYSCALE       then 1
    when ChunkyPNG::COLOR_GRAYSCALE_ALPHA then 2
    else raise "Don't know the bytesize of pixels in this colormode: #{color_mode}!"
  end
end

#compose_precise(fg, bg) ⇒ Fixnum

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.

Parameters:

  • fg (Fixnum)

    The foreground color.

  • bg (Fixnum)

    The foreground color.

Returns:

  • (Fixnum)

    The composited color.

See Also:



198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/chunky_png/color.rb', line 198

def compose_precise(fg, bg)
  return fg if opaque?(fg)
  return bg if fully_transparent?(fg)
  
  fg_a  = a(fg).to_f / MAX
  bg_a  = a(bg).to_f / MAX
  a_com = (1.0 - fg_a) * bg_a

  new_r = (fg_a * r(fg) + a_com * r(bg)).round
  new_g = (fg_a * g(fg) + a_com * g(bg)).round
  new_b = (fg_a * b(fg) + a_com * b(bg)).round
  new_a = ((fg_a + a_com) * MAX).round
  rgba(new_r, new_g, new_b, new_a)
end

#compose_quick(fg, bg) ⇒ Fixnum Also known as: compose

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.

Parameters:

  • fg (Fixnum)

    The foreground color.

  • bg (Fixnum)

    The foreground color.

Returns:

  • (Fixnum)

    The composited color.

See Also:



176
177
178
179
180
181
182
183
184
185
186
# File 'lib/chunky_png/color.rb', line 176

def compose_quick(fg, bg)
  return fg if opaque?(fg)
  return bg if fully_transparent?(fg)
  
  a_com = int8_mult(0xff - a(fg), a(bg))
  new_r = int8_mult(a(fg), r(fg)) + int8_mult(a_com, r(bg))
  new_g = int8_mult(a(fg), g(fg)) + int8_mult(a_com, g(bg))
  new_b = int8_mult(a(fg), b(fg)) + int8_mult(a_com, b(bg))
  new_a = a(fg) + a_com
  rgba(new_r, new_g, new_b, new_a)
end

#from_hex(str) ⇒ Object

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

It supports colors with (#rrggbbaa) or without (#rrggbb) alpha channel. Color strings may include the prefix “0x” or “#”.

converted color value.

Parameters:

  • str (String)

    The color in hex notation. @return [Fixnum] The



81
82
83
84
85
86
87
# File 'lib/chunky_png/color.rb', line 81

def from_hex(str)
  case str
    when /^(?:#|0x)?([0-9a-f]{6})$/i then ($1.hex << 8) | 0xff
    when /^(?:#|0x)?([0-9a-f]{8})$/i then $1.hex
    else raise "Not a valid hex color notation: #{str.inspect}!"
  end
end

#from_rgb_stream(stream, pos = 0) ⇒ Fixnum

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

Parameters:

  • stream (String)

    The string to load the color from. It should be at least 3 + pos bytes long.

  • pos (Fixnum) (defaults to: 0)

    The position in the string to load the triple from.

Returns:

  • (Fixnum)

    The newly constructed color value.



60
61
62
# File 'lib/chunky_png/color.rb', line 60

def from_rgb_stream(stream, pos = 0)
  rgb(*stream.unpack("@#{pos}C3"))
end

#from_rgba_stream(stream, pos = 0) ⇒ Fixnum

Creates a color by unpacking an rgba triple from a string

Parameters:

  • stream (String)

    The string to load the color from. It should be at least 4 + pos bytes long.

  • pos (Fixnum) (defaults to: 0)

    The position in the string to load the triple from.

Returns:

  • (Fixnum)

    The newly constructed color value.



70
71
72
# File 'lib/chunky_png/color.rb', line 70

def from_rgba_stream(stream, pos = 0)
  rgba(*stream.unpack("@#{pos}C4"))
end

#fully_transparent?(value) ⇒ true, false

Returns true if this color is fully transparent.

Parameters:

  • value (Fixnum)

    The color to test.

Returns:

  • (true, false)

    True if the alpha channel equals 0.



145
146
147
# File 'lib/chunky_png/color.rb', line 145

def fully_transparent?(value)
  a(value) == 0x00000000
end

#g(value) ⇒ Fixnum

Returns the green-component from the color value.

Parameters:

  • value (Fixnum)

    The color value.

Returns:

  • (Fixnum)

    A value between 0 and MAX.



105
106
107
# File 'lib/chunky_png/color.rb', line 105

def g(value)
  (value & 0x00ff0000) >> 16
end

#grayscale(teint, a = MAX) ⇒ ChunkyPNG::Color

Creates a new color using a grayscale teint.

Returns:



40
41
42
# File 'lib/chunky_png/color.rb', line 40

def grayscale(teint, a = MAX)
  rgba(teint, teint, teint, a)
end

#grayscale?(value) ⇒ true, false

Returns true if this color is fully transparent.

Parameters:

  • value (Fixnum)

    The color to test.

Returns:

  • (true, false)

    True if the r, g and b component are equal.



137
138
139
# File 'lib/chunky_png/color.rb', line 137

def grayscale?(value)
  r(value) == b(value) && b(value) == g(value)
end

#grayscale_alpha(teint, a) ⇒ Fixnum

Creates a new color using a grayscale teint and alpha value.

Returns:

  • (Fixnum)

    The newly constructed color value.



46
47
48
# File 'lib/chunky_png/color.rb', line 46

def grayscale_alpha(teint, a)
  rgba(teint, teint, teint, a)
end

#int8_mult(a, b) ⇒ Fixnum

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.

Parameters:

  • a (Fixnum)

    The first fraction.

  • b (Fixnum)

    The second fraction.

Returns:

  • (Fixnum)

    The result of the multiplication.



162
163
164
165
# File 'lib/chunky_png/color.rb', line 162

def int8_mult(a, b)
  t = a * b + 0x80
  ((t >> 8) + t) >> 8
end

#opaque?(value) ⇒ true, false

Returns true if this color is fully opaque.

Parameters:

  • value (Fixnum)

    The color to test.

Returns:

  • (true, false)

    True if the alpha channel equals MAX.



129
130
131
# File 'lib/chunky_png/color.rb', line 129

def opaque?(value)
  a(value) == 0x000000ff
end

#r(value) ⇒ Fixnum

Returns the red-component from the color value.

Parameters:

  • value (Fixnum)

    The color value.

Returns:

  • (Fixnum)

    A value between 0 and MAX.



97
98
99
# File 'lib/chunky_png/color.rb', line 97

def r(value)
  (value & 0xff000000) >> 24
end

#rgb(r, g, b, a = MAX) ⇒ Fixnum

Creates a new color using an r, g, b triple.

Returns:

  • (Fixnum)

    The newly constructed color value.



34
35
36
# File 'lib/chunky_png/color.rb', line 34

def rgb(r, g, b, a = MAX)
  rgba(r, g, b, a)
end

#rgba(r, g, b, a) ⇒ Fixnum

Creates a new color using an r, g, b triple and an alpha value.

Returns:

  • (Fixnum)

    The newly constructed color value.



28
29
30
# File 'lib/chunky_png/color.rb', line 28

def rgba(r, g, b, a)
  r << 24 | g << 16 | b << 8 | a
end

#to_grayscale_alpha_bytes(color) ⇒ Array<Fixnum>

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

This method expects the r,g and b value to be equal.

Parameters:

  • color (Fixnum)

    The grayscale color to convert.

Returns:

  • (Array<Fixnum>)

    An array with 2 Fixnum elements.



272
273
274
# File 'lib/chunky_png/color.rb', line 272

def to_grayscale_alpha_bytes(color)
  [r(color), a(color)] # assumption r == g == b
end

#to_grayscale_bytes(color) ⇒ Array<Fixnum>

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.

Parameters:

  • color (Fixnum)

    The grayscale color to convert.

Returns:

  • (Array<Fixnum>)

    An array with 1 Fixnum element.



261
262
263
# File 'lib/chunky_png/color.rb', line 261

def to_grayscale_bytes(color)
  [r(color)] # assumption r == g == b
end

#to_hex(color, include_alpha = true) ⇒ String

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

Parameters:

  • value (Fixnum)

    The color to convert.

Returns:

  • (String)

    The color in hex notation, starting with a pound sign.



233
234
235
# File 'lib/chunky_png/color.rb', line 233

def to_hex(color, include_alpha = true)
  include_alpha ? ('#%08x' % color) : ('#%06x' % [color >> 8])
end

#to_truecolor_alpha_bytes(color) ⇒ Array<Fixnum>

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

Parameters:

  • color (Fixnum)

    The color to convert.

Returns:

  • (Array<Fixnum>)

    An array with 4 Fixnum elements.



241
242
243
# File 'lib/chunky_png/color.rb', line 241

def to_truecolor_alpha_bytes(color)
  [r(color), g(color), b(color), a(color)]
end

#to_truecolor_bytes(color) ⇒ Array<Fixnum>

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

Parameters:

  • color (Fixnum)

    The color to convert.

Returns:

  • (Array<Fixnum>)

    An array with 3 Fixnum elements.



250
251
252
# File 'lib/chunky_png/color.rb', line 250

def to_truecolor_bytes(color)
  [r(color), g(color), b(color)]
end