chunky_png 0.0.5 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|