chunky_png 0.0.5 → 0.5.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/README.rdoc +20 -10
- data/chunky_png.gemspec +18 -6
- data/lib/chunky_png.rb +11 -28
- data/lib/chunky_png/canvas.rb +186 -0
- data/lib/chunky_png/canvas/adam7_interlacing.rb +53 -0
- data/lib/chunky_png/canvas/drawing.rb +8 -0
- data/lib/chunky_png/{pixel_matrix → canvas}/operations.rb +12 -12
- data/lib/chunky_png/canvas/png_decoding.rb +145 -0
- data/lib/chunky_png/canvas/png_encoding.rb +182 -0
- data/lib/chunky_png/chunk.rb +101 -23
- data/lib/chunky_png/color.rb +307 -0
- data/lib/chunky_png/datastream.rb +143 -45
- data/lib/chunky_png/image.rb +31 -30
- data/lib/chunky_png/palette.rb +49 -47
- data/lib/chunky_png/rmagick.rb +43 -0
- data/spec/chunky_png/canvas/adam7_interlacing_spec.rb +108 -0
- data/spec/chunky_png/canvas/png_decoding_spec.rb +81 -0
- data/spec/chunky_png/canvas/png_encoding_spec.rb +70 -0
- data/spec/chunky_png/canvas_spec.rb +71 -0
- data/spec/chunky_png/color_spec.rb +104 -0
- data/spec/chunky_png/datastream_spec.rb +32 -0
- data/spec/chunky_png/image_spec.rb +25 -0
- data/spec/chunky_png/rmagick_spec.rb +21 -0
- data/spec/{integration/image_spec.rb → chunky_png_spec.rb} +14 -8
- data/spec/resources/composited.png +0 -0
- data/spec/resources/cropped.png +0 -0
- data/spec/resources/damaged_chunk.png +0 -0
- data/spec/resources/damaged_signature.png +13 -0
- data/spec/resources/pixelstream.rgba +67 -0
- data/spec/resources/replaced.png +0 -0
- data/spec/resources/text_chunk.png +0 -0
- data/spec/resources/ztxt_chunk.png +0 -0
- data/spec/spec_helper.rb +8 -5
- data/tasks/github-gem.rake +1 -1
- metadata +37 -18
- data/lib/chunky_png/pixel.rb +0 -272
- data/lib/chunky_png/pixel_matrix.rb +0 -136
- data/lib/chunky_png/pixel_matrix/decoding.rb +0 -159
- data/lib/chunky_png/pixel_matrix/encoding.rb +0 -89
- data/spec/unit/decoding_spec.rb +0 -83
- data/spec/unit/encoding_spec.rb +0 -27
- data/spec/unit/pixel_matrix_spec.rb +0 -93
- data/spec/unit/pixel_spec.rb +0 -47
@@ -1,159 +0,0 @@
|
|
1
|
-
module ChunkyPNG
|
2
|
-
class PixelMatrix
|
3
|
-
module Decoding
|
4
|
-
|
5
|
-
def decode(ds)
|
6
|
-
raise "Only 8-bit color depth is currently supported by ChunkyPNG!" unless ds.header_chunk.depth == 8
|
7
|
-
|
8
|
-
stream = Zlib::Inflate.inflate(ds.data_chunks.map(&:content).join(''))
|
9
|
-
width = ds.header_chunk.width
|
10
|
-
height = ds.header_chunk.height
|
11
|
-
color_mode = ds.header_chunk.color
|
12
|
-
interlace = ds.header_chunk.interlace
|
13
|
-
palette = ChunkyPNG::Palette.from_chunks(ds.palette_chunk, ds.transparency_chunk)
|
14
|
-
decode_pixelstream(stream, width, height, color_mode, palette, interlace)
|
15
|
-
end
|
16
|
-
|
17
|
-
def decode_pixelstream(stream, width, height, color_mode = ChunkyPNG::COLOR_TRUECOLOR, palette = nil, interlace = ChunkyPNG::INTERLACING_NONE)
|
18
|
-
raise "This palette is not suitable for decoding!" if palette && !palette.can_decode?
|
19
|
-
|
20
|
-
pixel_size = Pixel.bytesize(color_mode)
|
21
|
-
pixel_decoder = case color_mode
|
22
|
-
when ChunkyPNG::COLOR_TRUECOLOR then lambda { |bytes| ChunkyPNG::Pixel.rgb(*bytes) }
|
23
|
-
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA then lambda { |bytes| ChunkyPNG::Pixel.rgba(*bytes) }
|
24
|
-
when ChunkyPNG::COLOR_INDEXED then lambda { |bytes| palette[bytes.first] }
|
25
|
-
when ChunkyPNG::COLOR_GRAYSCALE then lambda { |bytes| ChunkyPNG::Pixel.grayscale(*bytes) }
|
26
|
-
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA then lambda { |bytes| ChunkyPNG::Pixel.grayscale(*bytes) }
|
27
|
-
else raise "No suitable pixel decoder found for color mode #{color_mode}!"
|
28
|
-
end
|
29
|
-
|
30
|
-
pixels = case interlace
|
31
|
-
when ChunkyPNG::INTERLACING_NONE then decode_interlacing_none(stream, width, height, pixel_size, pixel_decoder)
|
32
|
-
when ChunkyPNG::INTERLACING_ADAM7 then decode_interlacing_adam7(stream, width, height, pixel_size, pixel_decoder)
|
33
|
-
else raise "Don't know how the handle interlacing method #{interlace}!"
|
34
|
-
end
|
35
|
-
|
36
|
-
return ChunkyPNG::PixelMatrix.new(width, height, pixels)
|
37
|
-
end
|
38
|
-
|
39
|
-
protected
|
40
|
-
|
41
|
-
def decode_image_pass(stream, width, height, pixel_size, pixel_decoder, start_pos = 0)
|
42
|
-
pixels = []
|
43
|
-
decoded_bytes = Array.new(width * pixel_size, 0)
|
44
|
-
height.times do |line_no|
|
45
|
-
|
46
|
-
if width > 0
|
47
|
-
|
48
|
-
# get bytes of scanline
|
49
|
-
position = start_pos + line_no * (width * pixel_size + 1)
|
50
|
-
line_length = width * pixel_size
|
51
|
-
bytes = stream.unpack("@#{position}CC#{line_length}")
|
52
|
-
filter = bytes.shift
|
53
|
-
decoded_bytes = decode_scanline(filter, bytes, decoded_bytes, pixel_size)
|
54
|
-
|
55
|
-
# decode bytes into colors
|
56
|
-
decoded_bytes.each_slice(pixel_size) { |bytes| pixels << pixel_decoder.call(bytes) }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
pixels
|
60
|
-
end
|
61
|
-
|
62
|
-
def decode_interlacing_none(stream, width, height, pixel_size, pixel_decoder)
|
63
|
-
raise "Invalid stream length!" unless stream.length == width * height * pixel_size + height
|
64
|
-
decode_image_pass(stream, width, height, pixel_size, pixel_decoder)
|
65
|
-
end
|
66
|
-
|
67
|
-
def decode_interlacing_adam7(stream, width, height, pixel_size, pixel_decoder)
|
68
|
-
start_pos = 0
|
69
|
-
sub_matrices = adam7_pass_sizes(width, height).map do |(pass_width, pass_height)|
|
70
|
-
pixels = decode_image_pass(stream, pass_width, pass_height, pixel_size, pixel_decoder, start_pos)
|
71
|
-
start_pos += (pass_width * pass_height * pixel_size) + pass_height
|
72
|
-
[pass_width, pass_height, pixels]
|
73
|
-
end
|
74
|
-
|
75
|
-
pixels = Array.new(width * height, ChunkyPNG::Pixel::TRANSPARENT)
|
76
|
-
0.upto(6) { |pass| adam7_merge_pass(pass, width, height, pixels, *sub_matrices[pass]) }
|
77
|
-
pixels
|
78
|
-
end
|
79
|
-
|
80
|
-
def adam7_multiplier_offset(pass)
|
81
|
-
{
|
82
|
-
:x_multiplier => 8 >> (pass >> 1),
|
83
|
-
:x_offset => (pass & 1 == 0) ? 0 : 8 >> ((pass + 1) >> 1),
|
84
|
-
:y_multiplier => pass == 0 ? 8 : 8 >> ((pass - 1) >> 1),
|
85
|
-
:y_offset => (pass == 0 || pass & 1 == 1) ? 0 : 8 >> (pass >> 1)
|
86
|
-
}
|
87
|
-
end
|
88
|
-
|
89
|
-
def adam7_merge_pass(pass, width, height, pixels, sm_width, sm_height, sm_pixels)
|
90
|
-
m_o = adam7_multiplier_offset(pass)
|
91
|
-
0.upto(sm_height - 1) do |y|
|
92
|
-
0.upto(sm_width - 1) do |x|
|
93
|
-
new_x = x * m_o[:x_multiplier] + m_o[:x_offset]
|
94
|
-
new_y = y * m_o[:y_multiplier] + m_o[:y_offset]
|
95
|
-
pixels[width * new_y + new_x] = sm_pixels[sm_width * y + x]
|
96
|
-
end
|
97
|
-
end
|
98
|
-
pixels
|
99
|
-
end
|
100
|
-
|
101
|
-
def adam7_pass_sizes(width, height)
|
102
|
-
(0...7).map do |pass|
|
103
|
-
m_o = adam7_multiplier_offset(pass)
|
104
|
-
[ ((width - m_o[:x_offset] ) / m_o[:x_multiplier].to_f).ceil,
|
105
|
-
((height - m_o[:y_offset] ) / m_o[:y_multiplier].to_f).ceil,]
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def decode_scanline(filter, bytes, previous_bytes, pixelsize = 3)
|
110
|
-
case filter
|
111
|
-
when ChunkyPNG::FILTER_NONE then decode_scanline_none( bytes, previous_bytes, pixelsize)
|
112
|
-
when ChunkyPNG::FILTER_SUB then decode_scanline_sub( bytes, previous_bytes, pixelsize)
|
113
|
-
when ChunkyPNG::FILTER_UP then decode_scanline_up( bytes, previous_bytes, pixelsize)
|
114
|
-
when ChunkyPNG::FILTER_AVERAGE then decode_scanline_average( bytes, previous_bytes, pixelsize)
|
115
|
-
when ChunkyPNG::FILTER_PAETH then decode_scanline_paeth( bytes, previous_bytes, pixelsize)
|
116
|
-
else raise "Unknown filter type"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def decode_scanline_none(bytes, previous_bytes, pixelsize = 3)
|
121
|
-
bytes
|
122
|
-
end
|
123
|
-
|
124
|
-
def decode_scanline_sub(bytes, previous_bytes, pixelsize = 3)
|
125
|
-
bytes.each_with_index { |b, i| bytes[i] = (b + (i >= pixelsize ? bytes[i-pixelsize] : 0)) % 256 }
|
126
|
-
bytes
|
127
|
-
end
|
128
|
-
|
129
|
-
def decode_scanline_up(bytes, previous_bytes, pixelsize = 3)
|
130
|
-
bytes.each_with_index { |b, i| bytes[i] = (b + previous_bytes[i]) % 256 }
|
131
|
-
bytes
|
132
|
-
end
|
133
|
-
|
134
|
-
def decode_scanline_average(bytes, previous_bytes, pixelsize = 3)
|
135
|
-
bytes.each_with_index do |byte, i|
|
136
|
-
a = (i >= pixelsize) ? bytes[i - pixelsize] : 0
|
137
|
-
b = previous_bytes[i]
|
138
|
-
bytes[i] = (byte + (a + b / 2).floor) % 256
|
139
|
-
end
|
140
|
-
bytes
|
141
|
-
end
|
142
|
-
|
143
|
-
def decode_scanline_paeth(bytes, previous_bytes, pixelsize = 3)
|
144
|
-
bytes.each_with_index do |byte, i|
|
145
|
-
a = (i >= pixelsize) ? bytes[i - pixelsize] : 0
|
146
|
-
b = previous_bytes[i]
|
147
|
-
c = (i >= pixelsize) ? previous_bytes[i - pixelsize] : 0
|
148
|
-
p = a + b - c
|
149
|
-
pa = (p - a).abs
|
150
|
-
pb = (p - b).abs
|
151
|
-
pc = (p - c).abs
|
152
|
-
pr = (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c)
|
153
|
-
bytes[i] = (byte + pr) % 256
|
154
|
-
end
|
155
|
-
bytes
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
module ChunkyPNG
|
2
|
-
class PixelMatrix
|
3
|
-
module Encoding
|
4
|
-
|
5
|
-
def encode(constraints = {})
|
6
|
-
encoding = determine_encoding(constraints)
|
7
|
-
result = {}
|
8
|
-
result[:header] = { :width => width, :height => height, :color => encoding[:color_mode] }
|
9
|
-
|
10
|
-
if encoding[:color_mode] == ChunkyPNG::COLOR_INDEXED
|
11
|
-
result[:palette_chunk] = encoding[:palette].to_plte_chunk
|
12
|
-
result[:transparency_chunk] = encoding[:palette].to_trns_chunk unless encoding[:palette].opaque?
|
13
|
-
end
|
14
|
-
|
15
|
-
result[:pixelstream] = encode_pixelstream(encoding[:color_mode], encoding[:palette])
|
16
|
-
return result
|
17
|
-
end
|
18
|
-
|
19
|
-
protected
|
20
|
-
|
21
|
-
def determine_encoding(constraints = {})
|
22
|
-
encoding = constraints
|
23
|
-
encoding[:palette] ||= palette
|
24
|
-
encoding[:color_mode] ||= encoding[:palette].best_colormode
|
25
|
-
return encoding
|
26
|
-
end
|
27
|
-
|
28
|
-
def encode_pixelstream(color_mode = ChunkyPNG::COLOR_TRUECOLOR, palette = nil)
|
29
|
-
|
30
|
-
pixel_encoder = case color_mode
|
31
|
-
when ChunkyPNG::COLOR_TRUECOLOR then lambda { |pixel| pixel.to_truecolor_bytes }
|
32
|
-
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA then lambda { |pixel| pixel.to_truecolor_alpha_bytes }
|
33
|
-
when ChunkyPNG::COLOR_INDEXED then lambda { |pixel| pixel.to_indexed_bytes(palette) }
|
34
|
-
when ChunkyPNG::COLOR_GRAYSCALE then lambda { |pixel| pixel.to_grayscale_bytes }
|
35
|
-
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA then lambda { |pixel| pixel.to_grayscale_alpha_bytes }
|
36
|
-
else raise "Cannot encode pixels for this mode: #{color_mode}!"
|
37
|
-
end
|
38
|
-
|
39
|
-
if color_mode == ChunkyPNG::COLOR_INDEXED && !palette.can_encode?
|
40
|
-
raise "This palette is not suitable for encoding!"
|
41
|
-
end
|
42
|
-
|
43
|
-
pixel_size = Pixel.bytesize(color_mode)
|
44
|
-
|
45
|
-
stream = ""
|
46
|
-
previous_bytes = Array.new(pixel_size * width, 0)
|
47
|
-
each_scanline do |line|
|
48
|
-
unencoded_bytes = line.map(&pixel_encoder).flatten
|
49
|
-
stream << encode_scanline_up(unencoded_bytes, previous_bytes, pixel_size).pack('C*')
|
50
|
-
previous_bytes = unencoded_bytes
|
51
|
-
end
|
52
|
-
return stream
|
53
|
-
end
|
54
|
-
|
55
|
-
def encode_scanline(filter, bytes, previous_bytes = nil, pixelsize = 3)
|
56
|
-
case filter
|
57
|
-
when ChunkyPNG::FILTER_NONE then encode_scanline_none( bytes, previous_bytes, pixelsize)
|
58
|
-
when ChunkyPNG::FILTER_SUB then encode_scanline_sub( bytes, previous_bytes, pixelsize)
|
59
|
-
when ChunkyPNG::FILTER_UP then encode_scanline_up( bytes, previous_bytes, pixelsize)
|
60
|
-
when ChunkyPNG::FILTER_AVERAGE then raise "Average filter are not yet supported!"
|
61
|
-
when ChunkyPNG::FILTER_PAETH then raise "Paeth filter are not yet supported!"
|
62
|
-
else raise "Unknown filter type"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def encode_scanline_none(original_bytes, previous_bytes = nil, pixelsize = 3)
|
67
|
-
[ChunkyPNG::FILTER_NONE] + original_bytes
|
68
|
-
end
|
69
|
-
|
70
|
-
def encode_scanline_sub(original_bytes, previous_bytes = nil, pixelsize = 3)
|
71
|
-
encoded_bytes = []
|
72
|
-
original_bytes.length.times do |index|
|
73
|
-
a = (index >= pixelsize) ? original_bytes[index - pixelsize] : 0
|
74
|
-
encoded_bytes[index] = (original_bytes[index] - a) % 256
|
75
|
-
end
|
76
|
-
[ChunkyPNG::FILTER_SUB] + encoded_bytes
|
77
|
-
end
|
78
|
-
|
79
|
-
def encode_scanline_up(original_bytes, previous_bytes, pixelsize = 3)
|
80
|
-
encoded_bytes = []
|
81
|
-
original_bytes.length.times do |index|
|
82
|
-
b = previous_bytes[index]
|
83
|
-
encoded_bytes[index] = (original_bytes[index] - b) % 256
|
84
|
-
end
|
85
|
-
[ChunkyPNG::FILTER_UP] + encoded_bytes
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
data/spec/unit/decoding_spec.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe ChunkyPNG::PixelMatrix::Decoding do
|
4
|
-
include ChunkyPNG::PixelMatrix::Decoding
|
5
|
-
|
6
|
-
describe '#decode_scanline' do
|
7
|
-
|
8
|
-
it "should decode a line without filtering as is" do
|
9
|
-
bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255]
|
10
|
-
decode_scanline(ChunkyPNG::FILTER_NONE, bytes, nil).should == bytes
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should decode a line with sub filtering correctly" do
|
14
|
-
# all white pixels
|
15
|
-
bytes = [255, 255, 255, 0, 0, 0, 0, 0, 0]
|
16
|
-
decoded_bytes = decode_scanline(ChunkyPNG::FILTER_SUB, bytes, nil)
|
17
|
-
decoded_bytes.should == [255, 255, 255, 255, 255, 255, 255, 255, 255]
|
18
|
-
|
19
|
-
# all black pixels
|
20
|
-
bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
21
|
-
decoded_bytes = decode_scanline(ChunkyPNG::FILTER_SUB, bytes, nil)
|
22
|
-
decoded_bytes.should == [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
23
|
-
|
24
|
-
# various colors
|
25
|
-
bytes = [255, 0, 45, 0, 255, 0, 112, 200, 178]
|
26
|
-
decoded_bytes = decode_scanline(ChunkyPNG::FILTER_SUB, bytes, nil)
|
27
|
-
decoded_bytes.should == [255, 0, 45, 255, 255, 45, 111, 199, 223]
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should decode a line with up filtering correctly" do
|
31
|
-
# previous line is all black
|
32
|
-
previous_bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
33
|
-
bytes = [255, 255, 255, 127, 127, 127, 0, 0, 0]
|
34
|
-
decoded_bytes = decode_scanline(ChunkyPNG::FILTER_UP, bytes, previous_bytes)
|
35
|
-
decoded_bytes.should == [255, 255, 255, 127, 127, 127, 0, 0, 0]
|
36
|
-
|
37
|
-
# previous line has various pixels
|
38
|
-
previous_bytes = [255, 255, 255, 127, 127, 127, 0, 0, 0]
|
39
|
-
bytes = [0, 127, 255, 0, 127, 255, 0, 127, 255]
|
40
|
-
decoded_bytes = decode_scanline(ChunkyPNG::FILTER_UP, bytes, previous_bytes)
|
41
|
-
decoded_bytes.should == [255, 126, 254, 127, 254, 126, 0, 127, 255]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe '#adam7_pass_sizes' do
|
46
|
-
it "should get the pass sizes for a 8x8 image correctly" do
|
47
|
-
adam7_pass_sizes(8, 8).should == [
|
48
|
-
[1, 1], [1, 1], [2, 1], [2, 2], [4, 2], [4, 4], [8, 4]
|
49
|
-
]
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should get the pass sizes for a 12x12 image correctly" do
|
53
|
-
adam7_pass_sizes(12, 12).should == [
|
54
|
-
[2, 2], [1, 2], [3, 1], [3, 3], [6, 3], [6, 6], [12, 6]
|
55
|
-
]
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should get the pass sizes for a 33x47 image correctly" do
|
59
|
-
adam7_pass_sizes(33, 47).should == [
|
60
|
-
[5, 6], [4, 6], [9, 6], [8, 12], [17, 12], [16, 24], [33, 23]
|
61
|
-
]
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should get the pass sizes for a 1x1 image correctly" do
|
65
|
-
adam7_pass_sizes(1, 1).should == [
|
66
|
-
[1, 1], [0, 1], [1, 0], [0, 1], [1, 0], [0, 1], [1, 0]
|
67
|
-
]
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should get the pass sizes for a 0x0 image correctly" do
|
71
|
-
adam7_pass_sizes(0, 0).should == [
|
72
|
-
[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]
|
73
|
-
]
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should always maintain the same amount of pixels in total" do
|
77
|
-
[[8, 8], [12, 12], [33, 47], [1, 1], [0, 0]].each do |(width, height)|
|
78
|
-
pass_sizes = adam7_pass_sizes(width, height)
|
79
|
-
pass_sizes.inject(0) { |sum, (w, h)| sum + (w*h) }.should == width * height
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
data/spec/unit/encoding_spec.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe ChunkyPNG::PixelMatrix::Encoding do
|
4
|
-
include ChunkyPNG::PixelMatrix::Encoding
|
5
|
-
|
6
|
-
describe '#encode_scanline' do
|
7
|
-
|
8
|
-
it "should encode a scanline without filtering correctly" do
|
9
|
-
bytes = [0, 0, 0, 1, 1, 1, 2, 2, 2]
|
10
|
-
encoded_bytes = encode_scanline(ChunkyPNG::FILTER_NONE, bytes, nil)
|
11
|
-
encoded_bytes.should == [0, 0, 0, 0, 1, 1, 1, 2, 2, 2]
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should encode a scanline with sub filtering correctly" do
|
15
|
-
bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255]
|
16
|
-
encoded_bytes = encode_scanline(ChunkyPNG::FILTER_SUB, bytes, nil)
|
17
|
-
encoded_bytes.should == [1, 255, 255, 255, 0, 0, 0, 0, 0, 0]
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should encode a scanline with up filtering correctly" do
|
21
|
-
bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255]
|
22
|
-
previous_bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255]
|
23
|
-
encoded_bytes = encode_scanline(ChunkyPNG::FILTER_UP, bytes, previous_bytes)
|
24
|
-
encoded_bytes.should == [2, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe ChunkyPNG::PixelMatrix do
|
4
|
-
|
5
|
-
describe '.from_rgb_stream' do
|
6
|
-
it "should load an image correctly from a datastrean" do
|
7
|
-
reference = ChunkyPNG.load(resource_file('pixelstream_reference.png')).pixel_matrix
|
8
|
-
|
9
|
-
File.open(resource_file('pixelstream.rgb')) do |stream|
|
10
|
-
pm = ChunkyPNG::PixelMatrix.from_rgb_stream(240, 180, stream)
|
11
|
-
pm.should == reference
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe '.decode' do
|
17
|
-
|
18
|
-
[:indexed, :grayscale, :grayscale_alpha, :truecolor, :truecolor_alpha].each do |color_mode|
|
19
|
-
it "should decode an image with color mode #{color_mode} correctly" do
|
20
|
-
reference = ChunkyPNG::PixelMatrix.new(10, 10, ChunkyPNG::Pixel.rgb(100, 100, 100))
|
21
|
-
ds = ChunkyPNG.load(resource_file("gray_10x10_#{color_mode}.png"))
|
22
|
-
ds.pixel_matrix.should == reference
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should decode a transparent image correctly" do
|
27
|
-
reference = ChunkyPNG::PixelMatrix.new(10, 10, ChunkyPNG::Pixel.rgba(100, 100, 100, 128))
|
28
|
-
ds = ChunkyPNG.load(resource_file("transparent_gray_10x10.png"))
|
29
|
-
ds.pixel_matrix.should == reference
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should decode an interlaced image correctly" do
|
33
|
-
ds_i = ChunkyPNG.load(resource_file("16x16_interlaced.png"))
|
34
|
-
ds_ni = ChunkyPNG.load(resource_file("16x16_non_interlaced.png"))
|
35
|
-
ds_i.pixel_matrix.should == ds_ni.pixel_matrix
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe '.encode' do
|
40
|
-
before(:each) do
|
41
|
-
@reference = ChunkyPNG::PixelMatrix.new(10, 10, ChunkyPNG::Pixel.rgb(100, 100, 100))
|
42
|
-
end
|
43
|
-
|
44
|
-
[:indexed, :grayscale, :grayscale_alpha, :truecolor, :truecolor_alpha].each do |color_mode|
|
45
|
-
it "should encode an image with color mode #{color_mode} correctly" do
|
46
|
-
|
47
|
-
filename = resource_file("_tmp_#{color_mode}.png")
|
48
|
-
File.open(filename, 'w') { |f| @reference.to_datastream.write(f) }
|
49
|
-
|
50
|
-
ChunkyPNG.load(filename).pixel_matrix.should == @reference
|
51
|
-
|
52
|
-
File.unlink(filename)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe '#crop' do
|
58
|
-
before(:each) do
|
59
|
-
@matrix = ChunkyPNG.load(resource_file('operations.png')).pixel_matrix
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should crop the right pixels from the original matrix" do
|
63
|
-
cropped = @matrix.crop(10, 5, 2, 3)
|
64
|
-
cropped.size.should == [2, 3]
|
65
|
-
cropped[0, 0].r.should == 10 * 16
|
66
|
-
cropped[0, 0].g.should == 5 * 16
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe '#compose' do
|
71
|
-
before(:each) do
|
72
|
-
@matrix = ChunkyPNG.load(resource_file('operations.png')).pixel_matrix
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should compose pixels correctly" do
|
76
|
-
submatrix = ChunkyPNG::PixelMatrix.new(4, 8, ChunkyPNG::Pixel.rgba(0, 0, 0, 75))
|
77
|
-
@matrix.compose(submatrix, 8, 4)
|
78
|
-
# display(@matrix)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
describe '#replace' do
|
83
|
-
before(:each) do
|
84
|
-
@matrix = ChunkyPNG.load(resource_file('operations.png')).pixel_matrix
|
85
|
-
end
|
86
|
-
|
87
|
-
it "should replace the correct pixels" do
|
88
|
-
submatrix = ChunkyPNG::PixelMatrix.new(3, 2, ChunkyPNG::Pixel.rgb(255, 255, 0))
|
89
|
-
@matrix.replace(submatrix, 5, 4)
|
90
|
-
# display(@matrix)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|