Class: ChunkyPNG::Palette

Inherits:
SortedSet
  • Object
show all
Defined in:
lib/chunky_png/palette.rb

Overview

A palette describes the set of colors that is being used for an image.

A PNG image can contain an explicit palette which defines the colors of that image, but can also use an implicit palette, e.g. all truecolor colors or all grayscale colors.

This palette supports decoding colors from a palette if an explicit palette is provided in a PNG datastream, and it supports encoding colors to an explicit palette (stores as PLTE & tRNS chunks in a PNG file).

See Also:

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Palette) initialize(enum, decoding_map = nil)

Builds a new palette given a set (Enumerable instance) of colors.

Parameters:

  • enum (Enumerable<Integer>)

    The set of colors to include in this palette.This Enumerable can contain duplicates.

  • decoding_map (Array) (defaults to: nil)

    An array of colors in the exact order at which they appeared in the palette chunk, so that this array can be used for decoding.



23
24
25
26
# File 'lib/chunky_png/palette.rb', line 23

def initialize(enum, decoding_map = nil)
  super(enum)
  @decoding_map = decoding_map if decoding_map
end

Class Method Details

+ (ChunkyPNG::Palette) from_canvas(canvas)

Builds a palette instance from a given canvas.

Parameters:

Returns:



65
66
67
# File 'lib/chunky_png/palette.rb', line 65

def self.from_canvas(canvas)
  self.new(canvas.pixels)
end

+ (ChunkyPNG::Palette) from_chunks(palette_chunk, transparency_chunk = nil)

Builds a palette instance from a PLTE chunk and optionally a tRNS chunk from a PNG datastream.

This method will cerate a palette that is suitable for decoding an image.

Parameters:

Returns:

See Also:



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/chunky_png/palette.rb', line 39

def self.from_chunks(palette_chunk, transparency_chunk = nil)
  return nil if palette_chunk.nil?

  decoding_map = []
  index = 0

  palatte_bytes = palette_chunk.content.unpack('C*')
  if transparency_chunk
    alpha_channel = transparency_chunk.content.unpack('C*')
  else
    alpha_channel = []
  end

  index = 0
  palatte_bytes.each_slice(3) do |bytes|
    bytes << alpha_channel.fetch(index, ChunkyPNG::Color::MAX)
    decoding_map << ChunkyPNG::Color.rgba(*bytes)
    index += 1
  end

  self.new(decoding_map, decoding_map)
end

+ (ChunkyPNG::Palette) from_pixels(pixels)

Builds a palette instance from a given set of pixels.

Parameters:

  • pixels (Enumerable<Integer>)

    An enumeration of pixels to create a palette for

Returns:



73
74
75
# File 'lib/chunky_png/palette.rb', line 73

def self.from_pixels(pixels)
  self.new(pixels)
end

Instance Method Details

- (ChunkyPNG::Color) [](index)

Returns a color, given the position in the original palette chunk.

Parameters:

  • index (Integer)

    The 0-based position of the color in the palette.

Returns:

  • (ChunkyPNG::Color)

    The color that is stored in the palette under the given index

See Also:



147
148
149
# File 'lib/chunky_png/palette.rb', line 147

def [](index)
  @decoding_map[index]
end

- (Integer) best_color_settings

Determines the most suitable colormode for this palette.

Returns:

  • (Integer)

    The colormode which would create the smallest possible file for images that use this exact palette.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/chunky_png/palette.rb', line 194

def best_color_settings
  if black_and_white?
    [ChunkyPNG::COLOR_GRAYSCALE, 1]
  elsif grayscale?
    if opaque?
      [ChunkyPNG::COLOR_GRAYSCALE, 8]
    else
      [ChunkyPNG::COLOR_GRAYSCALE_ALPHA, 8]
    end
  elsif indexable?
    [ChunkyPNG::COLOR_INDEXED, determine_bit_depth]
  elsif opaque?
    [ChunkyPNG::COLOR_TRUECOLOR, 8]
  else
    [ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8]
  end
end

- (true, false) black_and_white?

Check whether this palette only contains bacl and white.

Returns:

  • (true, false)

    True if all colors in this palette are grayscale teints.

See Also:

  • Color#grayscale??


103
104
105
# File 'lib/chunky_png/palette.rb', line 103

def black_and_white?
  entries == [ChunkyPNG::Color::BLACK, ChunkyPNG::Color::WHITE]
end

- (true, false) can_decode?

Checks whether this palette is suitable for decoding an image from a datastream.

This requires that the positions of the colors in the original palette chunk is known, which is stored as an array in the @decoding_map instance variable.

Returns:

  • (true, false)

    True if a decoding map was built when this palette was loaded.



125
126
127
# File 'lib/chunky_png/palette.rb', line 125

def can_decode?
  !@decoding_map.nil?
end

- (true, false) can_encode?

Checks whether this palette is suitable for encoding an image from to datastream.

This requires that the position of the color in the future palette chunk is known, which is stored as a hash in the @encoding_map instance variable.

Returns:

  • (true, false)

    True if a encoding map was built when this palette was loaded.



138
139
140
# File 'lib/chunky_png/palette.rb', line 138

def can_encode?
  !@encoding_map.nil?
end

- (Integer) determine_bit_depth

Determines the minimal bit depth required for an indexed image

Returns:

  • (Integer)

    Number of bits per pixel, i.e. 1, 2, 4 or 8, or nil if this image cannot be saved as an indexed image.



215
216
217
218
219
220
221
222
223
# File 'lib/chunky_png/palette.rb', line 215

def determine_bit_depth
  case size
    when 1..2; 1
    when 3..4; 2
    when 5..16; 4
    when 17..256; 8
    else nil
  end
end

- (true, false) grayscale?

Check whether this palette only contains grayscale colors.

Returns:

  • (true, false)

    True if all colors in this palette are grayscale teints.

See Also:

  • Color#grayscale??


95
96
97
# File 'lib/chunky_png/palette.rb', line 95

def grayscale?
  all? { |color| Color.grayscale?(color) }
end

- (Integer) index(color)

Returns the position of a color in the palette

Parameters:

Returns:

  • (Integer)

    The 0-based position of the color in the palette.

See Also:



155
156
157
# File 'lib/chunky_png/palette.rb', line 155

def index(color)
  color.nil? ? 0 : @encoding_map[color]
end

- (true, false) indexable?

Checks whether the size of this palette is suitable for indexed storage.

Returns:

  • (true, false)

    True if the number of colors in this palette is at most 256.



80
81
82
# File 'lib/chunky_png/palette.rb', line 80

def indexable?
  size <= 256
end

- (true, false) opaque?

Check whether this palette only contains opaque colors.

Returns:

  • (true, false)

    True if all colors in this palette are opaque.

See Also:



87
88
89
# File 'lib/chunky_png/palette.rb', line 87

def opaque?
  all? { |color| Color.opaque?(color) }
end

- (ChunkyPNG::Palette) opaque_palette

Returns a palette with all the opaque variants of the colors in this palette.

Returns:

See Also:



112
113
114
# File 'lib/chunky_png/palette.rb', line 112

def opaque_palette
  self.class.new(map { |c| ChunkyPNG::Color.opaque!(c) })
end

- (ChunkyPNG::Chunk::Palette) to_plte_chunk

Note:

A PLTE chunk should only be included if the image is encoded using index colors. After this chunk has been built, the palette becomes suitable for encoding an image.

Creates a PLTE chunk that corresponds with this palette to store the r, g, and b channels of all colors.

Returns:

See Also:



179
180
181
182
183
184
185
186
187
188
189
# File 'lib/chunky_png/palette.rb', line 179

def to_plte_chunk
  @encoding_map = {}
  colors        = []

  each_with_index do |color, index|
    @encoding_map[color] = index
    colors += ChunkyPNG::Color.to_truecolor_bytes(color)
  end

  ChunkyPNG::Chunk::Palette.new('PLTE', colors.pack('C*'))
end

- (ChunkyPNG::Chunk::Transparency) to_trns_chunk

Creates a tRNS chunk that corresponds with this palette to store the alpha channel of all colors.

Note that this chunk can be left out of every color in the palette is opaque, and the image is encoded using indexed colors.

Returns:



166
167
168
# File 'lib/chunky_png/palette.rb', line 166

def to_trns_chunk
  ChunkyPNG::Chunk::Transparency.new('tRNS', map { |c| ChunkyPNG::Color.a(c) }.pack('C*'))
end