chunky_png 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -51,8 +51,8 @@ module ChunkyPNG
51
51
  # @param [#read, String] stream The stream to read the pixel data from.
52
52
  # @return [ChunkyPNG::Canvas] The newly constructed canvas instance.
53
53
  def from_bgr_stream(width, height, stream)
54
- string = ChunkyPNG::EXTRA_BYTE # Add a first byte to the first BGR triple.
55
- string << stream.respond_to?(:read) ? stream.read(3 * width * height) : stream.to_s[0, 3 * width * height]
54
+ string = ChunkyPNG::EXTRA_BYTE.dup # Add a first byte to the first BGR triple.
55
+ string << (stream.respond_to?(:read) ? stream.read(3 * width * height) : stream.to_s[0, 3 * width * height])
56
56
  pixels = string.unpack("@1" << ('XV' * (width * height))).map { |color| color | 0x000000ff }
57
57
  self.new(width, height, pixels)
58
58
  end
@@ -1,8 +1,7 @@
1
1
  module ChunkyPNG
2
-
3
2
  # A PNG datastream consists of multiple chunks. This module, and the classes
4
- # contained within, help with handling these chunks. It supports both
5
- # reading and writing chunks.
3
+ # contained within, help with handling these chunks. It supports both reading
4
+ # and writing chunks.
6
5
  #
7
6
  # All chunk types are instances of the {ChunkyPNG::Chunk::Base} class. For
8
7
  # some chunk types a specialized class is available, e.g. the IHDR chunk is
@@ -12,13 +11,11 @@ module ChunkyPNG
12
11
  #
13
12
  # @see ChunkyPNG::Datastream
14
13
  module Chunk
15
-
16
14
  # Reads a chunk from an IO stream.
17
15
  #
18
- # @param [IO, #read] io The IO stream to read from.
16
+ # @param io [IO, #read] The IO stream to read from.
19
17
  # @return [ChunkyPNG::Chung::Base] The loaded chunk instance.
20
18
  def self.read(io)
21
-
22
19
  length, type = io.read(8).unpack('Na4')
23
20
  content = io.read(length)
24
21
  crc = io.read(4).unpack('N').first
@@ -27,13 +24,13 @@ module ChunkyPNG
27
24
 
28
25
  CHUNK_TYPES.fetch(type, Generic).read(type, content)
29
26
  end
30
-
27
+
31
28
  # Verifies the CRC of a chunk.
32
- # @param [String] type The chunk's type.
33
- # @param [String] content The chunk's content.
34
- # @param [Integer] content The chunk's content.
35
- # @raise [RuntimeError] An exception is raised if the found CRC value
36
- # is not equal to the expected CRC value.
29
+ # @param type [String] The chunk's type.
30
+ # @param content [String] The chunk's content.
31
+ # @param found_crc [Integer] The chunk's found CRC value.
32
+ # @raise [RuntimeError] An exception is raised if the found CRC value is
33
+ # not equal to the expected CRC value.
37
34
  def self.verify_crc!(type, content, found_crc)
38
35
  expected_crc = Zlib.crc32(content, Zlib.crc32(type))
39
36
  raise ChunkyPNG::CRCMismatch, "Chuck CRC mismatch!" if found_crc != expected_crc
@@ -47,15 +44,14 @@ module ChunkyPNG
47
44
  #
48
45
  # @abstract
49
46
  class Base
50
-
51
47
  # The four-character type indicator for the chunk. This field is used to
52
48
  # find the correct class for a chunk when it is loaded from a PNG stream.
53
49
  # @return [String]
54
50
  attr_accessor :type
55
51
 
56
52
  # Initializes the chunk instance.
57
- # @param [String] type The four character chunk type indicator.
58
- # @param [Hash] attributes A hash of attributes to set on this chunk.
53
+ # @param type [String] The four character chunk type indicator.
54
+ # @param attributes [Hash] A hash of attributes to set on this chunk.
59
55
  def initialize(type, attributes = {})
60
56
  self.type = type
61
57
  attributes.each { |k, v| send("#{k}=", v) }
@@ -63,8 +59,8 @@ module ChunkyPNG
63
59
 
64
60
  # Writes the chunk to the IO stream, using the provided content.
65
61
  # The checksum will be calculated and appended to the stream.
66
- # @param [IO] io The IO stream to write to.
67
- # @param [String] content The content for this chunk.
62
+ # @param io [IO] The IO stream to write to.
63
+ # @param content [String] The content for this chunk.
68
64
  def write_with_crc(io, content)
69
65
  io << [content.length].pack('N') << type << content
70
66
  io << [Zlib.crc32(content, Zlib.crc32(type))].pack('N')
@@ -74,47 +70,44 @@ module ChunkyPNG
74
70
  #
75
71
  # It will call the +content+ method to get the content for this chunk,
76
72
  # and will calculate and append the checksum automatically.
77
- # @param [IO] io The IO stream to write to.
73
+ # @param io [IO] The IO stream to write to.
78
74
  def write(io)
79
75
  write_with_crc(io, content || '')
80
76
  end
81
77
  end
82
78
 
83
- # The Generic chunk type will read the content from the chunk as it,
79
+ # The Generic chunk type will read the content from the chunk as it,
84
80
  # and will write it back as it was read.
85
81
  class Generic < Base
86
-
87
- # The attribute to store the content from the chunk, which gets
82
+ # The attribute to store the content from the chunk, which gets
88
83
  # written by the +write+ method.
89
84
  attr_accessor :content
90
85
 
91
-
92
86
  def initialize(type, content = '')
93
87
  super(type, :content => content)
94
88
  end
95
89
 
96
90
  # Creates an instance, given the chunk's type and content.
97
- # @param [String] type The four character chunk type indicator.
98
- # @param [String] content The content read from the chunk.
91
+ # @param type [String] The four character chunk type indicator.
92
+ # @param content [String] The content read from the chunk.
99
93
  # @return [ChunkyPNG::Chunk::Generic] The new chunk instance.
100
94
  def self.read(type, content)
101
- self.new(type, content)
95
+ new(type, content)
102
96
  end
103
97
  end
104
98
 
105
- # The header (IHDR) chunk is the first chunk of every PNG image, and
106
- # contains information about the image: i.e. its width, height, color
99
+ # The header (IHDR) chunk is the first chunk of every PNG image, and
100
+ # contains information about the image: i.e. its width, height, color
107
101
  # depth, color mode, compression method, filtering method and interlace
108
102
  # method.
109
103
  #
110
- # ChunkyPNG supports all values for these variables that are defined in
111
- # the PNG spec, except for color depth: Only 8-bit depth images are
112
- # supported. Note that it is still possible to access the chunk for such
113
- # an image, but ChunkyPNG will raise an exception if you try to access
114
- # the pixel data.
104
+ # ChunkyPNG supports all values for these variables that are defined in the
105
+ # PNG spec, except for color depth: Only 8-bit depth images are supported.
106
+ # Note that it is still possible to access the chunk for such an image, but
107
+ # ChunkyPNG will raise an exception if you try to access the pixel data.
115
108
  class Header < Base
116
-
117
- attr_accessor :width, :height, :depth, :color, :compression, :filtering, :interlace
109
+ attr_accessor :width, :height, :depth, :color, :compression, :filtering,
110
+ :interlace
118
111
 
119
112
  def initialize(attrs = {})
120
113
  super('IHDR', attrs)
@@ -125,36 +118,45 @@ module ChunkyPNG
125
118
  @interlace ||= ChunkyPNG::INTERLACING_NONE
126
119
  end
127
120
 
128
- # Reads the 13 bytes of content from the header chunk to set the image attributes.
129
- # @param [String] type The four character chunk type indicator (= "IHDR").
130
- # @param [String] content The 13 bytes of content read from the chunk.
131
- # @return [ChunkyPNG::Chunk::End] The new Header chunk instance with the
132
- # variables set to the values according to the content.
121
+ # Reads the 13 bytes of content from the header chunk to set the image
122
+ # attributes.
123
+ # @param type [String] The four character chunk type indicator (= "IHDR").
124
+ # @param content [String] The 13 bytes of content read from the chunk.
125
+ # @return [ChunkyPNG::Chunk::End] The new Header chunk instance with the
126
+ # variables set to the values according to the content.
133
127
  def self.read(type, content)
134
128
  fields = content.unpack('NNC5')
135
- self.new(:width => fields[0], :height => fields[1], :depth => fields[2], :color => fields[3],
136
- :compression => fields[4], :filtering => fields[5], :interlace => fields[6])
129
+ new(:width => fields[0],
130
+ :height => fields[1],
131
+ :depth => fields[2],
132
+ :color => fields[3],
133
+ :compression => fields[4],
134
+ :filtering => fields[5],
135
+ :interlace => fields[6])
137
136
  end
138
137
 
139
- # Returns the content for this chunk when it gets written to a file, by packing the
140
- # image information variables into the correct format.
138
+ # Returns the content for this chunk when it gets written to a file, by
139
+ # packing the image information variables into the correct format.
141
140
  # @return [String] The 13-byte content for the header chunk.
142
141
  def content
143
- [width, height, depth, color, compression, filtering, interlace].pack('NNC5')
142
+ [width, height, depth, color, compression, filtering, interlace].
143
+ pack('NNC5')
144
144
  end
145
145
  end
146
146
 
147
- # The End (IEND) chunk indicates the last chunk of a PNG stream. It does not
148
- # contain any data.
147
+ # The End (IEND) chunk indicates the last chunk of a PNG stream. It does
148
+ # not contain any data.
149
149
  class End < Base
150
-
150
+
151
151
  def initialize
152
152
  super('IEND')
153
153
  end
154
-
154
+
155
155
  # Reads the END chunk. It will check if the content is empty.
156
- # @param [String] type The four character chunk type indicator (= "IEND").
157
- # @param [String] content The content read from the chunk. Should be empty.
156
+ # @param type [String] The four character chunk type indicator (=
157
+ # "IEND").
158
+ # @param content [String] The content read from the chunk. Should be
159
+ # empty.
158
160
  # @return [ChunkyPNG::Chunk::End] The new End chunk instance.
159
161
  # @raise [RuntimeError] Raises an exception if the content was not empty.
160
162
  def self.read(type, content)
@@ -173,46 +175,56 @@ module ChunkyPNG
173
175
  # 8-bit RGB colors this image is using.
174
176
  #
175
177
  # @see ChunkyPNG::Chunk::Transparency
176
- # @see ChunkyPNG::Palette
178
+ # @see ChunkyPNG::Palette
177
179
  class Palette < Generic
178
180
  end
179
181
 
180
182
  # A transparency (tRNS) chunk defines the transparency for an image.
181
183
  #
182
- # * For indexed images, it contains the alpha channel for the colors defined in the Palette (PLTE) chunk.
183
- # * For grayscale images, it contains the grayscale teint that should be considered fully transparent.
184
- # * For truecolor images, it contains the color that should be considered fully transparent.
184
+ # * For indexed images, it contains the alpha channel for the colors
185
+ # defined in the Palette (PLTE) chunk.
186
+ # * For grayscale images, it contains the grayscale teint that should be
187
+ # considered fully transparent.
188
+ # * For truecolor images, it contains the color that should be considered
189
+ # fully transparent.
185
190
  #
186
- # Images having a color mode that already includes an alpha channel, this chunk should not be included.
191
+ # Images having a color mode that already includes an alpha channel, this
192
+ # chunk should not be included.
187
193
  #
188
194
  # @see ChunkyPNG::Chunk::Palette
189
195
  # @see ChunkyPNG::Palette
190
196
  class Transparency < Generic
191
-
192
197
  # Returns the alpha channel for the palette of an indexed image.
193
198
  #
194
- # This method should only be used for images having color mode ChunkyPNG::COLOR_INDEXED (3).
199
+ # This method should only be used for images having color mode
200
+ # ChunkyPNG::COLOR_INDEXED (3).
195
201
  #
196
- # @return [Array<Integer>] Returns an array of alpha channel values [0-255].
202
+ # @return [Array<Integer>] Returns an array of alpha channel values
203
+ # [0-255].
197
204
  def palette_alpha_channel
198
205
  content.unpack('C*')
199
206
  end
200
-
207
+
201
208
  # Returns the truecolor entry to be replaced by transparent pixels,
202
209
  #
203
- # This method should only be used for images having color mode ChunkyPNG::COLOR_TRUECOLOR (2).
210
+ # This method should only be used for images having color mode
211
+ # ChunkyPNG::COLOR_TRUECOLOR (2).
204
212
  #
205
213
  # @return [Integer] The color to replace with fully transparent pixels.
206
214
  def truecolor_entry(bit_depth)
207
- values = content.unpack('nnn').map { |c| ChunkyPNG::Canvas.send(:"decode_png_resample_#{bit_depth}bit_value", c) }
215
+ values = content.unpack('nnn').map do |c|
216
+ ChunkyPNG::Canvas.send(:"decode_png_resample_#{bit_depth}bit_value", c)
217
+ end
208
218
  ChunkyPNG::Color.rgb(*values)
209
219
  end
210
220
 
211
221
  # Returns the grayscale entry to be replaced by transparent pixels.
212
222
  #
213
- # This method should only be used for images having color mode ChunkyPNG::COLOR_GRAYSCALE (0).
223
+ # This method should only be used for images having color mode
224
+ # ChunkyPNG::COLOR_GRAYSCALE (0).
214
225
  #
215
- # @return [Integer] The (grayscale) color to replace with fully transparent pixels.
226
+ # @return [Integer] The (grayscale) color to replace with fully
227
+ # transparent pixels.
216
228
  def grayscale_entry(bit_depth)
217
229
  value = ChunkyPNG::Canvas.send(:"decode_png_resample_#{bit_depth}bit_value", content.unpack('n')[0])
218
230
  ChunkyPNG::Color.grayscale(value)
@@ -220,16 +232,15 @@ module ChunkyPNG
220
232
  end
221
233
 
222
234
  class ImageData < Generic
223
-
224
235
  def self.read(type, content)
225
236
  raise ExpectationFailed, 'The IDAT chunk should not be empty!' if content.bytesize == 0
226
237
  super
227
238
  end
228
-
239
+
229
240
  def self.combine_chunks(data_chunks)
230
241
  Zlib::Inflate.inflate(data_chunks.map { |c| c.content }.join(''))
231
242
  end
232
-
243
+
233
244
  def self.split_in_chunks(data, level = Zlib::DEFAULT_COMPRESSION, chunk_size = 2147483647)
234
245
  streamdata = Zlib::Deflate.deflate(data, level)
235
246
  # TODO: Split long streamdata over multiple chunks
@@ -237,16 +248,15 @@ module ChunkyPNG
237
248
  end
238
249
  end
239
250
 
240
- # The Text (tEXt) chunk contains keyword/value metadata about the PNG stream.
241
- # In this chunk, the value is stored uncompressed.
251
+ # The Text (tEXt) chunk contains keyword/value metadata about the PNG
252
+ # stream. In this chunk, the value is stored uncompressed.
242
253
  #
243
- # The tEXt chunk only supports Latin-1 encoded textual data. If you need UTF-8
244
- # support, check out the InternationalText chunk type.
254
+ # The tEXt chunk only supports Latin-1 encoded textual data. If you need
255
+ # UTF-8 support, check out the InternationalText chunk type.
245
256
  #
246
257
  # @see ChunkyPNG::Chunk::CompressedText
247
258
  # @see ChunkyPNG::Chunk::InternationalText
248
259
  class Text < Base
249
-
250
260
  attr_accessor :keyword, :value
251
261
 
252
262
  def initialize(keyword, value)
@@ -259,8 +269,8 @@ module ChunkyPNG
259
269
  new(keyword, value)
260
270
  end
261
271
 
262
- # Creates the content to write to the stream, by concatenating the keyword
263
- # with the value, joined by a null character.
272
+ # Creates the content to write to the stream, by concatenating the
273
+ # keyword with the value, joined by a null character.
264
274
  #
265
275
  # @return The content that should be written to the datastream.
266
276
  def content
@@ -268,14 +278,13 @@ module ChunkyPNG
268
278
  end
269
279
  end
270
280
 
271
- # The CompressedText (zTXt) chunk contains keyword/value metadata about
272
- # the PNG stream. In this chunk, the value is compressed using Deflate
281
+ # The CompressedText (zTXt) chunk contains keyword/value metadata about the
282
+ # PNG stream. In this chunk, the value is compressed using Deflate
273
283
  # compression.
274
284
  #
275
285
  # @see ChunkyPNG::Chunk::CompressedText
276
286
  # @see ChunkyPNG::Chunk::InternationalText
277
287
  class CompressedText < Base
278
-
279
288
  attr_accessor :keyword, :value
280
289
 
281
290
  def initialize(keyword, value)
@@ -289,40 +298,49 @@ module ChunkyPNG
289
298
  new(keyword, Zlib::Inflate.inflate(value))
290
299
  end
291
300
 
292
- # Creates the content to write to the stream, by concatenating the keyword
293
- # with the deflated value, joined by a null character.
301
+ # Creates the content to write to the stream, by concatenating the
302
+ # keyword with the deflated value, joined by a null character.
294
303
  #
295
304
  # @return The content that should be written to the datastream.
296
305
  def content
297
- [keyword, ChunkyPNG::COMPRESSION_DEFAULT, Zlib::Deflate.deflate(value)].pack('Z*Ca*')
306
+ [keyword, ChunkyPNG::COMPRESSION_DEFAULT, Zlib::Deflate.deflate(value)].
307
+ pack('Z*Ca*')
298
308
  end
299
309
  end
300
310
 
301
- # The Text (iTXt) chunk contains keyword/value metadata about the PNG stream.
302
- # The metadata in this chunk can be encoded using UTF-8 characters. Moreover,
303
- # it is possible to define the language of the metadata, and give a translation
304
- # of the keyword name. Finally, it supports bot compressed and uncompressed
305
- # values.
306
- #
307
- # @todo This chunk is currently not implemented, but merely read and written
308
- # back intact.
311
+ # The Text (iTXt) chunk contains keyword/value metadata about the PNG
312
+ # stream.
313
+ #
314
+ # The metadata in this chunk can be encoded using UTF-8 characters.
315
+ # Moreover, it is possible to define the language of the metadata, and give
316
+ # a translation of the keyword name. Finally, it supports bot compressed
317
+ # and uncompressed values.
318
+ #
319
+ # @todo This chunk is currently not implemented, but merely read and
320
+ # written back intact.
309
321
  #
310
322
  # @see ChunkyPNG::Chunk::Text
311
323
  # @see ChunkyPNG::Chunk::CompressedText
312
324
  class InternationalText < Generic
313
-
314
325
  # TODO
315
326
  end
316
327
 
317
- # Maps chunk types to classes, based on the four byte chunk type indicator at the
318
- # beginning of a chunk.
328
+ # Maps chunk types to classes, based on the four byte chunk type indicator
329
+ # at the beginning of a chunk.
319
330
  #
320
- # If a chunk type is not specified in this hash, the Generic chunk type will be used.
331
+ # If a chunk type is not specified in this hash, the Generic chunk type
332
+ # will be used.
321
333
  #
322
334
  # @see ChunkyPNG::Chunk.read
323
335
  CHUNK_TYPES = {
324
- 'IHDR' => Header, 'IEND' => End, 'IDAT' => ImageData, 'PLTE' => Palette, 'tRNS' => Transparency,
325
- 'tEXt' => Text, 'zTXt' => CompressedText, 'iTXt' => InternationalText
336
+ 'IHDR' => Header,
337
+ 'IEND' => End,
338
+ 'IDAT' => ImageData,
339
+ 'PLTE' => Palette,
340
+ 'tRNS' => Transparency,
341
+ 'tEXt' => Text,
342
+ 'zTXt' => CompressedText,
343
+ 'iTXt' => InternationalText,
326
344
  }
327
345
  end
328
346
  end
@@ -1,5 +1,5 @@
1
1
  module ChunkyPNG
2
-
2
+
3
3
  # Factory method to return a color value, based on the arguments given.
4
4
  #
5
5
  # @overload Color(r, g, b, a)
@@ -12,15 +12,18 @@ module ChunkyPNG
12
12
  #
13
13
  # @overload Color(hex_value, opacity = nil)
14
14
  # @param (see ChunkyPNG::Color.from_hex)
15
- # @return [Integer] The hex color value, with the opacity applied if one was given.
15
+ # @return [Integer] The hex color value, with the opacity applied if one
16
+ # was given.
16
17
  #
17
18
  # @overload Color(color_name, opacity = nil)
18
19
  # @param (see ChunkyPNG::Color.html_color)
19
- # @return [Integer] The hex color value, with the opacity applied if one was given.
20
+ # @return [Integer] The hex color value, with the opacity applied if one
21
+ # was given.
20
22
  #
21
23
  # @overload Color(color_value, opacity = nil)
22
24
  # @param [Integer, :to_i] The color value.
23
- # @return [Integer] The color value, with the opacity applied if one was given.
25
+ # @return [Integer] The color value, with the opacity applied if one was
26
+ # given.
24
27
  #
25
28
  # @return [Integer] The determined color value as RGBA integer.
26
29
  # @raise [ArgumentError] if the arguments weren't understood as a color.
@@ -54,7 +57,7 @@ module ChunkyPNG
54
57
 
55
58
  # @return [Integer] The maximum value of each color component.
56
59
  MAX = 0xff
57
-
60
+
58
61
  # @private
59
62
  # @return [Regexp] The regexp to parse 3-digit hex color values.
60
63
  HEX3_COLOR_REGEXP = /\A(?:#|0x)?([0-9a-f]{3})\z/i
@@ -66,7 +69,7 @@ module ChunkyPNG
66
69
  # @private
67
70
  # @return [Regexp] The regexp to parse named color values.
68
71
  HTML_COLOR_REGEXP = /^([a-z][a-z_ ]+[a-z])(?:\ ?\@\ ?(1\.0|0\.\d+))?$/i
69
-
72
+
70
73
  ####################################################################
71
74
  # CONSTRUCTING COLOR VALUES
72
75
  ####################################################################
@@ -76,7 +79,8 @@ module ChunkyPNG
76
79
  # It supports color numbers, colors in hex notation and named HTML colors.
77
80
  #
78
81
  # @param [Integer, String] The color value.
79
- # @return [Integer] The color value, with the opacity applied if one was given.
82
+ # @return [Integer] The color value, with the opacity applied if one was
83
+ # given.
80
84
  def parse(source)
81
85
  return source if source.kind_of?(Integer)
82
86
  case source.to_s
@@ -107,14 +111,16 @@ module ChunkyPNG
107
111
  end
108
112
 
109
113
  # Creates a new color using a grayscale teint.
110
- # @param [Integer] teint The grayscale teint (0-255), will be used as r, g, and b value.
114
+ # @param [Integer] teint The grayscale teint (0-255), will be used as r, g,
115
+ # and b value.
111
116
  # @return [Integer] The newly constructed color value.
112
117
  def grayscale(teint)
113
118
  teint << 24 | teint << 16 | teint << 8 | 0xff
114
119
  end
115
120
 
116
121
  # Creates a new color using a grayscale teint and alpha value.
117
- # @param [Integer] teint The grayscale teint (0-255), will be used as r, g, and b value.
122
+ # @param [Integer] teint The grayscale teint (0-255), will be used as r, g,
123
+ # and b value.
118
124
  # @param [Integer] a The opacity (0-255)
119
125
  # @return [Integer] The newly constructed color value.
120
126
  def grayscale_alpha(teint, a)
@@ -127,7 +133,7 @@ module ChunkyPNG
127
133
 
128
134
  # Creates a color by unpacking an rgb triple from a string.
129
135
  #
130
- # @param [String] stream The string to load the color from. It should be
136
+ # @param [String] stream The string to load the color from. It should be
131
137
  # at least 3 + pos bytes long.
132
138
  # @param [Integer] pos The position in the string to load the triple from.
133
139
  # @return [Integer] The newly constructed color value.
@@ -137,15 +143,15 @@ module ChunkyPNG
137
143
 
138
144
  # Creates a color by unpacking an rgba triple from a string
139
145
  #
140
- # @param [String] stream The string to load the color from. It should be
146
+ # @param [String] stream The string to load the color from. It should be
141
147
  # at least 4 + pos bytes long.
142
148
  # @param [Integer] pos The position in the string to load the triple from.
143
149
  # @return [Integer] The newly constructed color value.
144
150
  def from_rgba_stream(stream, pos = 0)
145
151
  rgba(*stream.unpack("@#{pos}C4"))
146
152
  end
147
-
148
- # Creates a color by converting it from a string in hex notation.
153
+
154
+ # Creates a color by converting it from a string in hex notation.
149
155
  #
150
156
  # It supports colors with (#rrggbbaa) or without (#rrggbb) alpha channel
151
157
  # as well as the 3-digit short format (#rgb) for those without.
@@ -181,7 +187,7 @@ module ChunkyPNG
181
187
  def r(value)
182
188
  (value & 0xff000000) >> 24
183
189
  end
184
-
190
+
185
191
  # Returns the green-component from the color value.
186
192
  #
187
193
  # @param [Integer] value The color value.
@@ -189,7 +195,7 @@ module ChunkyPNG
189
195
  def g(value)
190
196
  (value & 0x00ff0000) >> 16
191
197
  end
192
-
198
+
193
199
  # Returns the blue-component from the color value.
194
200
  #
195
201
  # @param [Integer] value The color value.
@@ -197,7 +203,7 @@ module ChunkyPNG
197
203
  def b(value)
198
204
  (value & 0x0000ff00) >> 8
199
205
  end
200
-
206
+
201
207
  # Returns the alpha channel value for the color value.
202
208
  #
203
209
  # @param [Integer] value The color value.
@@ -205,7 +211,7 @@ module ChunkyPNG
205
211
  def a(value)
206
212
  value & 0x000000ff
207
213
  end
208
-
214
+
209
215
  # Returns true if this color is fully opaque.
210
216
  #
211
217
  # @param [Integer] value The color to test.
@@ -213,14 +219,14 @@ module ChunkyPNG
213
219
  def opaque?(value)
214
220
  a(value) == 0x000000ff
215
221
  end
216
-
222
+
217
223
  # Returns the opaque value of this color by removing the alpha channel.
218
224
  # @param [Integer] value The color to transform.
219
225
  # @return [Integer] The opaque color
220
226
  def opaque!(value)
221
227
  value | 0x000000ff
222
228
  end
223
-
229
+
224
230
  # Returns true if this color is fully transparent.
225
231
  #
226
232
  # @param [Integer] value The color to test.
@@ -228,7 +234,7 @@ module ChunkyPNG
228
234
  def grayscale?(value)
229
235
  r(value) == b(value) && b(value) == g(value)
230
236
  end
231
-
237
+
232
238
  # Returns true if this color is fully transparent.
233
239
  #
234
240
  # @param [Integer] value The color to test.
@@ -241,9 +247,9 @@ module ChunkyPNG
241
247
  # ALPHA COMPOSITION
242
248
  ####################################################################
243
249
 
244
- # Multiplies two fractions using integer math, where the fractions are stored using an
245
- # integer between 0 and 255. This method is used as a helper method for compositing
246
- # colors using integer math.
250
+ # Multiplies two fractions using integer math, where the fractions are
251
+ # stored using an integer between 0 and 255. This method is used as a
252
+ # helper method for compositing colors using integer math.
247
253
  #
248
254
  # This is a quicker implementation of ((a * b) / 255.0).round.
249
255
  #
@@ -257,8 +263,8 @@ module ChunkyPNG
257
263
 
258
264
  # Composes two colors with an alpha channel using integer math.
259
265
  #
260
- # This version is faster than the version based on floating point math, so this
261
- # compositing function is used by default.
266
+ # This version is faster than the version based on floating point math, so
267
+ # this compositing function is used by default.
262
268
  #
263
269
  # @param [Integer] fg The foreground color.
264
270
  # @param [Integer] bg The foreground color.
@@ -267,7 +273,7 @@ module ChunkyPNG
267
273
  def compose_quick(fg, bg)
268
274
  return fg if opaque?(fg) || fully_transparent?(bg)
269
275
  return bg if fully_transparent?(fg)
270
-
276
+
271
277
  a_com = int8_mult(0xff - a(fg), a(bg))
272
278
  new_r = int8_mult(a(fg), r(fg)) + int8_mult(a_com, r(bg))
273
279
  new_g = int8_mult(a(fg), g(fg)) + int8_mult(a_com, g(bg))
@@ -278,9 +284,9 @@ module ChunkyPNG
278
284
 
279
285
  # Composes two colors with an alpha channel using floating point math.
280
286
  #
281
- # This method uses more precise floating point math, but this precision is lost
282
- # when the result is converted back to an integer. Because it is slower than
283
- # the version based on integer math, that version is preferred.
287
+ # This method uses more precise floating point math, but this precision is
288
+ # lost when the result is converted back to an integer. Because it is
289
+ # slower than the version based on integer math, that version is preferred.
284
290
  #
285
291
  # @param [Integer] fg The foreground color.
286
292
  # @param [Integer] bg The foreground color.
@@ -289,7 +295,7 @@ module ChunkyPNG
289
295
  def compose_precise(fg, bg)
290
296
  return fg if opaque?(fg) || fully_transparent?(bg)
291
297
  return bg if fully_transparent?(fg)
292
-
298
+
293
299
  fg_a = a(fg).to_f / MAX
294
300
  bg_a = a(bg).to_f / MAX
295
301
  a_com = (1.0 - fg_a) * bg_a
@@ -302,8 +308,8 @@ module ChunkyPNG
302
308
  end
303
309
 
304
310
  alias :compose :compose_quick
305
-
306
- # Blends the foreground and background color by taking the average of
311
+
312
+ # Blends the foreground and background color by taking the average of
307
313
  # the components.
308
314
  #
309
315
  # @param [Integer] fg The foreground color.
@@ -313,8 +319,8 @@ module ChunkyPNG
313
319
  (fg + bg) >> 1
314
320
  end
315
321
 
316
- # Interpolates the foreground and background colors by the given alpha value.
317
- # This also blends the alpha channels themselves.
322
+ # Interpolates the foreground and background colors by the given alpha
323
+ # value. This also blends the alpha channels themselves.
318
324
  #
319
325
  # A blending factor of 255 will give entirely the foreground,
320
326
  # while a blending factor of 0 will give the background.
@@ -326,37 +332,39 @@ module ChunkyPNG
326
332
  def interpolate_quick(fg, bg, alpha)
327
333
  return fg if alpha >= 255
328
334
  return bg if alpha <= 0
329
-
335
+
330
336
  alpha_com = 255 - alpha
331
337
 
332
338
  new_r = int8_mult(alpha, r(fg)) + int8_mult(alpha_com, r(bg))
333
339
  new_g = int8_mult(alpha, g(fg)) + int8_mult(alpha_com, g(bg))
334
340
  new_b = int8_mult(alpha, b(fg)) + int8_mult(alpha_com, b(bg))
335
341
  new_a = int8_mult(alpha, a(fg)) + int8_mult(alpha_com, a(bg))
336
-
337
- return rgba(new_r, new_g, new_b, new_a)
342
+
343
+ rgba(new_r, new_g, new_b, new_a)
338
344
  end
339
345
 
340
346
  # Calculates the grayscale teint of an RGB color.
341
347
  #
342
- # @param [Integer] color The color to convert.
348
+ # @param [Integer] color The color to convert.
343
349
  # @return [Integer] The grayscale teint of the input color, 0-255.
344
350
  def grayscale_teint(color)
345
351
  (r(color) * 0.3 + g(color) * 0.59 + b(color) * 0.11).round
346
352
  end
347
-
353
+
348
354
  # Converts a color to a fiting grayscale value. It will conserve the alpha
349
355
  # channel.
350
356
  #
351
- # This method will return a full color value, with the R, G, and B value set
352
- # to the grayscale teint calcuated from the input color's R, G and B values.
357
+ # This method will return a full color value, with the R, G, and B value
358
+ # set to the grayscale teint calcuated from the input color's R, G and B
359
+ # values.
353
360
  #
354
361
  # @param [Integer] color The color to convert.
355
- # @return [Integer] The input color, converted to the best fitting grayscale.
362
+ # @return [Integer] The input color, converted to the best fitting
363
+ # grayscale.
356
364
  # @see #grayscale_teint
357
365
  def to_grayscale(color)
358
366
  grayscale_alpha(grayscale_teint(color), a(color))
359
- end
367
+ end
360
368
 
361
369
  # Lowers the intensity of a color, by lowering its alpha by a given factor.
362
370
  # @param [Integer] color The color to adjust.
@@ -366,21 +374,23 @@ module ChunkyPNG
366
374
  new_alpha = int8_mult(a(color), factor)
367
375
  (color & 0xffffff00) | new_alpha
368
376
  end
369
-
377
+
370
378
  # Decomposes a color, given a color, a mask color and a background color.
371
379
  # The returned color will be a variant of the mask color, with the alpha
372
- # channel set to the best fitting value. This basically is the reverse
380
+ # channel set to the best fitting value. This basically is the reverse
373
381
  # operation if alpha composition.
374
382
  #
375
383
  # If the color cannot be decomposed, this method will return the fully
376
384
  # transparent variant of the mask color.
377
385
  #
378
386
  # @param [Integer] color The color that was the result of compositing.
379
- # @param [Integer] mask The opaque variant of the color that was being composed
387
+ # @param [Integer] mask The opaque variant of the color that was being
388
+ # composed
380
389
  # @param [Integer] bg The background color on which the color was composed.
381
- # @param [Integer] tolerance The decomposition tolerance level, a value between 0 and 255.
382
- # @return [Integer] The decomposed color,a variant of the masked color with the
383
- # alpha channel set to an appropriate value.
390
+ # @param [Integer] tolerance The decomposition tolerance level, a value
391
+ # between 0 and 255.
392
+ # @return [Integer] The decomposed color, a variant of the masked color
393
+ # with the alpha channel set to an appropriate value.
384
394
  def decompose_color(color, mask, bg, tolerance = 1)
385
395
  if alpha_decomposable?(color, mask, bg, tolerance)
386
396
  mask & 0xffffff00 | decompose_alpha(color, mask, bg)
@@ -388,62 +398,71 @@ module ChunkyPNG
388
398
  mask & 0xffffff00
389
399
  end
390
400
  end
391
-
401
+
392
402
  # Checks whether an alpha channel value can successfully be composed
393
403
  # given the resulting color, the mask color and a background color,
394
- # all of which should be opaque.
404
+ # all of which should be opaque.
395
405
  #
396
406
  # @param [Integer] color The color that was the result of compositing.
397
- # @param [Integer] mask The opaque variant of the color that was being composed
407
+ # @param [Integer] mask The opaque variant of the color that was being
408
+ # composed
398
409
  # @param [Integer] bg The background color on which the color was composed.
399
- # @param [Integer] tolerance The decomposition tolerance level, a value between 0 and 255.
400
- # @return [Boolean] True if the alpha component can be decomposed successfully.
410
+ # @param [Integer] tolerance The decomposition tolerance level, a value
411
+ # between 0 and 255.
412
+ # @return [Boolean] True if the alpha component can be decomposed
413
+ # successfully.
401
414
  # @see #decompose_alpha
402
415
  def alpha_decomposable?(color, mask, bg, tolerance = 1)
403
416
  components = decompose_alpha_components(color, mask, bg)
404
- sum = components.inject(0) { |a,b| a + b }
417
+ sum = components.inject(0) { |a,b| a + b }
405
418
  max = components.max * 3
406
- return components.max <= 255 && components.min >= 0 && (sum + tolerance * 3) >= max
419
+ components.max <= 255 && components.min >= 0 && (sum + tolerance * 3) >= max
407
420
  end
408
-
409
- # Decomposes the alpha channel value given the resulting color, the mask color
410
- # and a background color, all of which should be opaque.
421
+
422
+ # Decomposes the alpha channel value given the resulting color, the mask
423
+ # color and a background color, all of which should be opaque.
411
424
  #
412
- # Make sure to call {#alpha_decomposable?} first to see if the alpha channel
413
- # value can successfully decomposed with a given tolerance, otherwise the return
414
- # value of this method is undefined.
425
+ # Make sure to call {#alpha_decomposable?} first to see if the alpha
426
+ # channel value can successfully decomposed with a given tolerance,
427
+ # otherwise the return value of this method is undefined.
415
428
  #
416
429
  # @param [Integer] color The color that was the result of compositing.
417
- # @param [Integer] mask The opaque variant of the color that was being composed
430
+ # @param [Integer] mask The opaque variant of the color that was being
431
+ # composed
418
432
  # @param [Integer] bg The background color on which the color was composed.
419
- # @return [Integer] The best fitting alpha channel, a value between 0 and 255.
433
+ # @return [Integer] The best fitting alpha channel, a value between 0 and
434
+ # 255.
420
435
  # @see #alpha_decomposable?
421
436
  def decompose_alpha(color, mask, bg)
422
437
  components = decompose_alpha_components(color, mask, bg)
423
438
  (components.inject(0) { |a,b| a + b } / 3.0).round
424
439
  end
425
-
440
+
426
441
  # Decomposes an alpha channel for either the r, g or b color channel.
427
- # @param [:r, :g, :b] channel The channel to decompose the alpha channel from.
442
+ # @param [:r, :g, :b] channel The channel to decompose the alpha channel
443
+ # from.
428
444
  # @param [Integer] color The color that was the result of compositing.
429
- # @param [Integer] mask The opaque variant of the color that was being composed
445
+ # @param [Integer] mask The opaque variant of the color that was being
446
+ # composed
430
447
  # @param [Integer] bg The background color on which the color was composed.
431
448
  # @return [Integer] The decomposed alpha value for the channel.
432
449
  def decompose_alpha_component(channel, color, mask, bg)
433
450
  cc, mc, bc = send(channel, color), send(channel, mask), send(channel, bg)
434
-
451
+
435
452
  return 0x00 if bc == cc
436
453
  return 0xff if bc == mc
437
454
  return 0xff if cc == mc
438
-
455
+
439
456
  (((bc - cc).to_f / (bc - mc).to_f) * MAX).round
440
457
  end
441
-
458
+
442
459
  # Decomposes the alpha channels for the r, g and b color channel.
443
460
  # @param [Integer] color The color that was the result of compositing.
444
- # @param [Integer] mask The opaque variant of the color that was being composed
445
- # @param [Integer] bg The background color on which the color was composed.
446
- # @return [Array<Integer>] The decomposed alpha values for the r, g and b channels.
461
+ # @param [Integer] mask The opaque variant of the color that was being
462
+ # composed
463
+ # @param [Integer] bg The background color on which the color was composed.
464
+ # @return [Array<Integer>] The decomposed alpha values for the r, g and b
465
+ # channels.
447
466
  def decompose_alpha_components(color, mask, bg)
448
467
  [
449
468
  decompose_alpha_component(:r, color, mask, bg),
@@ -456,7 +475,8 @@ module ChunkyPNG
456
475
  # CONVERSIONS
457
476
  ####################################################################
458
477
 
459
- # Returns a string representing this color using hex notation (i.e. #rrggbbaa).
478
+ # Returns a string representing this color using hex notation (i.e.
479
+ # #rrggbbaa).
460
480
  #
461
481
  # @param [Integer] value The color to convert.
462
482
  # @return [String] The color in hex notation, starting with a pound sign.
@@ -472,8 +492,8 @@ module ChunkyPNG
472
492
  [r(color), g(color), b(color), a(color)]
473
493
  end
474
494
 
475
- # Returns an array with the separate RGB values for this color.
476
- # The alpha channel will be discarded.
495
+ # Returns an array with the separate RGB values for this color. The alpha
496
+ # channel will be discarded.
477
497
  #
478
498
  # @param [Integer] color The color to convert.
479
499
  # @return [Array<Integer>] An array with 3 Integer elements.
@@ -483,7 +503,7 @@ module ChunkyPNG
483
503
 
484
504
  # Returns an array with the grayscale teint value for this color.
485
505
  #
486
- # This method expects the r,g and b value to be equal, and the alpha
506
+ # This method expects the r, g, and b value to be equal, and the alpha
487
507
  # channel will be discarded.
488
508
  #
489
509
  # @param [Integer] color The grayscale color to convert.
@@ -492,189 +512,220 @@ module ChunkyPNG
492
512
  [b(color)] # assumption r == g == b
493
513
  end
494
514
 
495
- # Returns an array with the grayscale teint and alpha channel values
496
- # for this color.
515
+ # Returns an array with the grayscale teint and alpha channel values for
516
+ # this color.
497
517
  #
498
- # This method expects the color to be grayscale, i.e. r,g and b value
499
- # to be equal and uses only the B channel. If you need to convert a
500
- # color to grayscale first, see {#to_grayscale}.
518
+ # This method expects the color to be grayscale, i.e. r, g, and b value to
519
+ # be equal and uses only the B channel. If you need to convert a color to
520
+ # grayscale first, see {#to_grayscale}.
501
521
  #
502
522
  # @param [Integer] color The grayscale color to convert.
503
523
  # @return [Array<Integer>] An array with 2 Integer elements.
504
- # @see #to_grascale
524
+ # @see #to_grayscale
505
525
  def to_grayscale_alpha_bytes(color)
506
526
  [b(color), a(color)] # assumption r == g == b
507
527
  end
508
528
 
529
+ ####################################################################
530
+ # COMPARISON
531
+ ####################################################################
532
+
533
+ # Compute the Euclidean distance between 2 colors in RGBA
534
+ #
535
+ # This method simply takes the Euclidean distance between the RGBA channels
536
+ # of 2 colors, which gives us a measure of how different the two colors
537
+ # are.
538
+ #
539
+ # Although it would be more perceptually accurate to calculate a proper
540
+ # Delta E in Lab colorspace, this method should serve many use-cases while
541
+ # avoiding the overhead of converting RGBA to Lab.
542
+ #
543
+ # @param color_a [Integer]
544
+ # @param color_b [Integer]
545
+ # @return [Float]
546
+ def euclidean_distance_rgba(pixel_after, pixel_before)
547
+ Math.sqrt(
548
+ (r(pixel_after) - r(pixel_before))**2 +
549
+ (g(pixel_after) - g(pixel_before))**2 +
550
+ (b(pixel_after) - b(pixel_before))**2 +
551
+ (a(pixel_after) - a(pixel_before))**2
552
+ )
553
+ end
554
+
555
+ # Could be simplified as MAX * 2, but this format mirrors the math in
556
+ # {#euclidean_distance_rgba}
557
+ # @return [Float] The maximum Euclidean distance of two RGBA colors.
558
+ MAX_EUCLIDEAN_DISTANCE_RGBA = Math.sqrt(MAX**2 * 4)
559
+
509
560
  ####################################################################
510
561
  # COLOR CONSTANTS
511
562
  ####################################################################
512
563
 
513
564
  # @return [Hash<Symbol, Integer>] All the predefined color names in HTML.
514
565
  PREDEFINED_COLORS = {
515
- :aliceblue => 0xf0f8ff00,
516
- :antiquewhite => 0xfaebd700,
517
- :aqua => 0x00ffff00,
518
- :aquamarine => 0x7fffd400,
519
- :azure => 0xf0ffff00,
520
- :beige => 0xf5f5dc00,
521
- :bisque => 0xffe4c400,
522
- :black => 0x00000000,
523
- :blanchedalmond => 0xffebcd00,
524
- :blue => 0x0000ff00,
525
- :blueviolet => 0x8a2be200,
526
- :brown => 0xa52a2a00,
527
- :burlywood => 0xdeb88700,
528
- :cadetblue => 0x5f9ea000,
529
- :chartreuse => 0x7fff0000,
530
- :chocolate => 0xd2691e00,
531
- :coral => 0xff7f5000,
532
- :cornflowerblue => 0x6495ed00,
533
- :cornsilk => 0xfff8dc00,
534
- :crimson => 0xdc143c00,
535
- :cyan => 0x00ffff00,
536
- :darkblue => 0x00008b00,
537
- :darkcyan => 0x008b8b00,
538
- :darkgoldenrod => 0xb8860b00,
539
- :darkgray => 0xa9a9a900,
540
- :darkgrey => 0xa9a9a900,
541
- :darkgreen => 0x00640000,
542
- :darkkhaki => 0xbdb76b00,
543
- :darkmagenta => 0x8b008b00,
544
- :darkolivegreen => 0x556b2f00,
545
- :darkorange => 0xff8c0000,
546
- :darkorchid => 0x9932cc00,
547
- :darkred => 0x8b000000,
548
- :darksalmon => 0xe9967a00,
549
- :darkseagreen => 0x8fbc8f00,
550
- :darkslateblue => 0x483d8b00,
551
- :darkslategray => 0x2f4f4f00,
552
- :darkslategrey => 0x2f4f4f00,
553
- :darkturquoise => 0x00ced100,
554
- :darkviolet => 0x9400d300,
555
- :deeppink => 0xff149300,
556
- :deepskyblue => 0x00bfff00,
557
- :dimgray => 0x69696900,
558
- :dimgrey => 0x69696900,
559
- :dodgerblue => 0x1e90ff00,
560
- :firebrick => 0xb2222200,
561
- :floralwhite => 0xfffaf000,
562
- :forestgreen => 0x228b2200,
563
- :fuchsia => 0xff00ff00,
564
- :gainsboro => 0xdcdcdc00,
565
- :ghostwhite => 0xf8f8ff00,
566
- :gold => 0xffd70000,
567
- :goldenrod => 0xdaa52000,
568
- :gray => 0x80808000,
569
- :grey => 0x80808000,
570
- :green => 0x00800000,
571
- :greenyellow => 0xadff2f00,
572
- :honeydew => 0xf0fff000,
573
- :hotpink => 0xff69b400,
574
- :indianred => 0xcd5c5c00,
575
- :indigo => 0x4b008200,
576
- :ivory => 0xfffff000,
577
- :khaki => 0xf0e68c00,
578
- :lavender => 0xe6e6fa00,
579
- :lavenderblush => 0xfff0f500,
580
- :lawngreen => 0x7cfc0000,
581
- :lemonchiffon => 0xfffacd00,
582
- :lightblue => 0xadd8e600,
583
- :lightcoral => 0xf0808000,
584
- :lightcyan => 0xe0ffff00,
566
+ :aliceblue => 0xf0f8ff00,
567
+ :antiquewhite => 0xfaebd700,
568
+ :aqua => 0x00ffff00,
569
+ :aquamarine => 0x7fffd400,
570
+ :azure => 0xf0ffff00,
571
+ :beige => 0xf5f5dc00,
572
+ :bisque => 0xffe4c400,
573
+ :black => 0x00000000,
574
+ :blanchedalmond => 0xffebcd00,
575
+ :blue => 0x0000ff00,
576
+ :blueviolet => 0x8a2be200,
577
+ :brown => 0xa52a2a00,
578
+ :burlywood => 0xdeb88700,
579
+ :cadetblue => 0x5f9ea000,
580
+ :chartreuse => 0x7fff0000,
581
+ :chocolate => 0xd2691e00,
582
+ :coral => 0xff7f5000,
583
+ :cornflowerblue => 0x6495ed00,
584
+ :cornsilk => 0xfff8dc00,
585
+ :crimson => 0xdc143c00,
586
+ :cyan => 0x00ffff00,
587
+ :darkblue => 0x00008b00,
588
+ :darkcyan => 0x008b8b00,
589
+ :darkgoldenrod => 0xb8860b00,
590
+ :darkgray => 0xa9a9a900,
591
+ :darkgrey => 0xa9a9a900,
592
+ :darkgreen => 0x00640000,
593
+ :darkkhaki => 0xbdb76b00,
594
+ :darkmagenta => 0x8b008b00,
595
+ :darkolivegreen => 0x556b2f00,
596
+ :darkorange => 0xff8c0000,
597
+ :darkorchid => 0x9932cc00,
598
+ :darkred => 0x8b000000,
599
+ :darksalmon => 0xe9967a00,
600
+ :darkseagreen => 0x8fbc8f00,
601
+ :darkslateblue => 0x483d8b00,
602
+ :darkslategray => 0x2f4f4f00,
603
+ :darkslategrey => 0x2f4f4f00,
604
+ :darkturquoise => 0x00ced100,
605
+ :darkviolet => 0x9400d300,
606
+ :deeppink => 0xff149300,
607
+ :deepskyblue => 0x00bfff00,
608
+ :dimgray => 0x69696900,
609
+ :dimgrey => 0x69696900,
610
+ :dodgerblue => 0x1e90ff00,
611
+ :firebrick => 0xb2222200,
612
+ :floralwhite => 0xfffaf000,
613
+ :forestgreen => 0x228b2200,
614
+ :fuchsia => 0xff00ff00,
615
+ :gainsboro => 0xdcdcdc00,
616
+ :ghostwhite => 0xf8f8ff00,
617
+ :gold => 0xffd70000,
618
+ :goldenrod => 0xdaa52000,
619
+ :gray => 0x80808000,
620
+ :grey => 0x80808000,
621
+ :green => 0x00800000,
622
+ :greenyellow => 0xadff2f00,
623
+ :honeydew => 0xf0fff000,
624
+ :hotpink => 0xff69b400,
625
+ :indianred => 0xcd5c5c00,
626
+ :indigo => 0x4b008200,
627
+ :ivory => 0xfffff000,
628
+ :khaki => 0xf0e68c00,
629
+ :lavender => 0xe6e6fa00,
630
+ :lavenderblush => 0xfff0f500,
631
+ :lawngreen => 0x7cfc0000,
632
+ :lemonchiffon => 0xfffacd00,
633
+ :lightblue => 0xadd8e600,
634
+ :lightcoral => 0xf0808000,
635
+ :lightcyan => 0xe0ffff00,
585
636
  :lightgoldenrodyellow => 0xfafad200,
586
- :lightgray => 0xd3d3d300,
587
- :lightgrey => 0xd3d3d300,
588
- :lightgreen => 0x90ee9000,
589
- :lightpink => 0xffb6c100,
590
- :lightsalmon => 0xffa07a00,
591
- :lightseagreen => 0x20b2aa00,
592
- :lightskyblue => 0x87cefa00,
593
- :lightslategray => 0x77889900,
594
- :lightslategrey => 0x77889900,
595
- :lightsteelblue => 0xb0c4de00,
596
- :lightyellow => 0xffffe000,
597
- :lime => 0x00ff0000,
598
- :limegreen => 0x32cd3200,
599
- :linen => 0xfaf0e600,
600
- :magenta => 0xff00ff00,
601
- :maroon => 0x80000000,
602
- :mediumaquamarine => 0x66cdaa00,
603
- :mediumblue => 0x0000cd00,
604
- :mediumorchid => 0xba55d300,
605
- :mediumpurple => 0x9370d800,
606
- :mediumseagreen => 0x3cb37100,
607
- :mediumslateblue => 0x7b68ee00,
608
- :mediumspringgreen => 0x00fa9a00,
609
- :mediumturquoise => 0x48d1cc00,
610
- :mediumvioletred => 0xc7158500,
611
- :midnightblue => 0x19197000,
612
- :mintcream => 0xf5fffa00,
613
- :mistyrose => 0xffe4e100,
614
- :moccasin => 0xffe4b500,
615
- :navajowhite => 0xffdead00,
616
- :navy => 0x00008000,
617
- :oldlace => 0xfdf5e600,
618
- :olive => 0x80800000,
619
- :olivedrab => 0x6b8e2300,
620
- :orange => 0xffa50000,
621
- :orangered => 0xff450000,
622
- :orchid => 0xda70d600,
623
- :palegoldenrod => 0xeee8aa00,
624
- :palegreen => 0x98fb9800,
625
- :paleturquoise => 0xafeeee00,
626
- :palevioletred => 0xd8709300,
627
- :papayawhip => 0xffefd500,
628
- :peachpuff => 0xffdab900,
629
- :peru => 0xcd853f00,
630
- :pink => 0xffc0cb00,
631
- :plum => 0xdda0dd00,
632
- :powderblue => 0xb0e0e600,
633
- :purple => 0x80008000,
634
- :red => 0xff000000,
635
- :rosybrown => 0xbc8f8f00,
636
- :royalblue => 0x4169e100,
637
- :saddlebrown => 0x8b451300,
638
- :salmon => 0xfa807200,
639
- :sandybrown => 0xf4a46000,
640
- :seagreen => 0x2e8b5700,
641
- :seashell => 0xfff5ee00,
642
- :sienna => 0xa0522d00,
643
- :silver => 0xc0c0c000,
644
- :skyblue => 0x87ceeb00,
645
- :slateblue => 0x6a5acd00,
646
- :slategray => 0x70809000,
647
- :slategrey => 0x70809000,
648
- :snow => 0xfffafa00,
649
- :springgreen => 0x00ff7f00,
650
- :steelblue => 0x4682b400,
651
- :tan => 0xd2b48c00,
652
- :teal => 0x00808000,
653
- :thistle => 0xd8bfd800,
654
- :tomato => 0xff634700,
655
- :turquoise => 0x40e0d000,
656
- :violet => 0xee82ee00,
657
- :wheat => 0xf5deb300,
658
- :white => 0xffffff00,
659
- :whitesmoke => 0xf5f5f500,
660
- :yellow => 0xffff0000,
661
- :yellowgreen => 0x9acd3200
637
+ :lightgray => 0xd3d3d300,
638
+ :lightgrey => 0xd3d3d300,
639
+ :lightgreen => 0x90ee9000,
640
+ :lightpink => 0xffb6c100,
641
+ :lightsalmon => 0xffa07a00,
642
+ :lightseagreen => 0x20b2aa00,
643
+ :lightskyblue => 0x87cefa00,
644
+ :lightslategray => 0x77889900,
645
+ :lightslategrey => 0x77889900,
646
+ :lightsteelblue => 0xb0c4de00,
647
+ :lightyellow => 0xffffe000,
648
+ :lime => 0x00ff0000,
649
+ :limegreen => 0x32cd3200,
650
+ :linen => 0xfaf0e600,
651
+ :magenta => 0xff00ff00,
652
+ :maroon => 0x80000000,
653
+ :mediumaquamarine => 0x66cdaa00,
654
+ :mediumblue => 0x0000cd00,
655
+ :mediumorchid => 0xba55d300,
656
+ :mediumpurple => 0x9370d800,
657
+ :mediumseagreen => 0x3cb37100,
658
+ :mediumslateblue => 0x7b68ee00,
659
+ :mediumspringgreen => 0x00fa9a00,
660
+ :mediumturquoise => 0x48d1cc00,
661
+ :mediumvioletred => 0xc7158500,
662
+ :midnightblue => 0x19197000,
663
+ :mintcream => 0xf5fffa00,
664
+ :mistyrose => 0xffe4e100,
665
+ :moccasin => 0xffe4b500,
666
+ :navajowhite => 0xffdead00,
667
+ :navy => 0x00008000,
668
+ :oldlace => 0xfdf5e600,
669
+ :olive => 0x80800000,
670
+ :olivedrab => 0x6b8e2300,
671
+ :orange => 0xffa50000,
672
+ :orangered => 0xff450000,
673
+ :orchid => 0xda70d600,
674
+ :palegoldenrod => 0xeee8aa00,
675
+ :palegreen => 0x98fb9800,
676
+ :paleturquoise => 0xafeeee00,
677
+ :palevioletred => 0xd8709300,
678
+ :papayawhip => 0xffefd500,
679
+ :peachpuff => 0xffdab900,
680
+ :peru => 0xcd853f00,
681
+ :pink => 0xffc0cb00,
682
+ :plum => 0xdda0dd00,
683
+ :powderblue => 0xb0e0e600,
684
+ :purple => 0x80008000,
685
+ :red => 0xff000000,
686
+ :rosybrown => 0xbc8f8f00,
687
+ :royalblue => 0x4169e100,
688
+ :saddlebrown => 0x8b451300,
689
+ :salmon => 0xfa807200,
690
+ :sandybrown => 0xf4a46000,
691
+ :seagreen => 0x2e8b5700,
692
+ :seashell => 0xfff5ee00,
693
+ :sienna => 0xa0522d00,
694
+ :silver => 0xc0c0c000,
695
+ :skyblue => 0x87ceeb00,
696
+ :slateblue => 0x6a5acd00,
697
+ :slategray => 0x70809000,
698
+ :slategrey => 0x70809000,
699
+ :snow => 0xfffafa00,
700
+ :springgreen => 0x00ff7f00,
701
+ :steelblue => 0x4682b400,
702
+ :tan => 0xd2b48c00,
703
+ :teal => 0x00808000,
704
+ :thistle => 0xd8bfd800,
705
+ :tomato => 0xff634700,
706
+ :turquoise => 0x40e0d000,
707
+ :violet => 0xee82ee00,
708
+ :wheat => 0xf5deb300,
709
+ :white => 0xffffff00,
710
+ :whitesmoke => 0xf5f5f500,
711
+ :yellow => 0xffff0000,
712
+ :yellowgreen => 0x9acd3200
662
713
  }
663
-
714
+
664
715
  # Gets a color value based on a HTML color name.
665
- #
666
- # The color name is flexible. E.g. <tt>'yellowgreen'</tt>, <tt>'Yellow green'</tt>,
667
- # <tt>'YellowGreen'</tt>, <tt>'YELLOW_GREEN'</tt> and <tt>:yellow_green</tt> will
668
- # all return the same color value.
669
- #
670
- # You can include a opacity level in the color name (e.g. <tt>'red @ 0.5'</tt>) or give
671
- # an explicit opacity value as second argument. If no opacity value is given, the color
672
- # will be fully opaque.
673
- #
674
- # @param [Symbol, String] color_name The color name. It may include an opacity specifier
675
- # like <tt>@ 0.8</tt> to set the color's opacity.
676
- # @param [Integer] opacity The opacity value for the color between 0 and 255. Overrides
677
- # any opacity value given in the color name.
716
+ #
717
+ # The color name is flexible. E.g. <tt>'yellowgreen'</tt>, <tt>'Yellow
718
+ # green'</tt>, <tt>'YellowGreen'</tt>, <tt>'YELLOW_GREEN'</tt> and
719
+ # <tt>:yellow_green</tt> will all return the same color value.
720
+ #
721
+ # You can include a opacity level in the color name (e.g. <tt>'red @
722
+ # 0.5'</tt>) or give an explicit opacity value as second argument. If no
723
+ # opacity value is given, the color will be fully opaque.
724
+ #
725
+ # @param [Symbol, String] color_name The color name. It may include an
726
+ # opacity specifier like <tt>@ 0.8</tt> to set the color's opacity.
727
+ # @param [Integer] opacity The opacity value for the color between 0 and
728
+ # 255. Overrides any opacity value given in the color name.
678
729
  # @return [Integer] The color value.
679
730
  # @raise [ChunkyPNG::Exception] If the color name was not recognized.
680
731
  def html_color(color_name, opacity = nil)
@@ -709,37 +760,45 @@ module ChunkyPNG
709
760
  when ChunkyPNG::COLOR_TRUECOLOR_ALPHA; 4
710
761
  when ChunkyPNG::COLOR_GRAYSCALE; 1
711
762
  when ChunkyPNG::COLOR_GRAYSCALE_ALPHA; 2
712
- else raise ChunkyPNG::NotSupported, "Don't know the numer of samples for this colormode: #{color_mode}!"
763
+ else raise ChunkyPNG::NotSupported, "Don't know the number of samples for this colormode: #{color_mode}!"
713
764
  end
714
765
  end
715
766
 
716
- # Returns the size in bytes of a pixel when it is stored using a given color mode.
717
- # @param [Integer] color_mode The color mode in which the pixels are stored.
767
+ # Returns the size in bytes of a pixel when it is stored using a given
768
+ # color mode.
769
+ #
770
+ # @param [Integer] color_mode The color mode in which the pixels are
771
+ # stored.
718
772
  # @return [Integer] The number of bytes used per pixel in a datastream.
719
773
  def pixel_bytesize(color_mode, depth = 8)
720
774
  return 1 if depth < 8
721
775
  (pixel_bitsize(color_mode, depth) + 7) >> 3
722
776
  end
723
-
724
- # Returns the size in bits of a pixel when it is stored using a given color mode.
725
- # @param [Integer] color_mode The color mode in which the pixels are stored.
777
+
778
+ # Returns the size in bits of a pixel when it is stored using a given color
779
+ # mode.
780
+ #
781
+ # @param [Integer] color_mode The color mode in which the pixels are
782
+ # stored.
726
783
  # @param [Integer] depth The color depth of the pixels.
727
784
  # @return [Integer] The number of bytes used per pixel in a datastream.
728
785
  def pixel_bitsize(color_mode, depth = 8)
729
786
  samples_per_pixel(color_mode) * depth
730
787
  end
731
-
788
+
732
789
  # Returns the number of bytes used per scanline.
733
- # @param [Integer] color_mode The color mode in which the pixels are stored.
790
+ # @param [Integer] color_mode The color mode in which the pixels are
791
+ # stored.
734
792
  # @param [Integer] depth The color depth of the pixels.
735
793
  # @param [Integer] width The number of pixels per scanline.
736
794
  # @return [Integer] The number of bytes used per scanline in a datastream.
737
795
  def scanline_bytesize(color_mode, depth, width)
738
796
  ((pixel_bitsize(color_mode, depth) * width) + 7) >> 3
739
797
  end
740
-
798
+
741
799
  # Returns the number of bytes used for an image pass
742
- # @param [Integer] color_mode The color mode in which the pixels are stored.
800
+ # @param [Integer] color_mode The color mode in which the pixels are
801
+ # stored.
743
802
  # @param [Integer] depth The color depth of the pixels.
744
803
  # @param [Integer] width The width of the image pass.
745
804
  # @param [Integer] width The height of the image pass.