Class: PNG::Canvas

Inherits:
Object
  • Object
show all
Defined in:
lib/PatchedPNG.rb

Overview

PNG canvas

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(height, width, background = Color::White) ⇒ Canvas

Returns a new instance of Canvas.



194
195
196
197
198
# File 'lib/PatchedPNG.rb', line 194

def initialize(height, width, background = Color::White)
  @height = height
  @width = width
  @data = Array.new(@width) { |x| Array.new(@height) { background } }
end

Instance Attribute Details

#dataObject (readonly)

Raw data



192
193
194
# File 'lib/PatchedPNG.rb', line 192

def data
  @data
end

#heightObject (readonly)

Height of the canvas



182
183
184
# File 'lib/PatchedPNG.rb', line 182

def height
  @height
end

#widthObject (readonly)

Width of the canvas



187
188
189
# File 'lib/PatchedPNG.rb', line 187

def width
  @width
end

Instance Method Details

#[](x, y) ⇒ Object

Retrieves the color of the pixel at (x, y).



203
204
205
206
207
# File 'lib/PatchedPNG.rb', line 203

def [](x, y)
  raise "bad x value #{x} >= #{@height}" if x >= @height
  raise "bad y value #{y} >= #{@width}" if y >= @width
  @data[y][x]
end

#[]=(x, y, color) ⇒ Object

Sets the color of the pixel at (x, y) to color.



212
213
214
215
216
# File 'lib/PatchedPNG.rb', line 212

def []=(x, y, color)
  raise "bad x value #{x} >= #{@height}" if x >= @height
  raise "bad y value #{y} >= #{@width}"  if y >= @width
  @data[y][x] = color
end

#eachObject

Iterates over each pixel in the canvas.



221
222
223
224
225
226
227
# File 'lib/PatchedPNG.rb', line 221

def each
  @data.each_with_index do |row, y|
    row.each_with_index do |pixel, x|
      yield x, y, color
    end
  end
end

#line(x0, y0, x1, y1, color) ⇒ Object

Draws a line using Xiaolin Wu’s antialiasing technique.

en.wikipedia.org/wiki/Xiaolin_Wu’s_line_algorithm



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
293
294
295
296
297
298
# File 'lib/PatchedPNG.rb', line 241

def line(x0, y0, x1, y1, color)
  dx = x1 - x0
  sx = dx < 0 ? -1 : 1
  dx *= sx # TODO: abs?
  dy = y1 - y0

  # 'easy' cases
  if dy == 0 then
    Range.new(*[x0,x1].sort).each do |x|
      point(x, y0, color)
    end
    return
  end

  if dx == 0 then
    (y0..y1).each do |y|
      point(x0, y, color)
    end
    return
  end

  if dx == dy then
    Range.new(*[x0,x1].sort).each do |x|
      point(x, y0, color)
      y0 += 1
    end
    return
  end

  # main loop
  point(x0, y0, color)
  e_acc = 0
  if dy > dx then # vertical displacement
    e = (dx << 16) / dy
    (y0...y1-1).each do |i|
      e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
      x0 = x0 + sx if (e_acc <= e_acc_temp) 
      w = 0xFF-(e_acc >> 8)
      point(x0, y0, color.intensity(w))
      y0 = y0 + 1
      point(x0 + sx, y0, color.intensity(0xFF-w))
    end
    point(x1, y1, color)
    return
  end

  # horizontal displacement
  e = (dy << 16) / dx
  (x0...(x1-sx)).each do |i|
    e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
    y0 += 1 if (e_acc <= e_acc_temp)
    w = 0xFF-(e_acc >> 8)
    point(x0, y0, color.intensity(w))
    x0 += sx
    point(x0, y0 + 1, color.intensity(0xFF-w))
  end
  point(x1, y1, color)
end

#point(x, y, color) ⇒ Object

Blends color onto the color at point (x, y).



232
233
234
# File 'lib/PatchedPNG.rb', line 232

def point(x, y, color)
  self[x,y] = self[x,y].blend(color)
end