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.
Files changed (43) hide show
  1. data/README.rdoc +20 -10
  2. data/chunky_png.gemspec +18 -6
  3. data/lib/chunky_png.rb +11 -28
  4. data/lib/chunky_png/canvas.rb +186 -0
  5. data/lib/chunky_png/canvas/adam7_interlacing.rb +53 -0
  6. data/lib/chunky_png/canvas/drawing.rb +8 -0
  7. data/lib/chunky_png/{pixel_matrix → canvas}/operations.rb +12 -12
  8. data/lib/chunky_png/canvas/png_decoding.rb +145 -0
  9. data/lib/chunky_png/canvas/png_encoding.rb +182 -0
  10. data/lib/chunky_png/chunk.rb +101 -23
  11. data/lib/chunky_png/color.rb +307 -0
  12. data/lib/chunky_png/datastream.rb +143 -45
  13. data/lib/chunky_png/image.rb +31 -30
  14. data/lib/chunky_png/palette.rb +49 -47
  15. data/lib/chunky_png/rmagick.rb +43 -0
  16. data/spec/chunky_png/canvas/adam7_interlacing_spec.rb +108 -0
  17. data/spec/chunky_png/canvas/png_decoding_spec.rb +81 -0
  18. data/spec/chunky_png/canvas/png_encoding_spec.rb +70 -0
  19. data/spec/chunky_png/canvas_spec.rb +71 -0
  20. data/spec/chunky_png/color_spec.rb +104 -0
  21. data/spec/chunky_png/datastream_spec.rb +32 -0
  22. data/spec/chunky_png/image_spec.rb +25 -0
  23. data/spec/chunky_png/rmagick_spec.rb +21 -0
  24. data/spec/{integration/image_spec.rb → chunky_png_spec.rb} +14 -8
  25. data/spec/resources/composited.png +0 -0
  26. data/spec/resources/cropped.png +0 -0
  27. data/spec/resources/damaged_chunk.png +0 -0
  28. data/spec/resources/damaged_signature.png +13 -0
  29. data/spec/resources/pixelstream.rgba +67 -0
  30. data/spec/resources/replaced.png +0 -0
  31. data/spec/resources/text_chunk.png +0 -0
  32. data/spec/resources/ztxt_chunk.png +0 -0
  33. data/spec/spec_helper.rb +8 -5
  34. data/tasks/github-gem.rake +1 -1
  35. metadata +37 -18
  36. data/lib/chunky_png/pixel.rb +0 -272
  37. data/lib/chunky_png/pixel_matrix.rb +0 -136
  38. data/lib/chunky_png/pixel_matrix/decoding.rb +0 -159
  39. data/lib/chunky_png/pixel_matrix/encoding.rb +0 -89
  40. data/spec/unit/decoding_spec.rb +0 -83
  41. data/spec/unit/encoding_spec.rb +0 -27
  42. data/spec/unit/pixel_matrix_spec.rb +0 -93
  43. 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
@@ -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
@@ -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