chunky_png 1.0.0.beta2 → 1.0.0.rc1
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/.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.
|