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.
420 421 422 423 424 |
# File 'lib/png.rb', line 420 def initialize width, height, background = Color::Background @width = width @height = height @data = Array.new(@height) { Array.new(@width, background) } end |
Instance Attribute Details
#data ⇒ Object (readonly)
Raw data
418 419 420 |
# File 'lib/png.rb', line 418 def data @data end |
#height ⇒ Object (readonly)
Height of the canvas
408 409 410 |
# File 'lib/png.rb', line 408 def height @height end |
#width ⇒ Object (readonly)
Width of the canvas
413 414 415 |
# File 'lib/png.rb', line 413 def width @width end |
Instance Method Details
#[](x, y) ⇒ Object
Retrieves the color of the pixel at (x
, y
).
429 430 431 432 433 |
# File 'lib/png.rb', line 429 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
.
438 439 440 441 442 443 |
# File 'lib/png.rb', line 438 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.
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 |
# File 'lib/png.rb', line 448 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.
468 469 470 471 472 473 474 |
# File 'lib/png.rb', line 468 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
479 480 481 482 483 484 485 486 487 488 489 |
# File 'lib/png.rb', line 479 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:
491 492 493 |
# File 'lib/png.rb', line 491 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.
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 564 565 |
# File 'lib/png.rb', line 507 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 e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF x0 += sx if (e_acc <= e_acc_temp) w = 0xFF-(e_acc >> 8) point(x0, y0, color.intensity(w)) 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 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
).
498 499 500 |
# File 'lib/png.rb', line 498 def point x, y, color self[x, y] = self[x, y].blend(color) end |
#to_s ⇒ Object
Returns an ASCII representation of this image
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/png.rb', line 570 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 image.join end |