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.
- data/README.rdoc +3 -0
- data/lib/chunky_png/canvas.rb +99 -62
- data/lib/chunky_png/canvas/drawing.rb +91 -68
- data/lib/chunky_png/canvas/operations.rb +155 -120
- data/lib/chunky_png/canvas/stream_importing.rb +2 -2
- data/lib/chunky_png/chunk.rb +111 -93
- data/lib/chunky_png/color.rb +312 -253
- data/lib/chunky_png/datastream.rb +1 -1
- data/lib/chunky_png/palette.rb +66 -49
- data/lib/chunky_png/version.rb +1 -1
- data/spec/chunky_png/canvas/stream_importing_spec.rb +9 -0
- data/spec/chunky_png/color_spec.rb +92 -68
- data/spec/resources/pixelstream.bgr +67 -0
- metadata +4 -2
@@ -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
|
data/lib/chunky_png/chunk.rb
CHANGED
@@ -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
|
-
#
|
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]
|
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]
|
33
|
-
# @param [String]
|
34
|
-
# @param [Integer]
|
35
|
-
# @raise [RuntimeError] An exception is raised if the found CRC value
|
36
|
-
#
|
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]
|
58
|
-
# @param [Hash]
|
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]
|
67
|
-
# @param [String]
|
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]
|
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]
|
98
|
-
# @param [String]
|
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
|
-
|
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
|
-
#
|
112
|
-
#
|
113
|
-
#
|
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
|
-
|
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
|
129
|
-
#
|
130
|
-
# @param [String]
|
131
|
-
# @
|
132
|
-
#
|
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
|
-
|
136
|
-
|
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
|
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].
|
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
|
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]
|
157
|
-
#
|
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
|
183
|
-
#
|
184
|
-
# * For
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
#
|
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
|
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)].
|
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
|
302
|
-
#
|
303
|
-
#
|
304
|
-
#
|
305
|
-
#
|
306
|
-
#
|
307
|
-
#
|
308
|
-
#
|
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
|
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
|
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,
|
325
|
-
'
|
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
|
data/lib/chunky_png/color.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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,
|
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,
|
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
|
245
|
-
# integer between 0 and 255. This method is used as a
|
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
|
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
|
282
|
-
# when the result is converted back to an integer. Because it is
|
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
|
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
|
-
|
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
|
352
|
-
# to the grayscale teint calcuated from the input color's R, G and B
|
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
|
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
|
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
|
382
|
-
#
|
383
|
-
#
|
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
|
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
|
400
|
-
#
|
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
|
-
|
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
|
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
|
413
|
-
# value can successfully decomposed with a given tolerance,
|
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
|
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
|
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
|
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
|
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
|
445
|
-
#
|
446
|
-
# @
|
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.
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
500
|
-
#
|
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 #
|
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
|
516
|
-
:antiquewhite
|
517
|
-
:aqua
|
518
|
-
:aquamarine
|
519
|
-
:azure
|
520
|
-
:beige
|
521
|
-
:bisque
|
522
|
-
:black
|
523
|
-
:blanchedalmond
|
524
|
-
:blue
|
525
|
-
:blueviolet
|
526
|
-
:brown
|
527
|
-
:burlywood
|
528
|
-
:cadetblue
|
529
|
-
:chartreuse
|
530
|
-
:chocolate
|
531
|
-
:coral
|
532
|
-
:cornflowerblue
|
533
|
-
:cornsilk
|
534
|
-
:crimson
|
535
|
-
:cyan
|
536
|
-
:darkblue
|
537
|
-
:darkcyan
|
538
|
-
:darkgoldenrod
|
539
|
-
:darkgray
|
540
|
-
:darkgrey
|
541
|
-
:darkgreen
|
542
|
-
:darkkhaki
|
543
|
-
:darkmagenta
|
544
|
-
:darkolivegreen
|
545
|
-
:darkorange
|
546
|
-
:darkorchid
|
547
|
-
:darkred
|
548
|
-
:darksalmon
|
549
|
-
:darkseagreen
|
550
|
-
:darkslateblue
|
551
|
-
:darkslategray
|
552
|
-
:darkslategrey
|
553
|
-
:darkturquoise
|
554
|
-
:darkviolet
|
555
|
-
:deeppink
|
556
|
-
:deepskyblue
|
557
|
-
:dimgray
|
558
|
-
:dimgrey
|
559
|
-
:dodgerblue
|
560
|
-
:firebrick
|
561
|
-
:floralwhite
|
562
|
-
:forestgreen
|
563
|
-
:fuchsia
|
564
|
-
:gainsboro
|
565
|
-
:ghostwhite
|
566
|
-
:gold
|
567
|
-
:goldenrod
|
568
|
-
:gray
|
569
|
-
:grey
|
570
|
-
:green
|
571
|
-
:greenyellow
|
572
|
-
:honeydew
|
573
|
-
:hotpink
|
574
|
-
:indianred
|
575
|
-
:indigo
|
576
|
-
:ivory
|
577
|
-
:khaki
|
578
|
-
:lavender
|
579
|
-
:lavenderblush
|
580
|
-
:lawngreen
|
581
|
-
:lemonchiffon
|
582
|
-
:lightblue
|
583
|
-
:lightcoral
|
584
|
-
:lightcyan
|
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
|
587
|
-
:lightgrey
|
588
|
-
:lightgreen
|
589
|
-
:lightpink
|
590
|
-
:lightsalmon
|
591
|
-
:lightseagreen
|
592
|
-
:lightskyblue
|
593
|
-
:lightslategray
|
594
|
-
:lightslategrey
|
595
|
-
:lightsteelblue
|
596
|
-
:lightyellow
|
597
|
-
:lime
|
598
|
-
:limegreen
|
599
|
-
:linen
|
600
|
-
:magenta
|
601
|
-
:maroon
|
602
|
-
:mediumaquamarine
|
603
|
-
:mediumblue
|
604
|
-
:mediumorchid
|
605
|
-
:mediumpurple
|
606
|
-
:mediumseagreen
|
607
|
-
:mediumslateblue
|
608
|
-
:mediumspringgreen
|
609
|
-
:mediumturquoise
|
610
|
-
:mediumvioletred
|
611
|
-
:midnightblue
|
612
|
-
:mintcream
|
613
|
-
:mistyrose
|
614
|
-
:moccasin
|
615
|
-
:navajowhite
|
616
|
-
:navy
|
617
|
-
:oldlace
|
618
|
-
:olive
|
619
|
-
:olivedrab
|
620
|
-
:orange
|
621
|
-
:orangered
|
622
|
-
:orchid
|
623
|
-
:palegoldenrod
|
624
|
-
:palegreen
|
625
|
-
:paleturquoise
|
626
|
-
:palevioletred
|
627
|
-
:papayawhip
|
628
|
-
:peachpuff
|
629
|
-
:peru
|
630
|
-
:pink
|
631
|
-
:plum
|
632
|
-
:powderblue
|
633
|
-
:purple
|
634
|
-
:red
|
635
|
-
:rosybrown
|
636
|
-
:royalblue
|
637
|
-
:saddlebrown
|
638
|
-
:salmon
|
639
|
-
:sandybrown
|
640
|
-
:seagreen
|
641
|
-
:seashell
|
642
|
-
:sienna
|
643
|
-
:silver
|
644
|
-
:skyblue
|
645
|
-
:slateblue
|
646
|
-
:slategray
|
647
|
-
:slategrey
|
648
|
-
:snow
|
649
|
-
:springgreen
|
650
|
-
:steelblue
|
651
|
-
:tan
|
652
|
-
:teal
|
653
|
-
:thistle
|
654
|
-
:tomato
|
655
|
-
:turquoise
|
656
|
-
:violet
|
657
|
-
:wheat
|
658
|
-
:white
|
659
|
-
:whitesmoke
|
660
|
-
:yellow
|
661
|
-
:yellowgreen
|
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
|
667
|
-
# <tt>'YellowGreen'</tt>, <tt>'YELLOW_GREEN'</tt> and
|
668
|
-
# all return the same color value.
|
669
|
-
#
|
670
|
-
# You can include a opacity level in the color name (e.g. <tt>'red @
|
671
|
-
# an explicit opacity value as second argument. If no
|
672
|
-
# will be fully opaque.
|
673
|
-
#
|
674
|
-
# @param [Symbol, String] color_name The color name. It may include an
|
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
|
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
|
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
|
717
|
-
#
|
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
|
725
|
-
#
|
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
|
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
|
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.
|