Class: PNG::Canvas
- Inherits:
-
Object
- Object
- PNG::Canvas
- Defined in:
- lib/png.rb,
lib/png/font.rb
Overview
A canvas used for drawing images. Origin is 0, 0 in the bottom left corner.
Instance Attribute Summary collapse
-
#data ⇒ Object
readonly
Raw data.
-
#height ⇒ Object
readonly
Height of the canvas.
-
#width ⇒ Object
readonly
Width of the canvas.
Instance Method Summary collapse
-
#[](x, y) ⇒ Object
Retrieves the color of the pixel at (
x
,y
). -
#[]=(x, y, color) ⇒ Object
Sets the color of the pixel at (
x
,y
) tocolor
. -
#annotate(string, x, y, font = PNG::Font.default, align = :left, style = :overwrite) ⇒ Object
Write a string at [x, y] with font, optionally specifying a font, an alignment of :left, :center, or :right and the style to draw the annotation (see #composite).
-
#composite(canvas, x, y, style = :overwrite) ⇒ Object
Composites another canvas onto self at the given (bottom left) coordinates.
-
#each ⇒ Object
Iterates over the canvas yielding x, y, and color.
-
#extract(x0, y0, x1, y1) ⇒ Object
Create a new canvas copying a region of the current canvas.
-
#initialize(width, height, background = Color::Background) ⇒ Canvas
constructor
A new instance of Canvas.
-
#inspect ⇒ Object
:nodoc:.
-
#line(x0, y0, x1, y1, color) ⇒ Object
Draws a line using Xiaolin Wu’s antialiasing technique.
-
#point(x, y, color) ⇒ Object
Blends
color
onto the color at point (x
,y
). -
#to_s ⇒ Object
Returns an ASCII representation of this image.
Constructor Details
#initialize(width, height, background = Color::Background) ⇒ Canvas
Returns a new instance of Canvas.
418 419 420 421 422 |
# File 'lib/png.rb', line 418 def initialize width, height, background = Color::Background @width = width @height = height @data = Array.new(@height) { |x| Array.new(@width, background) } end |
Instance Attribute Details
#data ⇒ Object (readonly)
Raw data
416 417 418 |
# File 'lib/png.rb', line 416 def data @data end |
#height ⇒ Object (readonly)
Height of the canvas
406 407 408 |
# File 'lib/png.rb', line 406 def height @height end |
#width ⇒ Object (readonly)
Width of the canvas
411 412 413 |
# File 'lib/png.rb', line 411 def width @width end |
Instance Method Details
#[](x, y) ⇒ Object
Retrieves the color of the pixel at (x
, y
).
427 428 429 430 431 |
# File 'lib/png.rb', line 427 def [] x, y raise "bad x value #{x} >= #{@width}" if x >= @width raise "bad y value #{y} >= #{@height}" if y >= @height @data[@height-y-1][x] end |
#[]=(x, y, color) ⇒ Object
Sets the color of the pixel at (x
, y
) to color
.
436 437 438 439 440 441 |
# File 'lib/png.rb', line 436 def []= x, y, color raise "bad x value #{x} >= #{@width}" if x >= @width raise "bad y value #{y} >= #{@height}" if y >= @height raise "bad color #{color.inspect}" unless color.kind_of? PNG::Color @data[@height-y-1][x] = color end |
#annotate(string, x, y, font = PNG::Font.default, align = :left, style = :overwrite) ⇒ Object
Write a string at [x, y] with font, optionally specifying a font, an alignment of :left, :center, or :right and the style to draw the annotation (see #composite).
require 'png/font'
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/png/font.rb', line 53 def annotate(string, x, y, font = PNG::Font.default, align = :left, style = :overwrite) case align when :left then # do nothing when :center then x -= string.length * font.width / 2 when :right then x -= string.length * font.width else raise ArgumentError, "Unknown align: #{align.inspect}" end x_offset, width = 0, font.width string.split(//).each do |char| self.composite font[char], x + x_offset, y x_offset += width end end |
#composite(canvas, x, y, style = :overwrite) ⇒ Object
Composites another canvas onto self at the given (bottom left) coordinates.
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
# File 'lib/png.rb', line 446 def composite canvas, x, y, style = :overwrite canvas.each do |x1, y1, color| case style when :overwrite then self[x+x1, y+y1] = color when :add, :underlay then self[x+x1, y+y1] = self[x+x1, y+y1] | color when :overlay then self[x+x1, y+y1] = color | self[x+x1, y+y1] when :blend then self.point x+x1, y+y1, color else raise "unknown style for composite: #{style.inspect}" end end end |
#each ⇒ Object
Iterates over the canvas yielding x, y, and color.
466 467 468 469 470 471 472 |
# File 'lib/png.rb', line 466 def each data.reverse.each_with_index do |row, y| row.each_with_index do |color, x| yield x, y, color end end end |
#extract(x0, y0, x1, y1) ⇒ Object
Create a new canvas copying a region of the current canvas
477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/png.rb', line 477 def extract x0, y0, x1, y1 canvas = Canvas.new(x1-x0+1, y1-y0+1) (x0..x1).each_with_index do |x2, x3| (y0..y1).each_with_index do |y2, y3| canvas[x3, y3] = self[x2, y2] end end canvas end |
#inspect ⇒ Object
:nodoc:
489 490 491 |
# File 'lib/png.rb', line 489 def inspect # :nodoc: '#<%s %dx%d>' % [self.class, @width, @height] end |
#line(x0, y0, x1, y1, color) ⇒ Object
Draws a line using Xiaolin Wu’s antialiasing technique.
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/png.rb', line 505 def line(x0, y0, x1, y1, color) y0, y1, x0, x1 = y1, y0, x1, x0 if y0 > y1 dx = x1 - x0 sx = dx < 0 ? -1 : 1 dx *= sx 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 x0.step(x1, sx) 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 (dx - 1).downto(0) 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
).
496 497 498 |
# File 'lib/png.rb', line 496 def point(x, y, color) self[x,y] = self[x,y].blend(color) end |
#to_s ⇒ Object
Returns an ASCII representation of this image
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
# File 'lib/png.rb', line 568 def to_s image = [] scale = (@width / 39) + 1 @data.each_with_index do |row, x| next if x % scale != 0 row.each_with_index do |color, y| next if y % scale != 0 image << color.to_ascii end image << "\n" end return image.join end |