This file is indexed.

/usr/lib/ruby/vendor_ruby/chunky_png/palette.rb is in ruby-chunky-png 1.2.8-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
module ChunkyPNG

  # 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
  class Palette < SortedSet

    # 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.
    def initialize(enum, decoding_map = nil)
      super(enum)
      @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

      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

    # 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.
    def self.from_canvas(canvas)
      self.new(canvas.pixels)
    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.
    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 at most 256.
    def indexable?
      size <= 256
    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?
    def opaque?
      all? { |color| Color.opaque?(color) }
    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??
    def grayscale?
      all? { |color| Color.grayscale?(color) }
    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??
    def black_and_white?
      entries == [ChunkyPNG::Color::BLACK, ChunkyPNG::Color::WHITE]
    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!
    def opaque_palette
      self.class.new(map { |c| ChunkyPNG::Color.opaque!(c) })
    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 [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?
    def [](index)
      @decoding_map[index]
    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?
    def index(color)
      color.nil? ? 0 : @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 { |c| ChunkyPNG::Color.a(c) }.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|
        @encoding_map[color] = index
        colors += ChunkyPNG::Color.to_truecolor_bytes(color)
      end

      ChunkyPNG::Chunk::Palette.new('PLTE', colors.pack('C*'))
    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.
    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
    
    # 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.
    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
  end
end