lib/chunky_png/palette.rb in chunky_png-0.0.2 vs lib/chunky_png/palette.rb in chunky_png-0.0.3

- old
+ new

@@ -1,18 +1,38 @@ module ChunkyPNG - - ########################################### - # PALETTE CLASS - ########################################### - + + # 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 matrix. + # + # @see ChunkyPNG::Pixel class Palette < SortedSet - def initialize(enum) + # Builds a new palette given a set (Enumerable instance) of colors. + # + # @param [Enumerbale<ChunkyPNG::Pixel>] enum The set of colors to include in this palette. + # This Enumerbale 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. + def initialize(enum, decoding_map = nil) super(enum) - @decoding_map = enum if enum.kind_of?(Array) + @decoding_map = decoding_map if decoding_map 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? def self.from_chunks(palette_chunk, transparency_chunk = nil) return nil if palette_chunk.nil? decoding_map = [] index = 0 @@ -29,49 +49,103 @@ bytes << alpha_channel[index] decoding_map << ChunkyPNG::Pixel.rgba(*bytes) index += 1 end - self.new(decoding_map) + self.new(decoding_map, decoding_map) end + # Builds a palette instance from a given pixel matrix. + # @param [ChunkyPNG::PixelMatrix] pixel_matrix The pixel matrix to create a palette for. + # @return [ChunkyPNG::Palette] The palette instance. def self.from_pixel_matrix(pixel_matrix) self.new(pixel_matrix.pixels) end + # Builds a palette instance from a given set of pixels. + # @param [Enumerable<ChunkyPNG::Pixel>] pixels An enumeration of pixels to create a palette for + # @return [ChunkyPNG::Palette] The palette instance. def self.from_pixels(pixels) self.new(pixels) 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 less than 256. def indexable? size < 256 end + # Check whether this pelette only contains opaque colors. + # @return [true, false] True if all colors in this palette are opaque. + # @see ChunkyPNG::Pixel#opaque? def opaque? all? { |pixel| pixel.opaque? } end + + # Check whether this pelette only contains grayscale colors. + # @return [true, false] True if all colors in this palette are grayscale teints. + # @see ChunkyPNG::Pixel#grayscale?? + def grayscale? + all? { |pixel| pixel.grayscale? } + 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. def can_decode? !@decoding_map.nil? 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. def can_encode? !@encoding_map.nil? end + # Returns a color, given the position in the original palette chunk. + # @param [Fixnum] index The 0-based position of the color in the palette. + # @return [ChunkyPNG::Pixel] The color that is stored in the palette under the given index + # @see ChunkyPNG::Palette#can_decode? def [](index) @decoding_map[index] end + # Returns the position of a color in the palette + # @param [ChunkyPNG::Pixel] color The color for which to look up the index. + # @return [Fixnum] The 0-based position of the color in the palette. + # @see ChunkyPNG::Palette#can_encode? def index(color) @encoding_map[color] 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. def to_trns_chunk ChunkyPNG::Chunk::Transparency.new('tRNS', map(&:a).pack('C*')) 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? def to_plte_chunk @encoding_map = {} colors = [] each_with_index do |color, index| @@ -80,16 +154,25 @@ end ChunkyPNG::Chunk::Palette.new('PLTE', colors.pack('C*')) end + # Determines the most suitable colormode for this palette. + # @return [Fixnum] The colormode which would create the smalles possible + # file for images that use this exact palette. def best_colormode - if indexable? - ChunkyPNG::Chunk::Header::COLOR_INDEXED + if grayscale? + if opaque? + ChunkyPNG::COLOR_GRAYSCALE + else + ChunkyPNG::COLOR_GRAYSCALE_ALPHA + end + elsif indexable? + ChunkyPNG::COLOR_INDEXED elsif opaque? - ChunkyPNG::Chunk::Header::COLOR_TRUECOLOR + ChunkyPNG::COLOR_TRUECOLOR else - ChunkyPNG::Chunk::Header::COLOR_TRUECOLOR_ALPHA + ChunkyPNG::COLOR_TRUECOLOR_ALPHA end end end end