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
Binary file
|
Binary file
|
Binary file
|
data/spec/spec_helper.rb
CHANGED
@@ -12,16 +12,19 @@ module ResourceFileHelper
|
|
12
12
|
end
|
13
13
|
|
14
14
|
|
15
|
-
module
|
16
|
-
def display(
|
17
|
-
image = ChunkyPNG::Image.from_pixel_matrix(matrix)
|
15
|
+
module MatrixSpecHelper
|
16
|
+
def display(canvas)
|
18
17
|
filename = resource_file('_tmp.png')
|
19
|
-
|
18
|
+
canvas.to_datastream.save(filename)
|
20
19
|
`open #{filename}`
|
21
20
|
end
|
21
|
+
|
22
|
+
def reference_canvas(name)
|
23
|
+
ChunkyPNG::Canvas.from_file(resource_file("#{name}.png"))
|
24
|
+
end
|
22
25
|
end
|
23
26
|
|
24
27
|
Spec::Runner.configure do |config|
|
25
28
|
config.include ResourceFileHelper
|
26
|
-
config.include
|
29
|
+
config.include MatrixSpecHelper
|
27
30
|
end
|
data/tasks/github-gem.rake
CHANGED
@@ -229,7 +229,7 @@ module GithubGem
|
|
229
229
|
def rubyforge_release_task
|
230
230
|
sh 'rubyforge', 'add_release', gemspec.rubyforge_project, gemspec.name, gemspec.version.to_s, "pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
231
231
|
end
|
232
|
-
|
232
|
+
|
233
233
|
def gemcutter_release_task
|
234
234
|
sh "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
235
235
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chunky_png
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-16 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 1.2.9
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: " This pure Ruby library can read and write PNG images without depending on an external \n image library, like RMagick. It tries to be memory efficient and reasonably fast.\n \n It supports reading and writing all PNG variants that are defined in the specification, \n with one limitation: only 8-bit color depth is supported. It supports all transparency, \n interlacing and filtering options the PNG specifications allows. It can also read and \n write textual metadata from PNG files. Low-level read/write access to PNG chunks is\n also possible.\n \n This library supports simple drawing on the image canvas and simple operations like alpha composition\n and cropping. Finally, it can import from and export to RMagick for interoperability. \n"
|
26
26
|
email:
|
27
27
|
- willem@railsdoctors.com
|
28
28
|
executables: []
|
@@ -33,39 +33,54 @@ extra_rdoc_files:
|
|
33
33
|
- README.rdoc
|
34
34
|
files:
|
35
35
|
- spec/spec_helper.rb
|
36
|
+
- spec/resources/ztxt_chunk.png
|
37
|
+
- spec/resources/text_chunk.png
|
38
|
+
- spec/resources/replaced.png
|
36
39
|
- spec/resources/pixelstream.rgb
|
37
40
|
- spec/resources/gray_10x10_grayscale.png
|
41
|
+
- spec/resources/damaged_signature.png
|
42
|
+
- spec/resources/damaged_chunk.png
|
43
|
+
- spec/chunky_png/canvas/png_encoding_spec.rb
|
38
44
|
- spec/resources/gray_10x10.png
|
45
|
+
- lib/chunky_png/color.rb
|
46
|
+
- lib/chunky_png/canvas/operations.rb
|
39
47
|
- .gitignore
|
40
48
|
- spec/resources/gray_10x10_truecolor_alpha.png
|
41
|
-
-
|
49
|
+
- spec/chunky_png/canvas_spec.rb
|
42
50
|
- LICENSE
|
43
51
|
- spec/resources/gray_10x10_truecolor.png
|
44
|
-
-
|
52
|
+
- spec/resources/composited.png
|
53
|
+
- spec/chunky_png/color_spec.rb
|
54
|
+
- spec/chunky_png/canvas/adam7_interlacing_spec.rb
|
45
55
|
- lib/chunky_png/chunk.rb
|
46
|
-
-
|
56
|
+
- lib/chunky_png/canvas/png_encoding.rb
|
57
|
+
- lib/chunky_png/canvas/adam7_interlacing.rb
|
47
58
|
- spec/resources/operations.png
|
59
|
+
- spec/chunky_png/canvas/png_decoding_spec.rb
|
60
|
+
- lib/chunky_png/canvas.rb
|
48
61
|
- Rakefile
|
49
62
|
- spec/resources/transparent_gray_10x10.png
|
63
|
+
- spec/resources/pixelstream.rgba
|
64
|
+
- spec/resources/cropped.png
|
50
65
|
- README.rdoc
|
51
66
|
- spec/resources/gray_10x10_indexed.png
|
52
67
|
- spec/resources/16x16_non_interlaced.png
|
53
|
-
- spec/
|
54
|
-
- lib/chunky_png/pixel_matrix/operations.rb
|
55
|
-
- lib/chunky_png/pixel.rb
|
68
|
+
- spec/chunky_png_spec.rb
|
56
69
|
- lib/chunky_png/palette.rb
|
57
70
|
- lib/chunky_png/datastream.rb
|
58
71
|
- chunky_png.gemspec
|
59
72
|
- tasks/github-gem.rake
|
60
|
-
- spec/unit/decoding_spec.rb
|
61
73
|
- spec/resources/pixelstream_reference.png
|
62
74
|
- spec/resources/gray_10x10_grayscale_alpha.png
|
63
75
|
- spec/resources/16x16_interlaced.png
|
76
|
+
- spec/chunky_png/image_spec.rb
|
77
|
+
- lib/chunky_png/canvas/drawing.rb
|
64
78
|
- spec/resources/adam7.png
|
65
|
-
- lib/chunky_png/
|
79
|
+
- lib/chunky_png/rmagick.rb
|
66
80
|
- lib/chunky_png/image.rb
|
67
|
-
- spec/
|
68
|
-
- spec/
|
81
|
+
- spec/chunky_png/rmagick_spec.rb
|
82
|
+
- spec/chunky_png/datastream_spec.rb
|
83
|
+
- lib/chunky_png/canvas/png_decoding.rb
|
69
84
|
- lib/chunky_png.rb
|
70
85
|
has_rdoc: true
|
71
86
|
homepage: http://wiki.github.com/wvanbergen/chunky_png
|
@@ -101,8 +116,12 @@ signing_key:
|
|
101
116
|
specification_version: 3
|
102
117
|
summary: Pure ruby library for read/write, chunk-level access to PNG files
|
103
118
|
test_files:
|
104
|
-
- spec/
|
105
|
-
- spec/
|
106
|
-
- spec/
|
107
|
-
- spec/
|
108
|
-
- spec/
|
119
|
+
- spec/chunky_png/canvas/png_encoding_spec.rb
|
120
|
+
- spec/chunky_png/canvas_spec.rb
|
121
|
+
- spec/chunky_png/color_spec.rb
|
122
|
+
- spec/chunky_png/canvas/adam7_interlacing_spec.rb
|
123
|
+
- spec/chunky_png/canvas/png_decoding_spec.rb
|
124
|
+
- spec/chunky_png_spec.rb
|
125
|
+
- spec/chunky_png/image_spec.rb
|
126
|
+
- spec/chunky_png/rmagick_spec.rb
|
127
|
+
- spec/chunky_png/datastream_spec.rb
|
data/lib/chunky_png/pixel.rb
DELETED
@@ -1,272 +0,0 @@
|
|
1
|
-
module ChunkyPNG
|
2
|
-
|
3
|
-
# The Pixel class represents a pixel, which has a single color. Within the
|
4
|
-
# ChunkyPNG library, the concepts of pixels and colors are both used, and
|
5
|
-
# they are both represented by the pixel class.
|
6
|
-
#
|
7
|
-
# Pixels/colors are represented in RGBA moduds. Each of the four components
|
8
|
-
# is stored with a depth of 8 biths (maximum value = 255). Together, these
|
9
|
-
# components are stored in a 4-bye Fixnum.
|
10
|
-
class Pixel
|
11
|
-
|
12
|
-
# @return [Fixnum] The 4-byte fixnum representation of the pixel's
|
13
|
-
# color, where red compenent uses the most significant byte and the
|
14
|
-
# alpha component the least significant byte.
|
15
|
-
attr_reader :value
|
16
|
-
|
17
|
-
alias :to_i :value
|
18
|
-
|
19
|
-
# Initalizes a new pixel instance. Usually, it is more convenient to
|
20
|
-
# use one of the constructors below.
|
21
|
-
# @param [Fixnum] value The 4-byte fixnum representation of the pixel's
|
22
|
-
# color, where red compenent uses the most significant byte and the
|
23
|
-
# alpha component the least significant byte.
|
24
|
-
def initialize(value)
|
25
|
-
@value = value.to_i
|
26
|
-
end
|
27
|
-
|
28
|
-
####################################################################
|
29
|
-
# PIXEL LOADING
|
30
|
-
####################################################################
|
31
|
-
|
32
|
-
# Creates a new pixels using an r, g, b triple.
|
33
|
-
# @return [ChunkyPNG::Pixel] The newly constructed pixel.
|
34
|
-
def self.rgb(r, g, b, a = 255)
|
35
|
-
rgba(r, g, b, a)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Creates a new pixels using an r, g, b triple and an alpha value.
|
39
|
-
# @return [ChunkyPNG::Pixel] The newly constructed pixel.
|
40
|
-
def self.rgba(r, g, b, a)
|
41
|
-
self.new(r << 24 | g << 16 | b << 8 | a)
|
42
|
-
end
|
43
|
-
|
44
|
-
# Creates a new pixels using a grayscale teint.
|
45
|
-
# @return [ChunkyPNG::Pixel] The newly constructed pixel.
|
46
|
-
def self.grayscale(teint, a = 255)
|
47
|
-
rgba(teint, teint, teint, a)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Creates a new pixels using a grayscale teint and alpha value.
|
51
|
-
# @return [ChunkyPNG::Pixel] The newly constructed pixel.
|
52
|
-
def self.grayscale_alpha(teint, a)
|
53
|
-
rgba(teint, teint, teint, a)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Creates a pixel by unpacking an rgb triple from a string
|
57
|
-
# @return [ChunkyPNG::Pixel] The newly constructed pixel.
|
58
|
-
def self.from_rgb_stream(stream)
|
59
|
-
self.rgb(*stream.unpack('C3'))
|
60
|
-
end
|
61
|
-
|
62
|
-
# Creates a pixel by unpacking an rgba triple from a string
|
63
|
-
# @return [ChunkyPNG::Pixel] The newly constructed pixel.
|
64
|
-
def self.from_rgba_stream(stream)
|
65
|
-
self.rgba(*stream.unpack('C4'))
|
66
|
-
end
|
67
|
-
|
68
|
-
####################################################################
|
69
|
-
# COLOR CONSTANTS
|
70
|
-
####################################################################
|
71
|
-
|
72
|
-
BLACK = rgb( 0, 0, 0)
|
73
|
-
WHITE = rgb(255, 255, 255)
|
74
|
-
|
75
|
-
TRANSPARENT = rgba(0, 0, 0, 0)
|
76
|
-
|
77
|
-
####################################################################
|
78
|
-
# PROPERTIES
|
79
|
-
####################################################################
|
80
|
-
|
81
|
-
# Returns the red-component from the pixel value
|
82
|
-
# @return [Fixnum] A value between 0 and 255
|
83
|
-
def r
|
84
|
-
(@value & 0xff000000) >> 24
|
85
|
-
end
|
86
|
-
|
87
|
-
# Returns the green-component from the pixel value
|
88
|
-
# @return [Fixnum] A value between 0 and 255
|
89
|
-
def g
|
90
|
-
(@value & 0x00ff0000) >> 16
|
91
|
-
end
|
92
|
-
|
93
|
-
# Returns the blue-component from the pixel value
|
94
|
-
# @return [Fixnum] A value between 0 and 255
|
95
|
-
def b
|
96
|
-
(@value & 0x0000ff00) >> 8
|
97
|
-
end
|
98
|
-
|
99
|
-
# Returns the alpha channel value for the pixel
|
100
|
-
# @return [Fixnum] A value between 0 and 255
|
101
|
-
def a
|
102
|
-
@value & 0x000000ff
|
103
|
-
end
|
104
|
-
|
105
|
-
# Returns true if this pixel is fully opaque
|
106
|
-
# @return [true, false] True if the alpha channel equals 255
|
107
|
-
def opaque?
|
108
|
-
a == 0x000000ff
|
109
|
-
end
|
110
|
-
|
111
|
-
# Returns true if this pixel is fully transparent
|
112
|
-
# @return [true, false] True if the alpha channel equals 0
|
113
|
-
def fully_transparent?
|
114
|
-
a == 0x000000ff
|
115
|
-
end
|
116
|
-
|
117
|
-
# Returns true if this pixel is fully transparent
|
118
|
-
# @return [true, false] True if the r, g and b component are equal
|
119
|
-
def grayscale?
|
120
|
-
r == g && r == b
|
121
|
-
end
|
122
|
-
|
123
|
-
####################################################################
|
124
|
-
# COMPARISON
|
125
|
-
####################################################################
|
126
|
-
|
127
|
-
# Returns a nice string representation for this pixel using hex notation
|
128
|
-
# @return [String]
|
129
|
-
def inspect
|
130
|
-
'#%08x' % @value
|
131
|
-
end
|
132
|
-
|
133
|
-
# Returns a hash for determining the uniqueness of a pixel
|
134
|
-
# @return [Fixnum] The hash of the fixnum that is representing this pixel.
|
135
|
-
def hash
|
136
|
-
@value.hash
|
137
|
-
end
|
138
|
-
|
139
|
-
# Checks whether to pixels are the same (i.e. have the same color)
|
140
|
-
# @param [Object] The object to compare this pixel with
|
141
|
-
# @return [true, false] Returns true iff th pixels' fixnum representations is the same
|
142
|
-
def eql?(other)
|
143
|
-
other.kind_of?(self.class) && other.value == self.value
|
144
|
-
end
|
145
|
-
|
146
|
-
alias :== :eql?
|
147
|
-
|
148
|
-
# Compares to pixels for ordering, using the pixel's fixnum representation.
|
149
|
-
# @param [Object] The object to compare this pixel with.
|
150
|
-
# @return [Fixnum] A number used for sorting.
|
151
|
-
def <=>(other)
|
152
|
-
other.value <=> self.value
|
153
|
-
end
|
154
|
-
|
155
|
-
####################################################################
|
156
|
-
# CONVERSIONS
|
157
|
-
####################################################################
|
158
|
-
|
159
|
-
def to_truecolor_alpha_bytes
|
160
|
-
[r,g,b,a]
|
161
|
-
end
|
162
|
-
|
163
|
-
def to_truecolor_bytes
|
164
|
-
[r,g,b]
|
165
|
-
end
|
166
|
-
|
167
|
-
def to_indexed_bytes(palette)
|
168
|
-
[index(palette)]
|
169
|
-
end
|
170
|
-
|
171
|
-
def to_grayscale_bytes
|
172
|
-
[r] # Assumption: r == g == b
|
173
|
-
end
|
174
|
-
|
175
|
-
def to_grayscale_alpha_bytes
|
176
|
-
[r, a] # Assumption: r == g == b
|
177
|
-
end
|
178
|
-
|
179
|
-
####################################################################
|
180
|
-
# ALPHA COMPOSITION
|
181
|
-
####################################################################
|
182
|
-
|
183
|
-
# Multiplies two fractions using integer math, where the fractions are stored using an
|
184
|
-
# integer between 0 and 255. This method is used as a helper method for compositing
|
185
|
-
# pixels when using integer math.
|
186
|
-
#
|
187
|
-
# @param [Fixnum] a The first fraction.
|
188
|
-
# @param [Fixnum] b The second fraction.
|
189
|
-
# @return [Fixnum] The result of the multiplication.
|
190
|
-
def int8_mult(a, b)
|
191
|
-
t = a * b + 0x80
|
192
|
-
((t >> 8) + t) >> 8
|
193
|
-
end
|
194
|
-
|
195
|
-
# Composes two pixels with an alpha channel using integer math.
|
196
|
-
#
|
197
|
-
# The pixel instance is used as background color, the pixel provided as +other+
|
198
|
-
# parameter is used as foreground pixel in the composition formula.
|
199
|
-
#
|
200
|
-
# This version is faster than the version based on floating point math, so this
|
201
|
-
# compositing function is used by default.
|
202
|
-
#
|
203
|
-
# @param [ChunkyPNG::Pixel] other The foreground pixel to compose with
|
204
|
-
# @return [ChunkyPNG::Pixel] The composited pixel
|
205
|
-
# @see ChunkyPNG::Pixel#compose_precise
|
206
|
-
def compose_quick(other)
|
207
|
-
if other.a == 0xff
|
208
|
-
other
|
209
|
-
elsif other.a == 0x00
|
210
|
-
self
|
211
|
-
else
|
212
|
-
a_com = int8_mult(0xff - other.a, a)
|
213
|
-
new_r = int8_mult(other.a, other.r) + int8_mult(a_com, r)
|
214
|
-
new_g = int8_mult(other.a, other.g) + int8_mult(a_com, g)
|
215
|
-
new_b = int8_mult(other.a, other.b) + int8_mult(a_com, b)
|
216
|
-
new_a = other.a + a_com
|
217
|
-
ChunkyPNG::Pixel.rgba(new_r, new_g, new_b, new_a)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Composes two pixels with an alpha channel using floating point math.
|
222
|
-
#
|
223
|
-
# The pixel instance is used as background color, the pixel provided as +other+
|
224
|
-
# parameter is used as foreground pixel in the composition formula.
|
225
|
-
#
|
226
|
-
# This method uses more precise floating point math, but this precision is lost
|
227
|
-
# when the result is converted back to an integer. Because it is slower than
|
228
|
-
# the version based on integer, math, that version is preferred.
|
229
|
-
#
|
230
|
-
# @param [ChunkyPNG::Pixel] other The foreground pixel to compose with
|
231
|
-
# @return [ChunkyPNG::Pixel] The composited pixel
|
232
|
-
# @see ChunkyPNG::Pixel#compose_quick
|
233
|
-
def compose_precise(other)
|
234
|
-
if other.a == 255
|
235
|
-
other
|
236
|
-
elsif other.a == 0
|
237
|
-
self
|
238
|
-
else
|
239
|
-
alpha = other.a / 255.0
|
240
|
-
other_alpha = a / 255.0
|
241
|
-
alpha_com = (1.0 - alpha) * other_alpha
|
242
|
-
|
243
|
-
new_r = (alpha * other.r + alpha_com * r).round
|
244
|
-
new_g = (alpha * other.g + alpha_com * g).round
|
245
|
-
new_b = (alpha * other.b + alpha_com * b).round
|
246
|
-
new_a = ((alpha + alpha_com) * 255).round
|
247
|
-
ChunkyPNG::Pixel.rgba(new_r, new_g, new_b, new_a)
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
alias :compose :compose_quick
|
252
|
-
alias :& :compose
|
253
|
-
|
254
|
-
####################################################################
|
255
|
-
# STATIC UTILITY METHODS
|
256
|
-
####################################################################
|
257
|
-
|
258
|
-
# Returns the size in bytes of a pixel whe it is stored using a given color mode
|
259
|
-
# @param [Fixnum] color_mode The color mode in which the pixels are stored
|
260
|
-
# @return [Fixnum] The number of bytes used per pixel in a datastream.
|
261
|
-
def self.bytesize(color_mode)
|
262
|
-
case color_mode
|
263
|
-
when ChunkyPNG::COLOR_INDEXED then 1
|
264
|
-
when ChunkyPNG::COLOR_TRUECOLOR then 3
|
265
|
-
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA then 4
|
266
|
-
when ChunkyPNG::COLOR_GRAYSCALE then 1
|
267
|
-
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA then 2
|
268
|
-
else raise "Don't know the bytesize of pixels in this colormode: #{color_mode}!"
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
@@ -1,136 +0,0 @@
|
|
1
|
-
module ChunkyPNG
|
2
|
-
|
3
|
-
# The ChunkPNG::PixelMatrix class represents a matrix of pixels of which an
|
4
|
-
# image consists. This class supports loading a PixelMatrix from a PNG datastream,
|
5
|
-
# and creating a PNG datastream bse don this matrix.
|
6
|
-
#
|
7
|
-
# This class offers per-pixel access to the matrix by using x,y coordinates. It uses
|
8
|
-
# a palette (see {ChunkyPNG::Palette}) to keep track of the different colors used in
|
9
|
-
# this matrix.
|
10
|
-
#
|
11
|
-
# The pixels in the matrix are stored as 4-byte fixnums. When accessing these pixels,
|
12
|
-
# these Fixnums are wrapped in a {ChunkyPNG::Pixel} instance to simplify working with them.
|
13
|
-
#
|
14
|
-
# @see ChunkyPNG::Datastream
|
15
|
-
class PixelMatrix
|
16
|
-
|
17
|
-
include Encoding
|
18
|
-
extend Decoding
|
19
|
-
|
20
|
-
include Operations
|
21
|
-
|
22
|
-
# @return [Integer] The number of columns in this pixel matrix
|
23
|
-
attr_reader :width
|
24
|
-
|
25
|
-
# @return [Integer] The number of rows in this pixel matrix
|
26
|
-
attr_reader :height
|
27
|
-
|
28
|
-
# @return [Array<ChunkyPNG::Pixel>] The list of pixels in this matrix.
|
29
|
-
# This array always should have +width * height+ elements.
|
30
|
-
attr_reader :pixels
|
31
|
-
|
32
|
-
# Initializes a new PixelMatrix instance
|
33
|
-
# @param [Integer] width The width in pixels of this matrix
|
34
|
-
# @param [Integer] width The height in pixels of this matrix
|
35
|
-
# @param [ChunkyPNG::Pixel, Array<ChunkyPNG::Pixel>] initial The initial value of te pixels:
|
36
|
-
#
|
37
|
-
# * If a color is passed to this parameter, this color will be used as background color.
|
38
|
-
#
|
39
|
-
# * If an array of pixels is provided, these pixels will be used as initial value. Note
|
40
|
-
# that the amount of pixels in this array should equal +width * height+.
|
41
|
-
def initialize(width, height, initial = ChunkyPNG::Pixel::TRANSPARENT)
|
42
|
-
|
43
|
-
@width, @height = width, height
|
44
|
-
|
45
|
-
if initial.kind_of?(ChunkyPNG::Pixel)
|
46
|
-
@pixels = Array.new(width * height, initial.to_i)
|
47
|
-
elsif initial.kind_of?(Array) && initial.size == width * height
|
48
|
-
@pixels = initial.map(&:to_i)
|
49
|
-
else
|
50
|
-
raise "Cannot use this value as initial pixel matrix: #{initial.inspect}!"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Returns the size ([width, height]) for this matrix.
|
55
|
-
# @return Array An array with the width and height of this matrix as elements.
|
56
|
-
def size
|
57
|
-
[@width, @height]
|
58
|
-
end
|
59
|
-
|
60
|
-
# Replaces a single pixel in this matrix.
|
61
|
-
# @param [Integer] x The x-coordinate of the pixel (column)
|
62
|
-
# @param [Integer] y The y-coordinate of the pixel (row)
|
63
|
-
# @param [ChunkyPNG::Pixel] pixel The new pixel for the provided coordinates.
|
64
|
-
def []=(x, y, pixel)
|
65
|
-
@pixels[y * width + x] = pixel.to_i
|
66
|
-
end
|
67
|
-
|
68
|
-
# Returns a single pixel from this matrix.
|
69
|
-
# @param [Integer] x The x-coordinate of the pixel (column)
|
70
|
-
# @param [Integer] y The y-coordinate of the pixel (row)
|
71
|
-
# @return [ChunkyPNG::Pixel] The current pixel at the provided coordinates.
|
72
|
-
def [](x, y)
|
73
|
-
ChunkyPNG::Pixel.new(@pixels[y * width + x])
|
74
|
-
end
|
75
|
-
|
76
|
-
# Passes to this matrix of pixels line by line.
|
77
|
-
# @yield [Array<ChunkyPNG::Pixel>] An line of pixels
|
78
|
-
def each_scanline(&block)
|
79
|
-
height.times do |i|
|
80
|
-
scanline = @pixels[width * i, width].map { |fn| ChunkyPNG::Pixel.new(fn) }
|
81
|
-
yield(scanline)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Returns the palette used for this pixel matrix.
|
86
|
-
# @return [ChunkyPNG::Palette] A pallete which contains all the colors that are
|
87
|
-
# being used for this image.
|
88
|
-
def palette
|
89
|
-
ChunkyPNG::Palette.from_pixel_matrix(self)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Converts this PixelMatrix to a datastream, so that it can be saved as a PNG image.
|
93
|
-
# @param [Hash] constraints The constraints to use when encoding the matrix.
|
94
|
-
def to_datastream(constraints = {})
|
95
|
-
data = encode(constraints)
|
96
|
-
ds = Datastream.new
|
97
|
-
ds.header_chunk = Chunk::Header.new(data[:header])
|
98
|
-
ds.palette_chunk = data[:palette_chunk] if data[:palette_chunk]
|
99
|
-
ds.transparency_chunk = data[:transparency_chunk] if data[:transparency_chunk]
|
100
|
-
ds.data_chunks = ds.idat_chunks(data[:pixelstream])
|
101
|
-
ds.end_chunk = Chunk::End.new
|
102
|
-
return ds
|
103
|
-
end
|
104
|
-
|
105
|
-
# Equality check to compare this pixel matrix with other matrices.
|
106
|
-
# @param other The object to compare this Matrix to.
|
107
|
-
# @return [true, false] True if the size and pixel values of the other matrix
|
108
|
-
# are exactly the same as this matrix size and pixel values.
|
109
|
-
def eql?(other)
|
110
|
-
other.kind_of?(self.class) && other.pixels == self.pixels &&
|
111
|
-
other.width == self.width && other.height == self.height
|
112
|
-
end
|
113
|
-
|
114
|
-
alias :== :eql?
|
115
|
-
|
116
|
-
#################################################################
|
117
|
-
# CONSTRUCTORS
|
118
|
-
#################################################################
|
119
|
-
|
120
|
-
def self.from_rgb_stream(width, height, stream)
|
121
|
-
pixels = []
|
122
|
-
while pixeldata = stream.read(3)
|
123
|
-
pixels << ChunkyPNG::Pixel.from_rgb_stream(pixeldata)
|
124
|
-
end
|
125
|
-
self.new(width, height, pixels)
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.from_rgba_stream(width, height, stream)
|
129
|
-
pixels = []
|
130
|
-
while pixeldata = stream.read(4)
|
131
|
-
pixels << ChunkyPNG::Pixel.from_rgba_stream(pixeldata)
|
132
|
-
end
|
133
|
-
self.new(width, height, pixels)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|