module HexaPDF::Content::ColorSpace

def self.device_color_from_specification(*spec)

canvas.line(185, 10, 185, 190).stroke
canvas.stroke_color(cs.device_color_from_specification([0, 128, 255]))
canvas.line(160, 10, 160, 190).stroke
canvas.stroke_color(cs.device_color_from_specification(10, 50, 0, 60))
canvas.line(135, 10, 135, 190).stroke
canvas.stroke_color(cs.device_color_from_specification("hp-blue"))
canvas.line(110, 10, 110, 190).stroke
canvas.stroke_color(cs.device_color_from_specification("gold"))
canvas.line(85, 10, 85, 190).stroke
canvas.stroke_color(cs.device_color_from_specification("08F"))
canvas.line(60, 10, 60, 190).stroke
canvas.stroke_color(cs.device_color_from_specification("0088FF"))
canvas.line(35, 10, 35, 190).stroke
canvas.stroke_color(cs.device_color_from_specification(0, 128, 255))
canvas.line(10, 10, 10, 190).stroke
canvas.stroke_color(cs.device_color_from_specification(160))
# explicitly using it like in this example is not needed
# Note that Canvas#stroke_color implicitly uses this method, so

canvas.line_width(5)
cs = HexaPDF::Content::ColorSpace
#>pdf

Examples:

DeviceGray#color, DeviceRGB#color and DeviceCMYK#color for details.
values are first normalized (expected range by the PDF specification is 0.0 - 1.0) - see
Note that it makes a difference whether integer or float values are used because the given

* An array is treated as if its items were specified separately as arguments.
* Four numeric arguments specify a CMYK color (see DeviceCMYK::Color).
color names are supported - see COLOR_NAMES).
* Any other string is treated as a color name (CSS Color Module Level 3 and HexaPDF design
hexadecimal numbers for the red, green and blue color values of an RGB color.
* As does a string in the format "RGB" where "RR", "GG" and "BB" would be used as the
for the green and "BB" for the blue color value also specifies an RGB color.
* A string in the format "RRGGBB" where "RR" is the hexadecimal number for the red, "GG"
* Three numeric arguments specify an RGB color (see DeviceRGB::Color).
* A single numeric argument specifies a gray color (see DeviceGray::Color).

There are several ways to define the color that should be used:

Creates and returns a device color object from the given color specification.

ColorSpace.device_color_from_specification(array) => color
ColorSpace.device_color_from_specification(string) => color
ColorSpace.device_color_from_specification(c, m, y, k) => color
ColorSpace.device_color_from_specification(r, g, b) => color
ColorSpace.device_color_from_specification(gray) => color
:call-seq:
def self.device_color_from_specification(*spec)
  spec.flatten!
  first_item = spec[0]
  if spec.length == 1 && first_item.kind_of?(String)
    spec = if first_item.match?(/\A\h{6}\z/)
             first_item.scan(/../).map!(&:hex)
           elsif first_item.match?(/\A\h{3}\z/)
             first_item.each_char.map {|x| (x * 2).hex }
           elsif COLOR_NAMES.key?(first_item)
             COLOR_NAMES[first_item]
           else
             raise ArgumentError, "Given string '#{first_item}' is neither a hex color " \
               "nor a color name"
           end
  end
  GlobalConfiguration.constantize('color_space.map', for_components(spec)).new.color(*spec)
end

def self.for_components(components)

from the components array.
Returns the name of the device color space that should be used for creating a color object
def self.for_components(components)
  case components.length
  when 1 then :DeviceGray
  when 3 then :DeviceRGB
  when 4 then :DeviceCMYK
  else
    raise ArgumentError, "Invalid number of color components, 1|3|4 expected, " \
      "#{components.length} given"
  end
end

def self.prenormalized_device_color(components)

normalization.
Returns a device color object for the given components array without applying value
def self.prenormalized_device_color(components)
  GlobalConfiguration.constantize('color_space.map', for_components(components)).new.
    prenormalized_color(*components)
end

def self.serialize_device_color(color, type: :fill)

fill color operator.
The +type+ argument can either be :stroke to serialize as stroke color operator or :fill as

Serializes the given device color into the form expected by PDF content streams.
def self.serialize_device_color(color, type: :fill)
  operator = case color.color_space.family
             when :DeviceRGB then :rg
             when :DeviceGray then :g
             when :DeviceCMYK then :k
             else
               raise ArgumentError, "Device color object expected, got #{color.class}"
             end
  operator = operator.upcase if type == :stroke
  Content::Operator::DEFAULT_OPERATORS[operator].
    serialize(HexaPDF::Serializer.new, *color.components)
end