chunky_png 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|