Class ChunkyPNG::Palette
In: lib/chunky_png/palette.rb
Parent: SortedSet

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 ChunkyPNG::Color

Methods

Public Class methods

Builds a palette instance from a given canvas. @param [ChunkyPNG::Canvas] canvas The canvas to create a palette for. @return [ChunkyPNG::Palette] The palette instance.

[Source]

    # File lib/chunky_png/palette.rb, line 62
62:     def self.from_canvas(canvas)
63:       self.new(canvas.pixels)
64:     end

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.

@param [ChunkyPNG::Chunk::Palette] The palette chunk to load from @param [ChunkyPNG::Chunk::Transparency, nil] The optional transparency chunk. @return [ChunkyPNG::Palette] The loaded palette instance. @see ChunkyPNG::Palette#can_decode?

[Source]

    # File lib/chunky_png/palette.rb, line 36
36:     def self.from_chunks(palette_chunk, transparency_chunk = nil)
37:       return nil if palette_chunk.nil?
38: 
39:       decoding_map = []
40:       index = 0
41: 
42:       palatte_bytes = palette_chunk.content.unpack('C*')
43:       if transparency_chunk
44:         alpha_channel = transparency_chunk.content.unpack('C*')
45:       else
46:         alpha_channel = []
47:       end
48: 
49:       index = 0
50:       palatte_bytes.each_slice(3) do |bytes|
51:         bytes << alpha_channel.fetch(index, ChunkyPNG::Color::MAX)
52:         decoding_map << ChunkyPNG::Color.rgba(*bytes)
53:         index += 1
54:       end
55: 
56:       self.new(decoding_map, decoding_map)
57:     end

Builds a palette instance from a given set of pixels. @param [Enumerable<Integer>] pixels An enumeration of pixels to create a palette for @return [ChunkyPNG::Palette] The palette instance.

[Source]

    # File lib/chunky_png/palette.rb, line 69
69:     def self.from_pixels(pixels)
70:       self.new(pixels)
71:     end

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

@param [Enumerable<Integer>] enum The set of colors to include in this palette.

  This Enumerable can contains duplicates.

@param [Array] decoding_map 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.

[Source]

    # File lib/chunky_png/palette.rb, line 22
22:     def initialize(enum, decoding_map = nil)
23:       super(enum)
24:       @decoding_map = decoding_map if decoding_map
25:     end

Public Instance methods

Returns a color, given the position in the original palette chunk. @param [Integer] index The 0-based position of the color in the palette. @return [ChunkyPNG::Color] The color that is stored in the palette under the given index @see ChunkyPNG::Palette#can_decode?

[Source]

     # File lib/chunky_png/palette.rb, line 131
131:     def [](index)
132:       @decoding_map[index]
133:     end

Determines the most suitable colormode for this palette. @return [Integer] The colormode which would create the smallest possible

   file for images that use this exact palette.

[Source]

     # File lib/chunky_png/palette.rb, line 178
178:     def best_color_settings
179:       if black_and_white?
180:         [ChunkyPNG::COLOR_GRAYSCALE, 1]
181:       elsif grayscale?
182:         if opaque?
183:           [ChunkyPNG::COLOR_GRAYSCALE, 8]
184:         else
185:           [ChunkyPNG::COLOR_GRAYSCALE_ALPHA, 8]
186:         end
187:       elsif indexable?
188:         [ChunkyPNG::COLOR_INDEXED, determine_bit_depth]
189:       elsif opaque?
190:         [ChunkyPNG::COLOR_TRUECOLOR, 8]
191:       else
192:         [ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8]
193:       end
194:     end

Check whether this palette only contains bacl and white. @return [true, false] True if all colors in this palette are grayscale teints. @see ChunkyPNG::Color#grayscale??

[Source]

    # File lib/chunky_png/palette.rb, line 96
96:     def black_and_white?
97:       entries == [ChunkyPNG::Color::BLACK, ChunkyPNG::Color::WHITE]
98:     end

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.

@return [true, false] True if a decoding map was built when this palette was loaded.

[Source]

     # File lib/chunky_png/palette.rb, line 113
113:     def can_decode?
114:       !@decoding_map.nil?
115:     end

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.

@return [true, false] True if a encoding map was built when this palette was loaded.

[Source]

     # File lib/chunky_png/palette.rb, line 123
123:     def can_encode?
124:       !@encoding_map.nil?
125:     end

Determines the minimal bit depth required for an indexed image @return [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.

[Source]

     # File lib/chunky_png/palette.rb, line 199
199:     def determine_bit_depth
200:       case size
201:         when 1..2; 1
202:         when 3..4; 2
203:         when 5..16; 4
204:         when 17..256; 8
205:         else nil
206:       end
207:     end

Check whether this palette only contains grayscale colors. @return [true, false] True if all colors in this palette are grayscale teints. @see ChunkyPNG::Color#grayscale??

[Source]

    # File lib/chunky_png/palette.rb, line 89
89:     def grayscale?
90:       all? { |color| Color.grayscale?(color) }
91:     end

Returns the position of a color in the palette @param [ChunkyPNG::Color] color The color for which to look up the index. @return [Integer] The 0-based position of the color in the palette. @see ChunkyPNG::Palette#can_encode?

[Source]

     # File lib/chunky_png/palette.rb, line 139
139:     def index(color)
140:       color.nil? ? 0 : @encoding_map[color]
141:     end

Checks whether the size of this palette is suitable for indexed storage. @return [true, false] True if the number of colors in this palette is at most 256.

[Source]

    # File lib/chunky_png/palette.rb, line 75
75:     def indexable?
76:       size <= 256
77:     end

Check whether this palette only contains opaque colors. @return [true, false] True if all colors in this palette are opaque. @see ChunkyPNG::Color#opaque?

[Source]

    # File lib/chunky_png/palette.rb, line 82
82:     def opaque?
83:       all? { |color| Color.opaque?(color) }
84:     end

Returns a palette with all the opaque variants of the colors in this palette. @return [ChunkyPNG::Palette] A new Palette instance with only opaque colors. @see ChunkyPNG::Color#opaque!

[Source]

     # File lib/chunky_png/palette.rb, line 103
103:     def opaque_palette
104:       self.class.new(map { |c| ChunkyPNG::Color.opaque!(c) })
105:     end

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

Note that 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.

@return [ChunkyPNG::Chunk::Palette] The PLTE chunk. @see ChunkyPNG::Palette#can_encode?

[Source]

     # File lib/chunky_png/palette.rb, line 163
163:     def to_plte_chunk
164:       @encoding_map = {}
165:       colors        = []
166: 
167:       each_with_index do |color, index|
168:         @encoding_map[color] = index
169:         colors += ChunkyPNG::Color.to_truecolor_bytes(color)
170:       end
171: 
172:       ChunkyPNG::Chunk::Palette.new('PLTE', colors.pack('C*'))
173:     end

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.

@return [ChunkyPNG::Chunk::Transparency] The tRNS chunk.

[Source]

     # File lib/chunky_png/palette.rb, line 150
150:     def to_trns_chunk
151:       ChunkyPNG::Chunk::Transparency.new('tRNS', map { |c| ChunkyPNG::Color.a(c) }.pack('C*'))
152:     end

[Validate]