Module: ChunkyPNG::Canvas::Drawing
- Included in:
- ChunkyPNG::Canvas
- Defined in:
- lib/chunky_png/canvas/drawing.rb
Overview
Drawing operations will not fail when something is drawn outside of the bounds of the canvas; these pixels will simply be ignored.
Module that adds some primitive drawing methods to ChunkyPNG::Canvas.
All of these methods change the current canvas instance and do not create a new one, even though the method names do not end with a bang.
Instance Method Summary collapse
-
#bezier_curve(points, stroke_color = ChunkyPNG::Color::BLACK) ⇒ Chunky:PNG::Canvas
Draws a Bezier curve.
-
#circle(x0, y0, radius, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) ⇒ ChunkyPNG::Canvas
Draws a circle on the canvas.
-
#compose_pixel(x, y, color) ⇒ Integer
Composes a pixel on the canvas by alpha blending a color with its background color.
-
#compose_pixel_unsafe(x, y, color) ⇒ Integer
Composes a pixel on the canvas by alpha blending a color with its background color, without bounds checking.
-
#line_xiaolin_wu(x0, y0, x1, y1, stroke_color, inclusive = true) ⇒ ChunkyPNG::Canvas
(also: #line)
Draws an anti-aliased line using Xiaolin Wu’s algorithm.
-
#polygon(path, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) ⇒ ChunkyPNG::Canvas
Draws a polygon on the canvas using the stroke_color, filled using the fill_color if any.
-
#rect(x0, y0, x1, y1, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) ⇒ ChunkyPNG::Canvas
Draws a rectangle on the canvas, using two control points.
Instance Method Details
#bezier_curve(points, stroke_color = ChunkyPNG::Color::BLACK) ⇒ Chunky:PNG::Canvas
Draws a Bezier curve
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/chunky_png/canvas/drawing.rb', line 35 def bezier_curve(points, stroke_color = ChunkyPNG::Color::BLACK) points = ChunkyPNG::Vector(*points) case points.length when 0, 1; return self when 2; return line(points[0].x, points[0].y, points[1].x, points[1].y, stroke_color) end curve_points = Array.new t = 0 n = points.length - 1 bicof = 0 while t <= 100 cur_p = ChunkyPNG::Point.new(0,0) # Generate a float of t. t_f = t / 100.00 cur_p.x += ((1 - t_f) ** n) * points[0].x cur_p.y += ((1 - t_f) ** n) * points[0].y for i in 1...points.length - 1 bicof = binomial_coefficient(n , i) cur_p.x += (bicof * (1 - t_f) ** (n - i)) * (t_f ** i) * points[i].x cur_p.y += (bicof * (1 - t_f) ** (n - i)) * (t_f ** i) * points[i].y i += 1 end cur_p.x += (t_f ** n) * points[n].x cur_p.y += (t_f ** n) * points[n].y curve_points << cur_p bicof = 0 t += 1 end curve_points.each_cons(2) do |p1, p2| line_xiaolin_wu(p1.x.round, p1.y.round, p2.x.round, p2.y.round, stroke_color) end return self end |
#circle(x0, y0, radius, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) ⇒ ChunkyPNG::Canvas
Draws a circle on the canvas.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/chunky_png/canvas/drawing.rb', line 236 def circle(x0, y0, radius, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) stroke_color = ChunkyPNG::Color.parse(stroke_color) fill_color = ChunkyPNG::Color.parse(fill_color) f = 1 - radius ddF_x = 1 ddF_y = -2 * radius x = 0 y = radius compose_pixel(x0, y0 + radius, stroke_color) compose_pixel(x0, y0 - radius, stroke_color) compose_pixel(x0 + radius, y0, stroke_color) compose_pixel(x0 - radius, y0, stroke_color) lines = [radius - 1] unless fill_color == ChunkyPNG::Color::TRANSPARENT while x < y if f >= 0 y -= 1 ddF_y += 2 f += ddF_y end x += 1 ddF_x += 2 f += ddF_x unless fill_color == ChunkyPNG::Color::TRANSPARENT lines[y] = lines[y] ? [lines[y], x - 1].min : x - 1 lines[x] = lines[x] ? [lines[x], y - 1].min : y - 1 end compose_pixel(x0 + x, y0 + y, stroke_color) compose_pixel(x0 - x, y0 + y, stroke_color) compose_pixel(x0 + x, y0 - y, stroke_color) compose_pixel(x0 - x, y0 - y, stroke_color) unless x == y compose_pixel(x0 + y, y0 + x, stroke_color) compose_pixel(x0 - y, y0 + x, stroke_color) compose_pixel(x0 + y, y0 - x, stroke_color) compose_pixel(x0 - y, y0 - x, stroke_color) end end unless fill_color == ChunkyPNG::Color::TRANSPARENT lines.each_with_index do |length, y| line(x0 - length, y0 - y, x0 + length, y0 - y, fill_color) if length > 0 line(x0 - length, y0 + y, x0 + length, y0 + y, fill_color) if length > 0 && y > 0 end end return self end |
#compose_pixel(x, y, color) ⇒ Integer
Composes a pixel on the canvas by alpha blending a color with its background color.
19 20 21 22 |
# File 'lib/chunky_png/canvas/drawing.rb', line 19 def compose_pixel(x, y, color) return unless include_xy?(x, y) compose_pixel_unsafe(x, y, ChunkyPNG::Color.parse(color)) end |
#compose_pixel_unsafe(x, y, color) ⇒ Integer
Composes a pixel on the canvas by alpha blending a color with its background color, without bounds checking.
28 29 30 |
# File 'lib/chunky_png/canvas/drawing.rb', line 28 def compose_pixel_unsafe(x, y, color) set_pixel(x, y, ChunkyPNG::Color.compose(color, get_pixel(x, y))) end |
#line_xiaolin_wu(x0, y0, x1, y1, stroke_color, inclusive = true) ⇒ ChunkyPNG::Canvas Also known as: line
Draws an anti-aliased line using Xiaolin Wu’s algorithm.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/chunky_png/canvas/drawing.rb', line 93 def line_xiaolin_wu(x0, y0, x1, y1, stroke_color, inclusive = true) stroke_color = ChunkyPNG::Color.parse(stroke_color) dx = x1 - x0 sx = dx < 0 ? -1 : 1 dx *= sx dy = y1 - y0 sy = dy < 0 ? -1 : 1 dy *= sy if dy == 0 # vertical line x0.step(inclusive ? x1 : x1 - sx, sx) do |x| compose_pixel(x, y0, stroke_color) end elsif dx == 0 # horizontal line y0.step(inclusive ? y1 : y1 - sy, sy) do |y| compose_pixel(x0, y, stroke_color) end elsif dx == dy # diagonal x0.step(inclusive ? x1 : x1 - sx, sx) do |x| compose_pixel(x, y0, stroke_color) y0 += sy end elsif dy > dx # vertical displacement compose_pixel(x0, y0, stroke_color) e_acc = 0 e = ((dx << 16) / dy.to_f).round (dy - 1).downto(0) do |i| e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xffff x0 += sx if (e_acc <= e_acc_temp) w = 0xff - (e_acc >> 8) compose_pixel(x0, y0, ChunkyPNG::Color.fade(stroke_color, w)) compose_pixel(x0 + sx, y0 + sy, ChunkyPNG::Color.fade(stroke_color, 0xff - w)) if inclusive || i > 0 y0 += sy end compose_pixel(x1, y1, stroke_color) if inclusive else # horizontal displacement compose_pixel(x0, y0, stroke_color) e_acc = 0 e = ((dy << 16) / dx.to_f).round (dx - 1).downto(0) do |i| e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xffff y0 += sy if (e_acc <= e_acc_temp) w = 0xff - (e_acc >> 8) compose_pixel(x0, y0, ChunkyPNG::Color.fade(stroke_color, w)) compose_pixel(x0 + sx, y0 + sy, ChunkyPNG::Color.fade(stroke_color, 0xff - w)) if inclusive || i > 0 x0 += sx end compose_pixel(x1, y1, stroke_color) if inclusive end return self end |
#polygon(path, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) ⇒ ChunkyPNG::Canvas
Draws a polygon on the canvas using the stroke_color, filled using the fill_color if any.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/chunky_png/canvas/drawing.rb', line 161 def polygon(path, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) vector = ChunkyPNG::Vector(*path) raise ArgumentError, "A polygon requires at least 3 points" if path.length < 3 stroke_color = ChunkyPNG::Color.parse(stroke_color) fill_color = ChunkyPNG::Color.parse(fill_color) # Fill unless fill_color == ChunkyPNG::Color::TRANSPARENT vector.y_range.each do |y| intersections = [] vector.edges.each do |p1, p2| if (p1.y < y && p2.y >= y) || (p2.y < y && p1.y >= y) intersections << (p1.x + (y - p1.y).to_f / (p2.y - p1.y) * (p2.x - p1.x)).round end end intersections.sort! 0.step(intersections.length - 1, 2) do |i| intersections[i].upto(intersections[i + 1]) do |x| compose_pixel(x, y, fill_color) end end end end # Stroke vector.each_edge do |(from_x, from_y), (to_x, to_y)| line(from_x, from_y, to_x, to_y, stroke_color, false) end return self end |
#rect(x0, y0, x1, y1, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) ⇒ ChunkyPNG::Canvas
Draws a rectangle on the canvas, using two control points.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/chunky_png/canvas/drawing.rb', line 205 def rect(x0, y0, x1, y1, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT) stroke_color = ChunkyPNG::Color.parse(stroke_color) fill_color = ChunkyPNG::Color.parse(fill_color) # Fill unless fill_color == ChunkyPNG::Color::TRANSPARENT [x0, x1].min.upto([x0, x1].max) do |x| [y0, y1].min.upto([y0, y1].max) do |y| compose_pixel(x, y, fill_color) end end end # Stroke line(x0, y0, x0, y1, stroke_color, false) line(x0, y1, x1, y1, stroke_color, false) line(x1, y1, x1, y0, stroke_color, false) line(x1, y0, x0, y0, stroke_color, false) return self end |