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
@@ -11,8 +11,8 @@ Issue tracker:: http://github.com/wvanbergen/chunky_png/issues
11
11
 
12
12
  == Features
13
13
 
14
- * Decodes almost any image that the PNG standard allows, except for images
15
- that use a different color depth than 8 bits. This includes all standard
14
+ * Decodes almost any image that the PNG standard allows, except for images
15
+ that use a different color depth than 8 bits. This includes all standard
16
16
  color modes and all transparency, interlacing and filtering options.
17
17
  * Encodes images supports all color modes (true color, grayscale and indexed)
18
18
  and transparency for all these color modes. The best color mode will be
@@ -26,21 +26,30 @@ The main classes used within ChunkyPNG are:
26
26
 
27
27
  <tt>ChunkyPNG::Image</tt> :: create PNG images from scratch or based on another PNG image.
28
28
  <tt>ChunkyPNG::Datastream</tt> :: low-level read and write access to PNG images from or to a file or stream.
29
- <tt>ChunkyPNG::PixelMatrix</tt> :: represents an images as a matrix of pixels.
30
- <tt>ChunkyPNG::Pixel</tt> :: represents a single pixel or color value.
29
+ <tt>ChunkyPNG::Canvas</tt> :: represents an image canvas as a matrix of pixels.
30
+ <tt>ChunkyPNG::Color</tt> :: represents a, RGBA color
31
31
 
32
32
  == Usage
33
33
 
34
34
  require 'chunky_png'
35
-
35
+
36
36
  # Creating an image from scratch
37
- png = ChunkyPNG::Image.new(16, 16, ChunkyPNG::Pixel::TRANSPARENT)
38
- png[1,1] = ChunkyPNG::Pixel.rgba(255, 255, 255, 128)
39
- png[2,1] = ChunkyPNG::Pixel.rgba(255, 255, 255, 128)
37
+ png = ChunkyPNG::Image.new(16, 16, ChunkyPNG::Color::TRANSPARENT)
38
+ png[1,1] = ChunkyPNG::Color.rgba(10, 20, 30, 128)
39
+ png[2,1] = ChunkyPNG::Color.rgba(0, 0, 0, 128)
40
40
  png.save('filename.png')
41
41
 
42
- # Modify an image - TODO
42
+ # Compose images using alpha blending
43
+ avatar = ChunkyPNG::Image.from_file('avatar.png')
44
+ badge = ChunkyPNG::Image.from_file('no_ie_badge.png')
45
+ avatar.compose(badge, 10, 10)
46
+ avatar.save('composited.png', :color_mode => ChunkyPNG::COLOR_GRAYSCALE, :interlace => true)
47
+
43
48
  # Inspecting metadata - TODO
49
+
50
+ # Low level access to PNG chunks
51
+ png_stream = ChunkyPNG::Datastream.from_file('filename.png')
52
+ png_stream.each_chunk { |chunk| p chunk.type }
44
53
 
45
54
  (Note: this is subject to change while work is in progress)
46
55
 
@@ -50,4 +59,5 @@ The library is written by Willem van Bergen for Floorplanner.com, and released
50
59
  under the MIT license (see LICENSE). Please contact me for questions or
51
60
  remarks. Patches are greatly appreciated! :-)
52
61
 
53
- P.S.: _why is why this library is so chunky.
62
+ P.S.: The name of this library is intentionally similar to Chunky Bacon and
63
+ Chunky GIF. Use Google if you want to know _why.
@@ -1,13 +1,25 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'chunky_png'
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.0.5"
7
- s.date = "2010-01-13"
6
+ s.version = "0.5.0"
7
+ s.date = "2010-01-16"
8
8
 
9
9
  s.summary = "Pure ruby library for read/write, chunk-level access to PNG files"
10
- s.description = "Pure ruby library for read/write, chunk-level access to PNG files"
10
+ s.description = <<-EOT
11
+ This pure Ruby library can read and write PNG images without depending on an external
12
+ image library, like RMagick. It tries to be memory efficient and reasonably fast.
13
+
14
+ It supports reading and writing all PNG variants that are defined in the specification,
15
+ with one limitation: only 8-bit color depth is supported. It supports all transparency,
16
+ interlacing and filtering options the PNG specifications allows. It can also read and
17
+ write textual metadata from PNG files. Low-level read/write access to PNG chunks is
18
+ also possible.
19
+
20
+ This library supports simple drawing on the image canvas and simple operations like alpha composition
21
+ and cropping. Finally, it can import from and export to RMagick for interoperability.
22
+ EOT
11
23
 
12
24
  s.authors = ['Willem van Bergen']
13
25
  s.email = ['willem@railsdoctors.com']
@@ -20,6 +32,6 @@ Gem::Specification.new do |s|
20
32
 
21
33
  # Do not change the files and test_files fields by hand. This will be done
22
34
  # automatically by the gem release script.
23
- s.files = %w(spec/spec_helper.rb spec/resources/pixelstream.rgb spec/resources/gray_10x10_grayscale.png spec/resources/gray_10x10.png .gitignore spec/resources/gray_10x10_truecolor_alpha.png lib/chunky_png/pixel_matrix.rb LICENSE spec/resources/gray_10x10_truecolor.png lib/chunky_png/pixel_matrix/decoding.rb lib/chunky_png/chunk.rb spec/unit/encoding_spec.rb spec/resources/operations.png Rakefile spec/resources/transparent_gray_10x10.png README.rdoc spec/resources/gray_10x10_indexed.png spec/resources/16x16_non_interlaced.png spec/integration/image_spec.rb lib/chunky_png/pixel_matrix/operations.rb lib/chunky_png/pixel.rb lib/chunky_png/palette.rb lib/chunky_png/datastream.rb chunky_png.gemspec tasks/github-gem.rake spec/unit/decoding_spec.rb spec/resources/pixelstream_reference.png spec/resources/gray_10x10_grayscale_alpha.png spec/resources/16x16_interlaced.png spec/resources/adam7.png lib/chunky_png/pixel_matrix/encoding.rb lib/chunky_png/image.rb spec/unit/pixel_spec.rb spec/unit/pixel_matrix_spec.rb lib/chunky_png.rb)
24
- s.test_files = %w(spec/unit/encoding_spec.rb spec/integration/image_spec.rb spec/unit/decoding_spec.rb spec/unit/pixel_spec.rb spec/unit/pixel_matrix_spec.rb)
35
+ s.files = %w(spec/spec_helper.rb spec/resources/ztxt_chunk.png spec/resources/text_chunk.png spec/resources/replaced.png spec/resources/pixelstream.rgb spec/resources/gray_10x10_grayscale.png spec/resources/damaged_signature.png spec/resources/damaged_chunk.png spec/chunky_png/canvas/png_encoding_spec.rb spec/resources/gray_10x10.png lib/chunky_png/color.rb lib/chunky_png/canvas/operations.rb .gitignore spec/resources/gray_10x10_truecolor_alpha.png spec/chunky_png/canvas_spec.rb LICENSE spec/resources/gray_10x10_truecolor.png spec/resources/composited.png spec/chunky_png/color_spec.rb spec/chunky_png/canvas/adam7_interlacing_spec.rb lib/chunky_png/chunk.rb lib/chunky_png/canvas/png_encoding.rb lib/chunky_png/canvas/adam7_interlacing.rb spec/resources/operations.png spec/chunky_png/canvas/png_decoding_spec.rb lib/chunky_png/canvas.rb Rakefile spec/resources/transparent_gray_10x10.png spec/resources/pixelstream.rgba spec/resources/cropped.png README.rdoc spec/resources/gray_10x10_indexed.png spec/resources/16x16_non_interlaced.png spec/chunky_png_spec.rb lib/chunky_png/palette.rb lib/chunky_png/datastream.rb chunky_png.gemspec tasks/github-gem.rake spec/resources/pixelstream_reference.png spec/resources/gray_10x10_grayscale_alpha.png spec/resources/16x16_interlaced.png spec/chunky_png/image_spec.rb lib/chunky_png/canvas/drawing.rb spec/resources/adam7.png lib/chunky_png/rmagick.rb lib/chunky_png/image.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png/datastream_spec.rb lib/chunky_png/canvas/png_decoding.rb lib/chunky_png.rb)
36
+ s.test_files = %w(spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png/datastream_spec.rb)
25
37
  end
@@ -4,11 +4,13 @@ require 'zlib'
4
4
  require 'chunky_png/datastream'
5
5
  require 'chunky_png/chunk'
6
6
  require 'chunky_png/palette'
7
- require 'chunky_png/pixel'
8
- require 'chunky_png/pixel_matrix/encoding'
9
- require 'chunky_png/pixel_matrix/decoding'
10
- require 'chunky_png/pixel_matrix/operations'
11
- require 'chunky_png/pixel_matrix'
7
+ require 'chunky_png/color'
8
+ require 'chunky_png/canvas/png_encoding'
9
+ require 'chunky_png/canvas/png_decoding'
10
+ require 'chunky_png/canvas/adam7_interlacing'
11
+ require 'chunky_png/canvas/operations'
12
+ require 'chunky_png/canvas/drawing'
13
+ require 'chunky_png/canvas'
12
14
  require 'chunky_png/image'
13
15
 
14
16
  # ChunkyPNG
@@ -16,7 +18,10 @@ require 'chunky_png/image'
16
18
  # The ChunkyPNG module defines some constants that are used in the
17
19
  # PNG specification.
18
20
  module ChunkyPNG
19
- extend self
21
+
22
+ # The current version of ChunkyPNG. This value will be updated automatically
23
+ # by them gem:release rake task.
24
+ VERSION = "0.5.0"
20
25
 
21
26
  ###################################################
22
27
  # PNG international standard defined constants
@@ -40,26 +45,4 @@ module ChunkyPNG
40
45
  FILTER_UP = 2
41
46
  FILTER_AVERAGE = 3
42
47
  FILTER_PAETH = 4
43
-
44
- def load_from_io(io)
45
- ChunkyPNG::Datastream.read(io)
46
- end
47
-
48
- def load_from_file(file)
49
- File.open(file, 'rb') { |f| load_from_io(f) }
50
- end
51
-
52
- def load_from_memory(string)
53
- load_from_io(StringIO.new(string))
54
- end
55
-
56
- def load(arg)
57
- if arg.respond_to?(:read)
58
- load_from_io(arg)
59
- elsif File.exists?(arg)
60
- load_from_file(arg)
61
- else
62
- load_from_memory(arg)
63
- end
64
- end
65
48
  end
@@ -0,0 +1,186 @@
1
+ module ChunkyPNG
2
+
3
+ # The ChunkPNG::Canvas class represents a raster image as a matrix of
4
+ # pixels.
5
+ #
6
+ # This class supports loading a Canvas from a PNG datastream, and creating a
7
+ # {ChunkyPNG::Datastream PNG datastream} based on this matrix. ChunkyPNG
8
+ # only supports 8-bit color depth, otherwise all of the PNG format's
9
+ # variations are supported for both reading and writing.
10
+ #
11
+ # This class offers per-pixel access to the matrix by using x,y coordinates.
12
+ # It uses a palette (see {ChunkyPNG::Palette}) to keep track of the
13
+ # different colors used in this matrix.
14
+ #
15
+ # The pixels in the canvas are stored as 4-byte fixnum, representing 32-bit
16
+ # RGBA colors (8 bit per channel). The module {ChunkyPNG::Color} is provided
17
+ # to work more easily with these number as color values.
18
+ #
19
+ # The module {ChunkyPNG::Canvas::Operations} is imported for operations on
20
+ # the whole canvas, like cropping and alpha compositing. Simple drawing
21
+ # functions are imported from the {ChunkyPNG::Canvas::Drawing} module.
22
+ class Canvas
23
+
24
+ include PNGEncoding
25
+ extend PNGDecoding
26
+ extend Adam7Interlacing
27
+
28
+ include Operations
29
+ include Drawing
30
+
31
+ # @return [Integer] The number of columns in this canvas
32
+ attr_reader :width
33
+
34
+ # @return [Integer] The number of rows in this canvas
35
+ attr_reader :height
36
+
37
+ # @return [Array<ChunkyPNG::Color>] The list of pixels in this canvas.
38
+ # This array always should have +width * height+ elements.
39
+ attr_reader :pixels
40
+
41
+ # Initializes a new Canvas instance
42
+ # @param [Integer] width The width in pixels of this canvas
43
+ # @param [Integer] width The height in pixels of this canvas
44
+ # @param [ChunkyPNG::Pixel, Array<ChunkyPNG::Color>] initial The initial value of te pixels:
45
+ #
46
+ # * If a color is passed to this parameter, this color will be used as background color.
47
+ #
48
+ # * If an array of pixels is provided, these pixels will be used as initial value. Note
49
+ # that the amount of pixels in this array should equal +width * height+.
50
+ def initialize(width, height, initial = ChunkyPNG::Color::TRANSPARENT)
51
+
52
+ @width, @height = width, height
53
+
54
+ if initial.kind_of?(Fixnum)
55
+ @pixels = Array.new(width * height, initial)
56
+ elsif initial.kind_of?(Array) && initial.size == width * height
57
+ @pixels = initial.map(&:to_i)
58
+ else
59
+ raise "Cannot use this value as initial canvas: #{initial.inspect}!"
60
+ end
61
+ end
62
+
63
+ def initialize_copy(other)
64
+ @width, @height = other.width, other.height
65
+ @pixels = other.pixels.dup
66
+ end
67
+
68
+ # Returns the size ([width, height]) for this canvas.
69
+ # @return Array An array with the width and height of this canvas as elements.
70
+ def size
71
+ [@width, @height]
72
+ end
73
+
74
+ # Replaces a single pixel in this canvas.
75
+ # @param [Integer] x The x-coordinate of the pixel (column)
76
+ # @param [Integer] y The y-coordinate of the pixel (row)
77
+ # @param [ChunkyPNG::Color] pixel The new pixel for the provided coordinates.
78
+ def []=(x, y, color)
79
+ @pixels[y * width + x] = color
80
+ end
81
+
82
+ # Returns a single pixel from this canvas.
83
+ # @param [Integer] x The x-coordinate of the pixel (column)
84
+ # @param [Integer] y The y-coordinate of the pixel (row)
85
+ # @return [ChunkyPNG::Color] The current pixel at the provided coordinates.
86
+ def [](x, y)
87
+ @pixels[y * width + x]
88
+ end
89
+
90
+ # Returns the palette used for this canvas.
91
+ # @return [ChunkyPNG::Palette] A pallete which contains all the colors that are
92
+ # being used for this image.
93
+ def palette
94
+ ChunkyPNG::Palette.from_canvas(self)
95
+ end
96
+
97
+ # Equality check to compare this canvas with other matrices.
98
+ # @param other The object to compare this Matrix to.
99
+ # @return [true, false] True if the size and pixel values of the other canvas
100
+ # are exactly the same as this canvas's size and pixel values.
101
+ def eql?(other)
102
+ other.kind_of?(self.class) && other.pixels == self.pixels &&
103
+ other.width == self.width && other.height == self.height
104
+ end
105
+
106
+ alias :== :eql?
107
+
108
+ # Creates an ChunkyPNG::Image object from this canvas
109
+ def to_image
110
+ ChunkyPNG::Image.from_canvas(self)
111
+ end
112
+
113
+ #################################################################
114
+ # CONSTRUCTORS
115
+ #################################################################
116
+
117
+ # Creates a new canvas instance by duplicating another instance.
118
+ # @param [ChunkyPNG::Canvas] canvas The canvas to duplicate
119
+ # @return [ChunkyPNG::Canvas] The newly constructed canvas instance.
120
+ def self.from_canvas(canvas)
121
+ self.new(canvas.width, canvas.height, canvas.pixels.dup)
122
+ end
123
+
124
+ # Creates a canvas by reading pixels from an RGB formatted stream with a
125
+ # provided with and height.
126
+ #
127
+ # Every pixel should be represented by 3 bytes in the stream, in the correct
128
+ # RGB order. This format closely resembles the internal representation of a
129
+ # canvas object, so this kind of stream can be read extremely quickly.
130
+ #
131
+ # @param [Integer] width The width of the new canvas.
132
+ # @param [Integer] height The height of the new canvas.
133
+ # @param [#read, String] stream The stream to read the pixel data from.
134
+ # @return [ChunkyPNG::Canvas] The newly constructed canvas instance.
135
+ def self.from_rgb_stream(width, height, stream)
136
+ string = stream.respond_to?(:read) ? stream.read(3 * width * height) : stream.to_s[0, 3 * width * height]
137
+ string << "\255" # Add a fourth byte to the last RGB triple.
138
+ unpacker = 'NX' * (width * height)
139
+ pixels = string.unpack(unpacker).map { |color| color | 0x000000ff }
140
+ self.new(width, height, pixels)
141
+ end
142
+
143
+ # Creates a canvas by reading pixels from an RGBA formatted stream with a
144
+ # provided with and height.
145
+ #
146
+ # Every pixel should be represented by 4 bytes in the stream, in the correct
147
+ # RGBA order. This format is exactly like the internal representation of a
148
+ # canvas object, so this kind of stream can be read extremely quickly.
149
+ #
150
+ # @param [Integer] width The width of the new canvas.
151
+ # @param [Integer] height The height of the new canvas.
152
+ # @param [#read, String] stream The stream to read the pixel data from.
153
+ # @return [ChunkyPNG::Canvas] The newly constructed canvas instance.
154
+ def self.from_rgba_stream(width, height, stream)
155
+ string = stream.respond_to?(:read) ? stream.read(4 * width * height) : stream.to_s[0, 4 * width * height]
156
+ self.new(width, height, string.unpack("N*"))
157
+ end
158
+
159
+ #################################################################
160
+ # EXPORTING
161
+ #################################################################
162
+
163
+ # Creates an RGB-formatted pixelstream with the pixel data from this canvas.
164
+ #
165
+ # Note that this format is fast but bloated, because no compression is used
166
+ # and the internal representation is left intact. However, to reconstruct the
167
+ # canvas, the width and height should be known.
168
+ #
169
+ # @return [String] The RGBA-formatted pixel data.
170
+ def to_rgba_stream
171
+ pixels.pack('N*')
172
+ end
173
+
174
+ # Creates an RGB-formatted pixelstream with the pixel data from this canvas.
175
+ #
176
+ # Note that this format is fast but bloated, because no compression is used
177
+ # and the internal representation is almost left intact. However, to reconstruct
178
+ # the canvas, the width and height should be known.
179
+ #
180
+ # @return [String] The RGB-formatted pixel data.
181
+ def to_rgb_stream
182
+ packer = 'NX' * (width * height)
183
+ pixels.pack(packer)
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,53 @@
1
+ module ChunkyPNG
2
+ class Canvas
3
+
4
+ # Methods for decoding and encoding adam7 interlacing
5
+ #
6
+ module Adam7Interlacing
7
+
8
+ def adam7_multiplier_offset(pass)
9
+ {
10
+ :x_multiplier => 8 >> (pass >> 1),
11
+ :x_offset => (pass & 1 == 0) ? 0 : 8 >> ((pass + 1) >> 1),
12
+ :y_multiplier => pass == 0 ? 8 : 8 >> ((pass - 1) >> 1),
13
+ :y_offset => (pass == 0 || pass & 1 == 1) ? 0 : 8 >> (pass >> 1)
14
+ }
15
+ end
16
+
17
+ def adam7_pass_size(pass, original_width, original_height)
18
+ m_o = adam7_multiplier_offset(pass)
19
+ [ ((original_width - m_o[:x_offset] ) / m_o[:x_multiplier].to_f).ceil,
20
+ ((original_height - m_o[:y_offset] ) / m_o[:y_multiplier].to_f).ceil]
21
+ end
22
+
23
+ def adam7_pass_sizes(original_width, original_height)
24
+ (0...7).map { |pass| adam7_pass_size(pass, original_width, original_height) }
25
+ end
26
+
27
+ def adam7_merge_pass(pass, canvas, subcanvas)
28
+ m_o = adam7_multiplier_offset(pass)
29
+ 0.upto(subcanvas.height - 1) do |y|
30
+ 0.upto(subcanvas.width - 1) do |x|
31
+ new_x = x * m_o[:x_multiplier] + m_o[:x_offset]
32
+ new_y = y * m_o[:y_multiplier] + m_o[:y_offset]
33
+ canvas[new_x, new_y] = subcanvas[x, y]
34
+ end
35
+ end
36
+ canvas
37
+ end
38
+
39
+ def adam7_extract_pass(pass, canvas)
40
+ m_o = adam7_multiplier_offset(pass)
41
+ sm_pixels = []
42
+ m_o[:y_offset].step(canvas.height - 1, m_o[:y_multiplier]) do |y|
43
+ m_o[:x_offset].step(canvas.width - 1, m_o[:x_multiplier]) do |x|
44
+ sm_pixels << canvas[x, y]
45
+ end
46
+ end
47
+
48
+ new_canvas_args = adam7_pass_size(pass, canvas.width, canvas.height) + [sm_pixels]
49
+ ChunkyPNG::Canvas.new(*new_canvas_args)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ module ChunkyPNG
2
+ class Canvas
3
+
4
+ module Drawing
5
+
6
+ end
7
+ end
8
+ end
@@ -1,34 +1,34 @@
1
1
  module ChunkyPNG
2
- class PixelMatrix
2
+ class Canvas
3
3
  module Operations
4
- def compose(other, dx = 0, dy = 0)
5
- check_size_constraints!(other, dx, dy)
6
-
7
- other.height.times do |y|
8
- other.width.times do |x|
9
- self[x+dx, y+dy] = self[x+dx, y+dy] & other[x, y]
4
+ def compose(new_foreground, dx = 0, dy = 0)
5
+ check_size_constraints!(new_foreground, dx, dy)
6
+
7
+ new_foreground.height.times do |y|
8
+ new_foreground.width.times do |x|
9
+ self[x+dx, y+dy] = ChunkyPNG::Color.compose(new_foreground[x, y], self[x+dx, y+dy])
10
10
  end
11
11
  end
12
12
  self
13
13
  end
14
-
14
+
15
15
  def replace(other, offset_x = 0, offset_y = 0)
16
16
  check_size_constraints!(other, offset_x, offset_y)
17
-
17
+
18
18
  other.height.times do |y|
19
19
  pixels[(y + offset_y) * width + offset_x, other.width] = other.pixels[y * other.width, other.width]
20
20
  end
21
21
  self
22
22
  end
23
-
23
+
24
24
  def crop(x, y, crop_width, crop_height)
25
25
  new_pixels = []
26
26
  crop_height.times do |cy|
27
27
  new_pixels += pixels.slice((cy + y) * width + x, crop_width)
28
28
  end
29
- ChunkyPNG::PixelMatrix.new(crop_width, crop_height, new_pixels)
29
+ ChunkyPNG::Canvas.new(crop_width, crop_height, new_pixels)
30
30
  end
31
-
31
+
32
32
  protected
33
33
 
34
34
  def check_size_constraints!(other, offset_x, offset_y)