chunky_png 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.infinity_test +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +13 -9
- data/chunky_png.gemspec +3 -3
- data/lib/chunky_png.rb +1 -1
- data/lib/chunky_png/canvas/png_encoding.rb +132 -22
- data/lib/chunky_png/palette.rb +14 -1
- data/spec/chunky_png/canvas/png_encoding_spec.rb +73 -10
- metadata +8 -8
data/.infinity_test
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
chunky_png (0.
|
4
|
+
chunky_png (0.12.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
8
8
|
specs:
|
9
|
+
bouncy-castle-java (1.5.0145.2)
|
9
10
|
diff-lcs (1.1.2)
|
11
|
+
jruby-openssl (0.7.2)
|
12
|
+
bouncy-castle-java
|
10
13
|
rake (0.8.7)
|
11
|
-
rspec (2.
|
12
|
-
rspec-core (~> 2.
|
13
|
-
rspec-expectations (~> 2.
|
14
|
-
rspec-mocks (~> 2.
|
15
|
-
rspec-core (2.1
|
16
|
-
rspec-expectations (2.
|
14
|
+
rspec (2.2.0)
|
15
|
+
rspec-core (~> 2.2)
|
16
|
+
rspec-expectations (~> 2.2)
|
17
|
+
rspec-mocks (~> 2.2)
|
18
|
+
rspec-core (2.2.1)
|
19
|
+
rspec-expectations (2.2.0)
|
17
20
|
diff-lcs (~> 1.1.2)
|
18
|
-
rspec-mocks (2.
|
21
|
+
rspec-mocks (2.2.0)
|
19
22
|
|
20
23
|
PLATFORMS
|
21
24
|
java
|
@@ -23,5 +26,6 @@ PLATFORMS
|
|
23
26
|
|
24
27
|
DEPENDENCIES
|
25
28
|
chunky_png!
|
29
|
+
jruby-openssl
|
26
30
|
rake
|
27
|
-
rspec (~> 2.
|
31
|
+
rspec (~> 2.2)
|
data/chunky_png.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
|
4
4
|
# Do not change the version and date fields by hand. This will be done
|
5
5
|
# automatically by the gem release script.
|
6
|
-
s.version = "0.
|
7
|
-
s.date = "2010-
|
6
|
+
s.version = "0.12.0"
|
7
|
+
s.date = "2010-12-12"
|
8
8
|
|
9
9
|
s.summary = "Pure ruby library for read/write, chunk-level access to PNG files"
|
10
10
|
s.description = <<-EOT
|
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.homepage = 'http://wiki.github.com/wvanbergen/chunky_png'
|
32
32
|
|
33
33
|
s.add_development_dependency('rake')
|
34
|
-
s.add_development_dependency('rspec', '~> 2.
|
34
|
+
s.add_development_dependency('rspec', '~> 2.2')
|
35
35
|
|
36
36
|
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
37
37
|
s.extra_rdoc_files = ['README.rdoc', 'BENCHMARKS.rdoc']
|
data/lib/chunky_png.rb
CHANGED
@@ -28,7 +28,7 @@ module ChunkyPNG
|
|
28
28
|
|
29
29
|
# The current version of ChunkyPNG. This value will be updated automatically
|
30
30
|
# by them gem:release rake task.
|
31
|
-
VERSION = "0.
|
31
|
+
VERSION = "0.12.0"
|
32
32
|
|
33
33
|
###################################################
|
34
34
|
# PNG international standard defined constants
|
@@ -64,20 +64,23 @@ module ChunkyPNG
|
|
64
64
|
# @option constraints [true, false] :interlace Whether to use interlacing.
|
65
65
|
# @option constraints [Fixnum] :compression The compression level for Zlib. This can be a
|
66
66
|
# value between 0 and 9, or a Zlib constant like Zlib::BEST_COMPRESSION.
|
67
|
+
# @option constraints [Fixnum] :bit_depth The bit depth to use. This option is only used
|
68
|
+
# for indexed images, in which case it overrides the determined minimal bit depth. For
|
69
|
+
# all the other color modes, a bit depth of 8 is used.
|
67
70
|
# @return [ChunkyPNG::Datastream] The PNG datastream containing the encoded canvas.
|
68
71
|
# @see ChunkyPNG::Canvas::PNGEncoding#determine_png_encoding
|
69
72
|
def to_datastream(constraints = {})
|
70
73
|
encoding = determine_png_encoding(constraints)
|
71
74
|
|
72
75
|
ds = Datastream.new
|
73
|
-
ds.header_chunk = Chunk::Header.new(:width => width, :height => height,
|
74
|
-
:color => encoding[:color_mode], :interlace => encoding[:interlace])
|
76
|
+
ds.header_chunk = Chunk::Header.new(:width => width, :height => height,
|
77
|
+
:color => encoding[:color_mode], :depth => encoding[:bit_depth], :interlace => encoding[:interlace])
|
75
78
|
|
76
79
|
if encoding[:color_mode] == ChunkyPNG::COLOR_INDEXED
|
77
80
|
ds.palette_chunk = encoding_palette.to_plte_chunk
|
78
81
|
ds.transparency_chunk = encoding_palette.to_trns_chunk unless encoding_palette.opaque?
|
79
82
|
end
|
80
|
-
data = encode_png_pixelstream(encoding[:color_mode], encoding[:interlace], encoding[:filtering])
|
83
|
+
data = encode_png_pixelstream(encoding[:color_mode], encoding[:bit_depth], encoding[:interlace], encoding[:filtering])
|
81
84
|
ds.data_chunks = Chunk::ImageData.split_in_chunks(data, encoding[:compression])
|
82
85
|
ds.end_chunk = Chunk::End.new
|
83
86
|
return ds
|
@@ -119,6 +122,14 @@ module ChunkyPNG
|
|
119
122
|
self.encoding_palette = self.palette
|
120
123
|
encoding[:color_mode] ||= encoding_palette.best_colormode
|
121
124
|
end
|
125
|
+
|
126
|
+
# Set the number of bits per color channel. This will always be 8 except for
|
127
|
+
# indexed image, which may also use lower bit depths
|
128
|
+
if encoding[:color_mode] == ChunkyPNG::COLOR_INDEXED
|
129
|
+
encoding[:bit_depth] = [encoding_palette.determine_bit_depth, encoding[:bit_depth] || 1].max
|
130
|
+
else
|
131
|
+
encoding[:bit_depth] = 8
|
132
|
+
end
|
122
133
|
|
123
134
|
# Use Zlib's default for compression unless otherwise provided.
|
124
135
|
encoding[:compression] ||= Zlib::DEFAULT_COMPRESSION
|
@@ -140,28 +151,30 @@ module ChunkyPNG
|
|
140
151
|
# Encodes the canvas according to the PNG format specification with a given color
|
141
152
|
# mode, possibly with interlacing.
|
142
153
|
# @param [Integer] color_mode The color mode to use for encoding.
|
154
|
+
# @param [Integer] bit_depth The bit depth of the image.
|
143
155
|
# @param [Integer] interlace The interlacing method to use.
|
144
156
|
# @return [String] The PNG encoded canvas as string.
|
145
|
-
def encode_png_pixelstream(color_mode = ChunkyPNG::COLOR_TRUECOLOR, interlace = ChunkyPNG::INTERLACING_NONE, filtering = ChunkyPNG::FILTER_NONE)
|
157
|
+
def encode_png_pixelstream(color_mode = ChunkyPNG::COLOR_TRUECOLOR, bit_depth = 8, interlace = ChunkyPNG::INTERLACING_NONE, filtering = ChunkyPNG::FILTER_NONE)
|
146
158
|
|
147
159
|
if color_mode == ChunkyPNG::COLOR_INDEXED && (encoding_palette.nil? || !encoding_palette.can_encode?)
|
148
160
|
raise ChunkyPNG::ExpectationFailed, "This palette is not suitable for encoding!"
|
149
161
|
end
|
150
162
|
|
151
163
|
case interlace
|
152
|
-
when ChunkyPNG::INTERLACING_NONE; encode_png_image_without_interlacing(color_mode, filtering)
|
153
|
-
when ChunkyPNG::INTERLACING_ADAM7; encode_png_image_with_interlacing(color_mode, filtering)
|
164
|
+
when ChunkyPNG::INTERLACING_NONE; encode_png_image_without_interlacing(color_mode, bit_depth, filtering)
|
165
|
+
when ChunkyPNG::INTERLACING_ADAM7; encode_png_image_with_interlacing(color_mode, bit_depth, filtering)
|
154
166
|
else raise ChunkyPNG::NotSupported, "Unknown interlacing method: #{interlace}!"
|
155
167
|
end
|
156
168
|
end
|
157
169
|
|
158
170
|
# Encodes the canvas according to the PNG format specification with a given color mode.
|
159
171
|
# @param [Integer] color_mode The color mode to use for encoding.
|
172
|
+
# @param [Integer] bit_depth The bit depth of the image.
|
160
173
|
# @param [Integer] filtering The filtering method to use.
|
161
174
|
# @return [String] The PNG encoded canvas as string.
|
162
|
-
def encode_png_image_without_interlacing(color_mode, filtering = ChunkyPNG::FILTER_NONE)
|
175
|
+
def encode_png_image_without_interlacing(color_mode, bit_depth = 8, filtering = ChunkyPNG::FILTER_NONE)
|
163
176
|
stream = ChunkyPNG::Datastream.empty_bytearray
|
164
|
-
encode_png_image_pass_to_stream(stream, color_mode, filtering)
|
177
|
+
encode_png_image_pass_to_stream(stream, color_mode, bit_depth, filtering)
|
165
178
|
stream
|
166
179
|
end
|
167
180
|
|
@@ -172,14 +185,15 @@ module ChunkyPNG
|
|
172
185
|
# one by one, concatenating the resulting strings.
|
173
186
|
#
|
174
187
|
# @param [Integer] color_mode The color mode to use for encoding.
|
188
|
+
# @param [Integer] bit_depth The bit depth of the image.
|
175
189
|
# @param [Integer] filtering The filtering method to use.
|
176
190
|
# @return [String] The PNG encoded canvas as string.
|
177
|
-
def encode_png_image_with_interlacing(color_mode, filtering = ChunkyPNG::FILTER_NONE)
|
191
|
+
def encode_png_image_with_interlacing(color_mode, bit_depth = 8, filtering = ChunkyPNG::FILTER_NONE)
|
178
192
|
stream = ChunkyPNG::Datastream.empty_bytearray
|
179
193
|
0.upto(6) do |pass|
|
180
194
|
subcanvas = self.class.adam7_extract_pass(pass, self)
|
181
195
|
subcanvas.encoding_palette = encoding_palette
|
182
|
-
subcanvas.encode_png_image_pass_to_stream(stream, color_mode, filtering)
|
196
|
+
subcanvas.encode_png_image_pass_to_stream(stream, color_mode, bit_depth, filtering)
|
183
197
|
end
|
184
198
|
stream
|
185
199
|
end
|
@@ -187,24 +201,16 @@ module ChunkyPNG
|
|
187
201
|
# Encodes the canvas to a stream, in a given color mode.
|
188
202
|
# @param [String] stream The stream to write to.
|
189
203
|
# @param [Integer] color_mode The color mode to use for encoding.
|
204
|
+
# @param [Integer] bit_depth The bit depth of the image.
|
190
205
|
# @param [Integer] filtering The filtering method to use.
|
191
|
-
def encode_png_image_pass_to_stream(stream, color_mode, filtering)
|
206
|
+
def encode_png_image_pass_to_stream(stream, color_mode, bit_depth, filtering)
|
192
207
|
|
193
208
|
start_pos = stream.bytesize
|
194
209
|
pixel_size = Color.pixel_bytesize(color_mode)
|
195
|
-
line_width =
|
196
|
-
|
197
|
-
# Encode the whole image without filtering
|
198
|
-
stream << case color_mode
|
199
|
-
when ChunkyPNG::COLOR_TRUECOLOR; pixels.pack(('x' + ('NX' * width)) * height)
|
200
|
-
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA; pixels.pack("xN#{width}" * height)
|
201
|
-
when ChunkyPNG::COLOR_INDEXED; pixels.map { |p| encoding_palette.index(p) }.pack("xC#{width}" * height)
|
202
|
-
when ChunkyPNG::COLOR_GRAYSCALE; pixels.map { |p| p >> 8 }.pack("xC#{width}" * height)
|
203
|
-
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA; pixels.pack("xn#{width}" * height)
|
204
|
-
else raise ChunkyPNG::NotSupported, "Cannot encode pixels for this mode: #{color_mode}!"
|
205
|
-
end
|
210
|
+
line_width = Color.scanline_bytesize(color_mode, bit_depth, width)
|
206
211
|
|
207
212
|
# Determine the filter method
|
213
|
+
encode_method = encode_png_pixels_to_scanline_method(color_mode, bit_depth)
|
208
214
|
filter_method = case filtering
|
209
215
|
when ChunkyPNG::FILTER_SUB; :encode_png_str_scanline_sub
|
210
216
|
when ChunkyPNG::FILTER_UP; :encode_png_str_scanline_up
|
@@ -213,6 +219,10 @@ module ChunkyPNG
|
|
213
219
|
else nil
|
214
220
|
end
|
215
221
|
|
222
|
+
0.upto(height - 1) do |y|
|
223
|
+
stream << send(encode_method, row(y))
|
224
|
+
end
|
225
|
+
|
216
226
|
# Now, apply filtering if any
|
217
227
|
if filter_method
|
218
228
|
(height - 1).downto(0) do |y|
|
@@ -222,6 +232,106 @@ module ChunkyPNG
|
|
222
232
|
end
|
223
233
|
end
|
224
234
|
end
|
235
|
+
|
236
|
+
# Encodes a line of pixels using 8-bit truecolor mode.
|
237
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
238
|
+
# @return [String] The encoded scanline as binary string
|
239
|
+
def encode_png_pixels_to_scanline_truecolor_8bit(pixels)
|
240
|
+
pixels.pack('x' + ('NX' * width))
|
241
|
+
end
|
242
|
+
|
243
|
+
# Encodes a line of pixels using 8-bit truecolor alpha mode.
|
244
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
245
|
+
# @return [String] The encoded scanline as binary string
|
246
|
+
def encode_png_pixels_to_scanline_truecolor_alpha_8bit(pixels)
|
247
|
+
pixels.pack("xN#{width}")
|
248
|
+
end
|
249
|
+
|
250
|
+
# Encodes a line of pixels using 1-bit indexed mode.
|
251
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
252
|
+
# @return [String] The encoded scanline as binary string
|
253
|
+
def encode_png_pixels_to_scanline_indexed_1bit(pixels)
|
254
|
+
chars = []
|
255
|
+
pixels.each_slice(8) do |p1, p2, p3, p4, p5, p6, p7, p8|
|
256
|
+
chars << ((encoding_palette.index(p1) << 7) |
|
257
|
+
(encoding_palette.index(p2) << 6) |
|
258
|
+
(encoding_palette.index(p3) << 5) |
|
259
|
+
(encoding_palette.index(p4) << 4) |
|
260
|
+
(encoding_palette.index(p5) << 3) |
|
261
|
+
(encoding_palette.index(p6) << 2) |
|
262
|
+
(encoding_palette.index(p7) << 1) |
|
263
|
+
(encoding_palette.index(p8)))
|
264
|
+
end
|
265
|
+
chars.pack('xC*')
|
266
|
+
end
|
267
|
+
|
268
|
+
# Encodes a line of pixels using 2-bit indexed mode.
|
269
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
270
|
+
# @return [String] The encoded scanline as binary string
|
271
|
+
def encode_png_pixels_to_scanline_indexed_2bit(pixels)
|
272
|
+
chars = []
|
273
|
+
pixels.each_slice(4) do |p1, p2, p3, p4|
|
274
|
+
chars << ((encoding_palette.index(p1) << 6) |
|
275
|
+
(encoding_palette.index(p2) << 4) |
|
276
|
+
(encoding_palette.index(p3) << 2) |
|
277
|
+
(encoding_palette.index(p4)))
|
278
|
+
end
|
279
|
+
chars.pack('xC*')
|
280
|
+
end
|
281
|
+
|
282
|
+
# Encodes a line of pixels using 4-bit indexed mode.
|
283
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
284
|
+
# @return [String] The encoded scanline as binary string
|
285
|
+
def encode_png_pixels_to_scanline_indexed_4bit(pixels)
|
286
|
+
chars = []
|
287
|
+
pixels.each_slice(2) do |p1, p2|
|
288
|
+
chars << ((encoding_palette.index(p1) << 4) | (encoding_palette.index(p2)))
|
289
|
+
end
|
290
|
+
chars.pack('xC*')
|
291
|
+
end
|
292
|
+
|
293
|
+
# Encodes a line of pixels using 8-bit indexed mode.
|
294
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
295
|
+
# @return [String] The encoded scanline as binary string
|
296
|
+
def encode_png_pixels_to_scanline_indexed_8bit(pixels)
|
297
|
+
pixels.map { |p| encoding_palette.index(p) }.pack("xC#{width}")
|
298
|
+
end
|
299
|
+
|
300
|
+
# Encodes a line of pixels using 8-bit grayscale mode.
|
301
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
302
|
+
# @return [String] The encoded scanline as binary string
|
303
|
+
def encode_png_pixels_to_scanline_grayscale_8bit(pixels)
|
304
|
+
pixels.map { |p| p >> 8 }.pack("xC#{width}")
|
305
|
+
end
|
306
|
+
|
307
|
+
# Encodes a line of pixels using 8-bit grayscale alpha mode.
|
308
|
+
# @param [Array<Integer>] pixels A row of pixels of the original image.
|
309
|
+
# @return [String] The encoded scanline as binary string
|
310
|
+
def encode_png_pixels_to_scanline_grayscale_alpha_8bit(pixels)
|
311
|
+
pixels.pack("xn#{width}")
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
# Returns the method name to use to decode scanlines into pixels.
|
316
|
+
# @param [Integer] color_mode The color mode of the image.
|
317
|
+
# @param [Integer] depth The bit depth of the image.
|
318
|
+
# @return [Symbol] The method name to use for decoding, to be called on the canvas class.
|
319
|
+
# @raise [ChunkyPNG::NotSupported] when the color_mode and/or bit depth is not supported.
|
320
|
+
def encode_png_pixels_to_scanline_method(color_mode, depth)
|
321
|
+
encoder_method = case color_mode
|
322
|
+
when ChunkyPNG::COLOR_TRUECOLOR; :"encode_png_pixels_to_scanline_truecolor_#{depth}bit"
|
323
|
+
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA; :"encode_png_pixels_to_scanline_truecolor_alpha_#{depth}bit"
|
324
|
+
when ChunkyPNG::COLOR_INDEXED; :"encode_png_pixels_to_scanline_indexed_#{depth}bit"
|
325
|
+
when ChunkyPNG::COLOR_GRAYSCALE; :"encode_png_pixels_to_scanline_grayscale_#{depth}bit"
|
326
|
+
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA; :"encode_png_pixels_to_scanline_grayscale_alpha_#{depth}bit"
|
327
|
+
else nil
|
328
|
+
end
|
329
|
+
|
330
|
+
raise ChunkyPNG::NotSupported, "No encoder found for color mode #{color_mode} and #{depth}-bit depth!" unless respond_to?(encoder_method)
|
331
|
+
encoder_method
|
332
|
+
end
|
333
|
+
|
334
|
+
|
225
335
|
|
226
336
|
# Encodes a scanline of a pixelstream without filtering. This is a no-op.
|
227
337
|
# @param [String] stream The pixelstream to work on. This string will be modified.
|
data/lib/chunky_png/palette.rb
CHANGED
@@ -130,7 +130,7 @@ module ChunkyPNG
|
|
130
130
|
# @return [Integer] The 0-based position of the color in the palette.
|
131
131
|
# @see ChunkyPNG::Palette#can_encode?
|
132
132
|
def index(color)
|
133
|
-
@encoding_map[color]
|
133
|
+
color.nil? ? 0 : @encoding_map[color]
|
134
134
|
end
|
135
135
|
|
136
136
|
# Creates a tRNS chunk that corresponds with this palette to store the
|
@@ -183,5 +183,18 @@ module ChunkyPNG
|
|
183
183
|
ChunkyPNG::COLOR_TRUECOLOR_ALPHA
|
184
184
|
end
|
185
185
|
end
|
186
|
+
|
187
|
+
# Determines the minimal bit depth required for an indexed image
|
188
|
+
# @return [Integer] Number of bits per pixel, i.e. 1, 2, 4 or 8, or nil if this
|
189
|
+
# image cannot be saved as an indexed image.
|
190
|
+
def determine_bit_depth
|
191
|
+
case size
|
192
|
+
when 1..2; 1
|
193
|
+
when 3..4; 2
|
194
|
+
when 5..16; 4
|
195
|
+
when 17..256; 8
|
196
|
+
else nil
|
197
|
+
end
|
198
|
+
end
|
186
199
|
end
|
187
200
|
end
|
@@ -19,6 +19,46 @@ describe ChunkyPNG::Canvas::PNGEncoding do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should encode an image with 2 colors using 1-bit indexed color mode" do
|
23
|
+
@canvas = ChunkyPNG::Canvas.from_file(png_suite_file('basic', 'basn3p01.png'))
|
24
|
+
ds = ChunkyPNG::Datastream.from_blob(@canvas.to_blob)
|
25
|
+
ds.header_chunk.color.should == ChunkyPNG::COLOR_INDEXED
|
26
|
+
ds.header_chunk.depth.should == 1
|
27
|
+
@canvas.should == ChunkyPNG::Canvas.from_datastream(ds)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should encode an image with 4 colors using 2-bit indexed color mode" do
|
31
|
+
@canvas = ChunkyPNG::Canvas.from_file(png_suite_file('basic', 'basn3p02.png'))
|
32
|
+
ds = ChunkyPNG::Datastream.from_blob(@canvas.to_blob)
|
33
|
+
ds.header_chunk.color.should == ChunkyPNG::COLOR_INDEXED
|
34
|
+
ds.header_chunk.depth.should == 2
|
35
|
+
@canvas.should == ChunkyPNG::Canvas.from_datastream(ds)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should encode an image with 16 colors using 4-bit indexed color mode" do
|
39
|
+
@canvas = ChunkyPNG::Canvas.from_file(png_suite_file('basic', 'basn3p04.png'))
|
40
|
+
ds = ChunkyPNG::Datastream.from_blob(@canvas.to_blob)
|
41
|
+
ds.header_chunk.color.should == ChunkyPNG::COLOR_INDEXED
|
42
|
+
ds.header_chunk.depth.should == 4
|
43
|
+
@canvas.should == ChunkyPNG::Canvas.from_datastream(ds)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should encode an image with 256 colors using 8-bit indexed color mode" do
|
47
|
+
@canvas = ChunkyPNG::Canvas.from_file(png_suite_file('basic', 'basn3p08.png'))
|
48
|
+
ds = ChunkyPNG::Datastream.from_blob(@canvas.to_blob)
|
49
|
+
ds.header_chunk.color.should == ChunkyPNG::COLOR_INDEXED
|
50
|
+
ds.header_chunk.depth.should == 8
|
51
|
+
@canvas.should == ChunkyPNG::Canvas.from_datastream(ds)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should use a higher bit depth than necessary if requested" do
|
55
|
+
@canvas = ChunkyPNG::Canvas.from_file(png_suite_file('basic', 'basn3p01.png'))
|
56
|
+
ds = ChunkyPNG::Datastream.from_blob(@canvas.to_blob(:bit_depth => 4))
|
57
|
+
ds.header_chunk.color.should == ChunkyPNG::COLOR_INDEXED
|
58
|
+
ds.header_chunk.depth.should == 4
|
59
|
+
@canvas.should == ChunkyPNG::Canvas.from_datastream(ds)
|
60
|
+
end
|
61
|
+
|
22
62
|
it "should encode an image with interlacing correctly" do
|
23
63
|
input_canvas = ChunkyPNG::Canvas.from_file(resource_file('operations.png'))
|
24
64
|
filename = resource_file("_tmp_interlaced.png")
|
@@ -68,42 +108,65 @@ describe ChunkyPNG::Canvas::PNGEncoding do
|
|
68
108
|
end
|
69
109
|
|
70
110
|
describe '#encode_png_image_pass_to_stream' do
|
71
|
-
before
|
111
|
+
before do
|
112
|
+
@canvas = ChunkyPNG::Canvas.new(2, 2, ChunkyPNG::Color.rgba(1, 2, 3, 4))
|
113
|
+
@palette_mock = mock('Palette')
|
114
|
+
@palette_mock.stub(:index).with(ChunkyPNG::Color.rgba(1, 2, 3, 4)).and_return(1)
|
115
|
+
@palette_mock.stub(:index).with(nil).and_return(0)
|
116
|
+
end
|
72
117
|
|
73
118
|
it "should encode using RGBA / no filtering mode correctly" do
|
74
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, ChunkyPNG::FILTER_NONE)
|
119
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8, ChunkyPNG::FILTER_NONE)
|
75
120
|
stream.should == "\0\1\2\3\4\1\2\3\4\0\1\2\3\4\1\2\3\4"
|
76
121
|
end
|
77
122
|
|
78
123
|
it "should encode using RGBA / SUB filtering mode correctly" do
|
79
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, ChunkyPNG::FILTER_SUB)
|
124
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8, ChunkyPNG::FILTER_SUB)
|
80
125
|
stream.should == "\1\1\2\3\4\0\0\0\0\1\1\2\3\4\0\0\0\0"
|
81
126
|
end
|
82
127
|
|
83
128
|
it "should encode using RGBA / UP filtering mode correctly" do
|
84
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, ChunkyPNG::FILTER_UP)
|
129
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8, ChunkyPNG::FILTER_UP)
|
85
130
|
stream.should == "\2\1\2\3\4\1\2\3\4\2\0\0\0\0\0\0\0\0"
|
86
131
|
end
|
87
132
|
|
88
133
|
it "should encode using RGBA / AVERAGE filtering mode correctly" do
|
89
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, ChunkyPNG::FILTER_AVERAGE)
|
134
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8, ChunkyPNG::FILTER_AVERAGE)
|
90
135
|
stream.should == "\3\1\2\3\4\1\1\2\2\3\1\1\2\2\0\0\0\0"
|
91
136
|
end
|
92
137
|
|
93
138
|
it "should encode using RGB / no filtering mode correctly" do
|
94
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_NONE)
|
139
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_TRUECOLOR, 8, ChunkyPNG::FILTER_NONE)
|
95
140
|
stream.should == "\0\1\2\3\1\2\3\0\1\2\3\1\2\3"
|
96
141
|
end
|
97
142
|
|
98
143
|
it "should encode using indexed / no filtering mode correctly" do
|
99
|
-
@canvas.stub(:encoding_palette).and_return(
|
100
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, ChunkyPNG::FILTER_NONE)
|
144
|
+
@canvas.stub(:encoding_palette).and_return(@palette_mock)
|
145
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, 8, ChunkyPNG::FILTER_NONE)
|
101
146
|
stream.should == "\0\1\1\0\1\1"
|
102
147
|
end
|
148
|
+
|
149
|
+
it "should encode using 1-bit indexed / no filtering mode correctly" do
|
150
|
+
@canvas.stub(:encoding_palette).and_return(@palette_mock)
|
151
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, 1, ChunkyPNG::FILTER_NONE)
|
152
|
+
stream.should == "\0\xc0\0\xc0"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should encode using 2-bit indexed / no filtering mode correctly" do
|
156
|
+
@canvas.stub(:encoding_palette).and_return(@palette_mock)
|
157
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, 2, ChunkyPNG::FILTER_NONE)
|
158
|
+
stream.should == "\x00\x50\x00\x50"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should encode using 4-bit indexed / no filtering mode correctly" do
|
162
|
+
@canvas.stub(:encoding_palette).and_return(@palette_mock)
|
163
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, 4, ChunkyPNG::FILTER_NONE)
|
164
|
+
stream.should == "\0\x11\0\x11"
|
165
|
+
end
|
103
166
|
|
104
167
|
it "should encode using indexed / PAETH filtering mode correctly" do
|
105
|
-
@canvas.stub(:encoding_palette).and_return(
|
106
|
-
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, ChunkyPNG::FILTER_PAETH)
|
168
|
+
@canvas.stub(:encoding_palette).and_return(@palette_mock)
|
169
|
+
@canvas.encode_png_image_pass_to_stream(stream = ChunkyPNG::Datastream.empty_bytearray, ChunkyPNG::COLOR_INDEXED, 8, ChunkyPNG::FILTER_PAETH)
|
107
170
|
stream.should == "\4\1\0\4\0\0"
|
108
171
|
end
|
109
172
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 12
|
8
|
+
- 0
|
9
|
+
version: 0.12.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Willem van Bergen
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-12-12 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -39,8 +39,8 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
segments:
|
41
41
|
- 2
|
42
|
-
-
|
43
|
-
version: "2.
|
42
|
+
- 2
|
43
|
+
version: "2.2"
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
46
|
version_requirements: *id002
|
@@ -360,7 +360,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
360
360
|
requirements:
|
361
361
|
- - ">="
|
362
362
|
- !ruby/object:Gem::Version
|
363
|
-
hash:
|
363
|
+
hash: 1966366750719945677
|
364
364
|
segments:
|
365
365
|
- 0
|
366
366
|
version: "0"
|
@@ -369,7 +369,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
369
369
|
requirements:
|
370
370
|
- - ">="
|
371
371
|
- !ruby/object:Gem::Version
|
372
|
-
hash:
|
372
|
+
hash: 1966366750719945677
|
373
373
|
segments:
|
374
374
|
- 0
|
375
375
|
version: "0"
|