chunky_png 1.0.0.beta2 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.infinity_test +1 -1
- data/README.rdoc +2 -2
- data/chunky_png.gemspec +4 -4
- data/lib/chunky_png.rb +14 -8
- data/lib/chunky_png/canvas.rb +110 -38
- data/lib/chunky_png/canvas/drawing.rb +175 -34
- data/lib/chunky_png/canvas/masking.rb +91 -0
- data/lib/chunky_png/canvas/operations.rb +141 -112
- data/lib/chunky_png/canvas/png_decoding.rb +13 -13
- data/lib/chunky_png/canvas/resampling.rb +42 -0
- data/lib/chunky_png/color.rb +252 -11
- data/lib/chunky_png/compatibility.rb +5 -5
- data/lib/chunky_png/dimension.rb +106 -0
- data/lib/chunky_png/point.rb +110 -0
- data/lib/chunky_png/vector.rb +92 -0
- data/spec/chunky_png/canvas/drawing_spec.rb +107 -14
- data/spec/chunky_png/canvas/masking_spec.rb +51 -0
- data/spec/chunky_png/canvas/operations_spec.rb +142 -75
- data/spec/chunky_png/canvas/resampling_spec.rb +31 -0
- data/spec/chunky_png/canvas/stream_exporting_spec.rb +20 -0
- data/spec/chunky_png/canvas/stream_importing_spec.rb +22 -0
- data/spec/chunky_png/canvas_spec.rb +151 -22
- data/spec/chunky_png/color_spec.rb +53 -0
- data/spec/chunky_png/dimension_spec.rb +43 -0
- data/spec/chunky_png/point_spec.rb +71 -0
- data/spec/chunky_png/vector_spec.rb +58 -0
- data/spec/resources/circles.png +0 -0
- data/spec/resources/clock_nn_xdown_ydown.png +0 -0
- data/spec/resources/clock_nn_xdown_yup.png +0 -0
- data/spec/resources/clock_nn_xup_yup.png +0 -0
- data/spec/resources/lines.png +0 -0
- data/spec/resources/partial_circles.png +0 -0
- data/spec/resources/polygon_filled_horizontal.png +0 -0
- data/spec/resources/polygon_filled_vertical.png +0 -0
- data/spec/resources/polygon_triangle_filled.png +0 -0
- data/spec/resources/polygon_unfilled.png +0 -0
- data/spec/resources/rect.png +0 -0
- metadata +31 -9
- data/spec/resources/clock_flip_horizontally.png +0 -0
- data/spec/resources/clock_flip_vertically.png +0 -0
- data/spec/resources/clock_rotate_180.png +0 -0
- data/spec/resources/clock_rotate_left.png +0 -0
- data/spec/resources/clock_rotate_right.png +0 -0
- data/spec/resources/clock_stubbed.png +0 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
module ChunkyPNG
|
2
|
+
class Canvas
|
3
|
+
|
4
|
+
# The ChunkyPNG::Canvas::Masking module defines methods to perform masking
|
5
|
+
# and theming oeprations on a {ChunkyPNG::Canvas}. The module is included into the Canvas class so all
|
6
|
+
# these methods are available on every canvas.
|
7
|
+
#
|
8
|
+
# @see ChunkyPNG::Canvas
|
9
|
+
module Masking
|
10
|
+
|
11
|
+
# Creates a new image, based on the current image but with a new theme color.
|
12
|
+
#
|
13
|
+
# This method will replace one color in an image with another image. This is done by
|
14
|
+
# first extracting the pixels with a color close to the original theme color as a mask
|
15
|
+
# image, changing the color of this mask image and then apply it on the original image.
|
16
|
+
#
|
17
|
+
# Mask extraction works best when the theme colored pixels are clearly distinguishable
|
18
|
+
# from a background color (preferably white). You can set a tolerance level to influence
|
19
|
+
# the extraction process.
|
20
|
+
#
|
21
|
+
# @param [Integer] old_theme_color The original theme color in this image.
|
22
|
+
# @param [Integer] new_theme_color The color to replace the old theme color with.
|
23
|
+
# @param [Integer] The backrgound color opn which the theme colored pixels are placed.
|
24
|
+
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
25
|
+
# the default; increase this if the masked image does not extract all the required pixels,
|
26
|
+
# decrease it if too many pixels get extracted.
|
27
|
+
# @return [ChunkyPNG::Canvas] Returns itself, but with the theme colored pixels changed.
|
28
|
+
# @see #change_theme_color!
|
29
|
+
# @see #change_mask_color!
|
30
|
+
def change_theme_color!(old_theme_color, new_theme_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
|
31
|
+
base, mask = extract_mask(old_theme_color, bg_color, tolerance)
|
32
|
+
mask.change_mask_color!(new_theme_color)
|
33
|
+
self.replace!(base.compose!(mask))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Creates a base image and a mask image from an original image that has a particular theme color.
|
37
|
+
# This can be used to easily change a theme color in an image.
|
38
|
+
#
|
39
|
+
# It will extract all the pixels that look like the theme color (with a tolerance level) and put
|
40
|
+
# these in a mask image. All the other pixels will be stored in a base image. Both images will be
|
41
|
+
# of the exact same size as the original image. The original image will be left untouched.
|
42
|
+
#
|
43
|
+
# The color of the mask image can be changed with {#change_mask_color!}. This new mask image can
|
44
|
+
# then be composed upon the base image to create an image with a new theme color. A call to
|
45
|
+
# {#change_theme_color!} will perform this in one go.
|
46
|
+
#
|
47
|
+
# @param [Integer] mask_color The current theme color.
|
48
|
+
# @param [Integer] bg_color The background color on which the theme colored pxiels are applied.
|
49
|
+
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
50
|
+
# the default; increase this if the masked image does not extract all the required pixels,
|
51
|
+
# decrease it if too many pixels get extracted.
|
52
|
+
# @return [Array<ChunkyPNG::Canvas, ChunkyPNG::Canvas>] An array with the base canvas and the mask
|
53
|
+
# canvas as elements.
|
54
|
+
# @see #change_theme_color!
|
55
|
+
# @see #change_mask_color!
|
56
|
+
def extract_mask(mask_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
|
57
|
+
base_pixels = []
|
58
|
+
mask_pixels = []
|
59
|
+
|
60
|
+
pixels.each do |pixel|
|
61
|
+
if ChunkyPNG::Color.alpha_decomposable?(pixel, mask_color, bg_color, tolerance)
|
62
|
+
mask_pixels << ChunkyPNG::Color.decompose_color(pixel, mask_color, bg_color, tolerance)
|
63
|
+
base_pixels << bg_color
|
64
|
+
else
|
65
|
+
mask_pixels << (mask_color & 0xffffff00)
|
66
|
+
base_pixels << pixel
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
[ self.class.new(width, height, base_pixels), self.class.new(width, height, mask_pixels) ]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Changes the color of a mask image.
|
74
|
+
#
|
75
|
+
# This method works on acanavs extracte out of another image using the {#extract_mask} method.
|
76
|
+
# It can then be applied on the extracted base image. See {#change_theme_color!} to perform
|
77
|
+
# these operations in one go.
|
78
|
+
#
|
79
|
+
# @param [Integer] new_color The color to replace the original mask color with.
|
80
|
+
# @raise [ChunkyPNG::ExpectationFailed] when this canvas is not a mask image, i.e. its palette
|
81
|
+
# has more than once color, disregarding transparency.
|
82
|
+
# @see #change_theme_color!
|
83
|
+
# @see #extract_mask
|
84
|
+
def change_mask_color!(new_color)
|
85
|
+
raise ChunkyPNG::ExpectationFailed, "This is not a mask image!" if palette.opaque_palette.size != 1
|
86
|
+
pixels.map! { |pixel| (new_color & 0xffffff00) | ChunkyPNG::Color.a(pixel) }
|
87
|
+
self
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -11,10 +11,11 @@ module ChunkyPNG
|
|
11
11
|
# @see ChunkyPNG::Canvas
|
12
12
|
module Operations
|
13
13
|
|
14
|
-
# Composes another image onto this image using alpha blending.
|
14
|
+
# Composes another image onto this image using alpha blending. This will modify
|
15
|
+
# the current canvas.
|
15
16
|
#
|
16
17
|
# If you simply want to replace pixels or when the other image does not have
|
17
|
-
# transparency, it is faster to use {#replace}.
|
18
|
+
# transparency, it is faster to use {#replace!}.
|
18
19
|
#
|
19
20
|
# @param [ChunkyPNG::Canvas] other The foreground canvas to compose on the
|
20
21
|
# current canvas, using alpha compositing.
|
@@ -22,9 +23,10 @@ module ChunkyPNG
|
|
22
23
|
# @param [Integer] offset_y The y-offset to apply the new forgeround on.
|
23
24
|
# @return [ChunkyPNG::Canvas] Returns itself, but with the other canvas composed onto it.
|
24
25
|
# @raise [ChunkyPNG::OutOfBounds] when the other canvas doesn't fit on this one,
|
25
|
-
# given the offset and size of the other
|
26
|
-
# @see #replace
|
27
|
-
|
26
|
+
# given the offset and size of the other canvas.
|
27
|
+
# @see #replace!
|
28
|
+
# @see #compose
|
29
|
+
def compose!(other, offset_x = 0, offset_y = 0)
|
28
30
|
check_size_constraints!(other, offset_x, offset_y)
|
29
31
|
|
30
32
|
for y in 0...other.height do
|
@@ -34,17 +36,41 @@ module ChunkyPNG
|
|
34
36
|
end
|
35
37
|
self
|
36
38
|
end
|
37
|
-
|
39
|
+
|
40
|
+
# Composes another image onto this image using alpha blending. This will return
|
41
|
+
# a new canvas and leave the original intact.
|
42
|
+
#
|
43
|
+
# If you simply want to replace pixels or when the other image does not have
|
44
|
+
# transparency, it is faster to use {#replace}.
|
45
|
+
#
|
46
|
+
# @param (see #compose!)
|
47
|
+
# @return [ChunkyPNG::Canvas] Returns the new canvas, composed of the other 2.
|
48
|
+
# @raise [ChunkyPNG::OutOfBounds] when the other canvas doesn't fit on this one,
|
49
|
+
# given the offset and size of the other canvas.
|
50
|
+
#
|
51
|
+
# @note API changed since 1.0 - This method now no longer is in place, but returns
|
52
|
+
# a new canvas and leaves the original intact. Use {#compose!} if you want to
|
53
|
+
# compose on the canvas in place.
|
54
|
+
# @see #replace
|
55
|
+
def compose(other, offset_x = 0, offset_y = 0)
|
56
|
+
dup.compose!(other, offset_x, offset_y)
|
57
|
+
end
|
58
|
+
|
38
59
|
# Replaces pixels on this image by pixels from another pixels, on a given offset.
|
60
|
+
# This method will modify the current canvas.
|
39
61
|
#
|
40
62
|
# This will completely replace the pixels of the background image. If you want to blend
|
41
|
-
# them with semi-transparent pixels from the foreground image, see {#compose}.
|
63
|
+
# them with semi-transparent pixels from the foreground image, see {#compose!}.
|
42
64
|
#
|
43
|
-
# @
|
65
|
+
# @param [ChunkyPNG::Canvas] other The foreground canvas to get the pixels from.
|
66
|
+
# @param [Integer] offset_x The x-offset to apply the new forgeround on.
|
67
|
+
# @param [Integer] offset_y The y-offset to apply the new forgeround on.
|
68
|
+
# @return [ChunkyPNG::Canvas] Returns itself, but with the other canvas placed onto it.
|
44
69
|
# @raise [ChunkyPNG::OutOfBounds] when the other canvas doesn't fit on this one,
|
45
|
-
# given the offset and size of the other
|
46
|
-
# @see #compose
|
47
|
-
|
70
|
+
# given the offset and size of the other canvas.
|
71
|
+
# @see #compose!
|
72
|
+
# @see #replace
|
73
|
+
def replace!(other, offset_x = 0, offset_y = 0)
|
48
74
|
check_size_constraints!(other, offset_x, offset_y)
|
49
75
|
|
50
76
|
for y in 0...other.height do
|
@@ -53,6 +79,25 @@ module ChunkyPNG
|
|
53
79
|
self
|
54
80
|
end
|
55
81
|
|
82
|
+
# Replaces pixels on this image by pixels from another pixels, on a given offset.
|
83
|
+
# This method will modify the current canvas.
|
84
|
+
#
|
85
|
+
# This will completely replace the pixels of the background image. If you want to blend
|
86
|
+
# them with semi-transparent pixels from the foreground image, see {#compose!}.
|
87
|
+
#
|
88
|
+
# @param (see #replace!)
|
89
|
+
# @return [ChunkyPNG::Canvas] Returns a new, combined canvas.
|
90
|
+
# @raise [ChunkyPNG::OutOfBounds] when the other canvas doesn't fit on this one,
|
91
|
+
# given the offset and size of the other canvas.
|
92
|
+
#
|
93
|
+
# @note API changed since 1.0 - This method now no longer is in place, but returns
|
94
|
+
# a new canvas and leaves the original intact. Use {#replace!} if you want to
|
95
|
+
# replace pixels on the canvas in place.
|
96
|
+
# @see #compose
|
97
|
+
def replace(other, offset_x = 0, offset_y = 0)
|
98
|
+
dup.replace!(other, offset_x, offset_y)
|
99
|
+
end
|
100
|
+
|
56
101
|
# Crops an image, given the coordinates and size of the image that needs to be cut out.
|
57
102
|
# This will leave the original image intact and return a new, cropped image with pixels
|
58
103
|
# copied from the original image.
|
@@ -76,125 +121,103 @@ module ChunkyPNG
|
|
76
121
|
ChunkyPNG::Canvas.new(crop_width, crop_height, new_pixels)
|
77
122
|
end
|
78
123
|
|
79
|
-
#
|
80
|
-
#
|
81
|
-
# This
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# the
|
88
|
-
#
|
89
|
-
# @
|
90
|
-
#
|
91
|
-
|
92
|
-
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
93
|
-
# the default; increase this if the masked image does not extract all the required pixels,
|
94
|
-
# decrease it if too many pixels get extracted.
|
95
|
-
# @return [ChunkyPNG::Canvas] Returns itself, but with the theme colored pixels changed.
|
96
|
-
# @see #change_theme_color!
|
97
|
-
# @see #change_mask_color!
|
98
|
-
def change_theme_color!(old_theme_color, new_theme_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
|
99
|
-
base, mask = extract_mask(old_theme_color, bg_color, tolerance)
|
100
|
-
mask.change_mask_color!(new_theme_color)
|
101
|
-
self.replace(base.compose(mask))
|
102
|
-
end
|
103
|
-
|
104
|
-
# Creates a base image and a mask image from an original image that has a particular theme color.
|
105
|
-
# This can be used to easily change a theme color in an image.
|
106
|
-
#
|
107
|
-
# It will extract all the pixels that look like the theme color (with a tolerance level) and put
|
108
|
-
# these in a mask image. All the other pixels will be stored in a base image. Both images will be
|
109
|
-
# of the exact same size as the original image. The original image will be left untouched.
|
110
|
-
#
|
111
|
-
# The color of the mask image can be changed with {#change_mask_color!}. This new mask image can
|
112
|
-
# then be composed upon the base image to create an image with a new theme color. A call to
|
113
|
-
# {#change_theme_color!} will perform this in one go.
|
114
|
-
#
|
115
|
-
# @param [Integer] mask_color The current theme color.
|
116
|
-
# @param [Integer] bg_color The background color on which the theme colored pxiels are applied.
|
117
|
-
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
118
|
-
# the default; increase this if the masked image does not extract all the required pixels,
|
119
|
-
# decrease it if too many pixels get extracted.
|
120
|
-
# @return [Array<ChunkyPNG::Canvas, ChunkyPNG::Canvas>] An array with the base canvas and the mask
|
121
|
-
# canvas as elements.
|
122
|
-
# @see #change_theme_color!
|
123
|
-
# @see #change_mask_color!
|
124
|
-
def extract_mask(mask_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
|
125
|
-
base_pixels = []
|
126
|
-
mask_pixels = []
|
127
|
-
|
128
|
-
pixels.each do |pixel|
|
129
|
-
if ChunkyPNG::Color.alpha_decomposable?(pixel, mask_color, bg_color, tolerance)
|
130
|
-
mask_pixels << ChunkyPNG::Color.decompose_color(pixel, mask_color, bg_color, tolerance)
|
131
|
-
base_pixels << bg_color
|
132
|
-
else
|
133
|
-
mask_pixels << (mask_color & 0xffffff00)
|
134
|
-
base_pixels << pixel
|
135
|
-
end
|
136
|
-
end
|
124
|
+
# Crops an image, given the coordinates and size of the image that needs to be cut out.
|
125
|
+
#
|
126
|
+
# This will change the size and content of the current canvas. Use {#crop} if you want to
|
127
|
+
# have a new canvas returned instead, leaving the current canvas intact.
|
128
|
+
#
|
129
|
+
# @param [Integer] x The x-coordinate of the top left corner of the image to be cropped.
|
130
|
+
# @param [Integer] y The y-coordinate of the top left corner of the image to be cropped.
|
131
|
+
# @param [Integer] crop_width The width of the image to be cropped.
|
132
|
+
# @param [Integer] crop_height The height of the image to be cropped.
|
133
|
+
# @return [ChunkyPNG::Canvas] Returns itself, but cropped.
|
134
|
+
# @raise [ChunkyPNG::OutOfBounds] when the crop dimensions plus the given coordinates
|
135
|
+
# are bigger then the original image.
|
136
|
+
def crop!(x, y, crop_width, crop_height)
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
#
|
147
|
-
# @param [Integer] new_color The color to replace the original mask color with.
|
148
|
-
# @raise [ChunkyPNG::ExpectationFailed] when this canvas is not a mask image, i.e. its palette
|
149
|
-
# has more than once color, disregarding transparency.
|
150
|
-
# @see #change_theme_color!
|
151
|
-
# @see #extract_mask
|
152
|
-
def change_mask_color!(new_color)
|
153
|
-
raise ChunkyPNG::ExpectationFailed, "This is not a mask image!" if palette.opaque_palette.size != 1
|
154
|
-
pixels.map! { |pixel| (new_color & 0xffffff00) | ChunkyPNG::Color.a(pixel) }
|
155
|
-
self
|
138
|
+
raise ChunkyPNG::OutOfBounds, "Image width is too small!" if crop_width + x > width
|
139
|
+
raise ChunkyPNG::OutOfBounds, "Image width is too small!" if crop_height + y > height
|
140
|
+
|
141
|
+
new_pixels = []
|
142
|
+
for cy in 0...crop_height do
|
143
|
+
new_pixels += pixels.slice((cy + y) * width + x, crop_width)
|
144
|
+
end
|
145
|
+
replace_canvas!(crop_width, crop_height, new_pixels)
|
156
146
|
end
|
157
147
|
|
158
|
-
# Flips the image horizontally.
|
148
|
+
# Flips the image horizontally, leaving the original intact.
|
159
149
|
#
|
160
150
|
# This will flip the image on its horizontal axis, e.g. pixels on the top will now
|
161
151
|
# be pixels on the bottom. Chaining this method twice will return the original canvas.
|
162
152
|
# This method will leave the original object intact and return a new canvas.
|
163
153
|
#
|
164
154
|
# @return [ChunkyPNG::Canvas] The flipped image
|
155
|
+
# @see #flip_horizontally!
|
165
156
|
def flip_horizontally
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
157
|
+
dup.flip_horizontally!
|
158
|
+
end
|
159
|
+
|
160
|
+
# Flips the image horizontally in place.
|
161
|
+
#
|
162
|
+
# This will flip the image on its horizontal axis, e.g. pixels on the top will now
|
163
|
+
# be pixels on the bottom. Chaining this method twice will return the original canvas.
|
164
|
+
# This method will leave the original object intact and return a new canvas.
|
165
|
+
#
|
166
|
+
# @return [ChunkyPNG::Canvas] Itself, but flipped
|
167
|
+
# @see #flip_horizontally
|
168
|
+
def flip_horizontally!
|
169
|
+
for y in 0..((height - 1) >> 1) do
|
170
|
+
other_y = height - (y + 1)
|
171
|
+
other_row = row(other_y)
|
172
|
+
replace_row!(other_y, row(y))
|
173
|
+
replace_row!(y, other_row)
|
170
174
|
end
|
175
|
+
return self
|
171
176
|
end
|
172
177
|
|
173
|
-
|
178
|
+
alias_method :flip!, :flip_horizontally!
|
179
|
+
alias_method :flip, :flip_horizontally
|
180
|
+
|
181
|
+
# Flips the image vertically, leaving the orginial intact.
|
174
182
|
#
|
175
183
|
# This will flip the image on its vertical axis, e.g. pixels on the left will now
|
176
184
|
# be pixels on the right. Chaining this method twice will return the original canvas.
|
177
185
|
# This method will leave the original object intact and return a new canvas.
|
178
186
|
#
|
179
187
|
# @return [ChunkyPNG::Canvas] The flipped image
|
188
|
+
# @see #flip_vertically!
|
180
189
|
def flip_vertically
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
190
|
+
dup.flip_vertically!
|
191
|
+
end
|
192
|
+
|
193
|
+
# Flips the image vertically in place.
|
194
|
+
#
|
195
|
+
# This will flip the image on its vertical axis, e.g. pixels on the left will now
|
196
|
+
# be pixels on the right. Chaining this method twice will return the original canvas.
|
197
|
+
# This method will leave the original object intact and return a new canvas.
|
198
|
+
#
|
199
|
+
# @return [ChunkyPNG::Canvas] Itself, but flipped
|
200
|
+
# @see #flip_vertically
|
201
|
+
def flip_vertically!
|
202
|
+
for y in 0...height do
|
203
|
+
replace_row!(y, row(y).reverse)
|
185
204
|
end
|
205
|
+
return self
|
186
206
|
end
|
207
|
+
|
208
|
+
alias_method :mirror!, :flip_vertically!
|
209
|
+
alias_method :mirror, :flip_vertically
|
187
210
|
|
188
211
|
# Rotates the image 90 degrees clockwise.
|
189
212
|
# This method will leave the original object intact and return a new canvas.
|
190
213
|
#
|
191
214
|
# @return [ChunkyPNG::Canvas] The rotated image
|
192
215
|
def rotate_right
|
193
|
-
self.class.new(height, width)
|
194
|
-
|
195
|
-
|
196
|
-
end
|
216
|
+
rotated = self.class.new(height, width)
|
217
|
+
for i in 0...width do
|
218
|
+
rotated.replace_row!(i, column(i).reverse)
|
197
219
|
end
|
220
|
+
return rotated
|
198
221
|
end
|
199
222
|
|
200
223
|
# Rotates the image 90 degrees counter-clockwise.
|
@@ -202,25 +225,31 @@ module ChunkyPNG
|
|
202
225
|
#
|
203
226
|
# @return [ChunkyPNG::Canvas] The rotated image.
|
204
227
|
def rotate_left
|
205
|
-
self.class.new(height, width)
|
206
|
-
|
207
|
-
|
208
|
-
end
|
228
|
+
rotated = self.class.new(height, width)
|
229
|
+
for i in 0...width do
|
230
|
+
rotated.replace_row!(width - (i + 1), column(i))
|
209
231
|
end
|
232
|
+
return rotated
|
210
233
|
end
|
211
|
-
|
234
|
+
|
212
235
|
# Rotates the image 180 degrees.
|
213
236
|
# This method will leave the original object intact and return a new canvas.
|
214
237
|
#
|
215
238
|
# @return [ChunkyPNG::Canvas] The rotated image.
|
239
|
+
# @see #rotate_180!
|
216
240
|
def rotate_180
|
217
|
-
|
218
|
-
for y in 0...height do
|
219
|
-
flipped.replace_row!(height - (y + 1), row(y).reverse)
|
220
|
-
end
|
221
|
-
end
|
241
|
+
dup.rotate_180!
|
222
242
|
end
|
223
|
-
|
243
|
+
|
244
|
+
# Rotates the image 180 degrees in place.
|
245
|
+
#
|
246
|
+
# @return [ChunkyPNG::Canvas] Itself, but rotated 180 degrees.
|
247
|
+
# @see #rotate_180
|
248
|
+
def rotate_180!
|
249
|
+
pixels.reverse!
|
250
|
+
return self
|
251
|
+
end
|
252
|
+
|
224
253
|
protected
|
225
254
|
|
226
255
|
# Checks whether another image has the correct dimension to be used for an operation
|
@@ -251,12 +251,12 @@ module ChunkyPNG
|
|
251
251
|
# @params (see #decode_png_pixels_from_scanline_indexed_1bit)
|
252
252
|
# @return (see #decode_png_pixels_from_scanline_indexed_1bit)
|
253
253
|
def decode_png_pixels_from_scanline_truecolor_alpha_16bit(stream, pos, width)
|
254
|
-
[]
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
end
|
254
|
+
pixels = []
|
255
|
+
stream.unpack("@#{pos + 1}n#{width * 4}").each_slice(4) do |r, g, b, a|
|
256
|
+
pixels << ChunkyPNG::Color.rgba(decode_png_resample_16bit_value(r), decode_png_resample_16bit_value(g),
|
257
|
+
decode_png_resample_16bit_value(b), decode_png_resample_16bit_value(a))
|
259
258
|
end
|
259
|
+
return pixels
|
260
260
|
end
|
261
261
|
|
262
262
|
# Decodes a scanline of an 8-bit, true color image into a row of pixels.
|
@@ -270,11 +270,11 @@ module ChunkyPNG
|
|
270
270
|
# @params (see #decode_png_pixels_from_scanline_indexed_1bit)
|
271
271
|
# @return (see #decode_png_pixels_from_scanline_indexed_1bit)
|
272
272
|
def decode_png_pixels_from_scanline_truecolor_16bit(stream, pos, width)
|
273
|
-
[]
|
274
|
-
|
275
|
-
|
276
|
-
end
|
273
|
+
pixels = []
|
274
|
+
stream.unpack("@#{pos + 1}n#{width * 3}").each_slice(3) do |r, g, b|
|
275
|
+
pixels << ChunkyPNG::Color.rgb(decode_png_resample_16bit_value(r), decode_png_resample_16bit_value(g), decode_png_resample_16bit_value(b))
|
277
276
|
end
|
277
|
+
return pixels
|
278
278
|
end
|
279
279
|
|
280
280
|
# Decodes a scanline of an 8-bit, grayscale image with transparency into a row of pixels.
|
@@ -288,11 +288,11 @@ module ChunkyPNG
|
|
288
288
|
# @params (see #decode_png_pixels_from_scanline_indexed_1bit)
|
289
289
|
# @return (see #decode_png_pixels_from_scanline_indexed_1bit)
|
290
290
|
def decode_png_pixels_from_scanline_grayscale_alpha_16bit(stream, pos, width)
|
291
|
-
[]
|
292
|
-
|
293
|
-
|
294
|
-
end
|
291
|
+
pixels = []
|
292
|
+
stream.unpack("@#{pos + 1}n#{width * 2}").each_slice(2) do |g, a|
|
293
|
+
pixels << ChunkyPNG::Color.grayscale_alpha(decode_png_resample_16bit_value(g), decode_png_resample_16bit_value(a))
|
295
294
|
end
|
295
|
+
return pixels
|
296
296
|
end
|
297
297
|
|
298
298
|
# Decodes a scanline of a 1-bit, grayscale image into a row of pixels.
|