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.
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