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
data/README.rdoc
CHANGED
@@ -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::
|
30
|
-
<tt>ChunkyPNG::
|
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::
|
38
|
-
png[1,1] = ChunkyPNG::
|
39
|
-
png[2,1] = ChunkyPNG::
|
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
|
-
#
|
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.:
|
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.
|
data/chunky_png.gemspec
CHANGED
@@ -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
|
7
|
-
s.date = "2010-01-
|
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 =
|
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
|
24
|
-
s.test_files = %w(spec/
|
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
|
data/lib/chunky_png.rb
CHANGED
@@ -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/
|
8
|
-
require 'chunky_png/
|
9
|
-
require 'chunky_png/
|
10
|
-
require 'chunky_png/
|
11
|
-
require 'chunky_png/
|
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
|
-
|
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
|
@@ -1,34 +1,34 @@
|
|
1
1
|
module ChunkyPNG
|
2
|
-
class
|
2
|
+
class Canvas
|
3
3
|
module Operations
|
4
|
-
def compose(
|
5
|
-
check_size_constraints!(
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
self[x+dx, y+dy] =
|
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::
|
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)
|