class ChunkyPNG::Canvas
The ChunkyPNG::Canvas
class represents a raster image as a matrix of pixels.
This class supports loading a Canvas
from a PNG datastream, and creating a {ChunkyPNG::Datastream PNG datastream} based on this matrix. ChunkyPNG
only supports 8-bit color depth, otherwise all of the PNG format’s variations are supported for both reading and writing.
This class offers per-pixel access to the matrix by using x,y coordinates. It uses a palette (see {ChunkyPNG::Palette}) to keep track of the different colors used in this matrix.
The pixels in the canvas are stored as 4-byte fixnum, representing 32-bit RGBA colors (8 bit per channel). The module {ChunkyPNG::Color} is provided to work more easily with these number as color values.
The module {ChunkyPNG::Canvas::Operations} is imported for operations on the whole canvas, like cropping and alpha compositing. Simple drawing functions are imported from the {ChunkyPNG::Canvas::Drawing} module.
Attributes
@return [Integer] The number of rows in this canvas
@return [Array<ChunkyPNG::Color>] The list of pixels in this canvas.
This array always should have +width * height+ elements.
@return [Integer] The number of columns in this canvas
Public Class Methods
Creates a new canvas instance by duplicating another instance. @param [ChunkyPNG::Canvas] canvas The canvas to duplicate @return [ChunkyPNG::Canvas] The newly constructed canvas instance.
# File lib/chunky_png/canvas.rb 105 def self.from_canvas(canvas) 106 new(canvas.width, canvas.height, canvas.pixels.dup) 107 end
Initializes a new Canvas
instance.
@overload initialize(width, height, background_color)
@param [Integer] width The width in pixels of this canvas @param [Integer] height The height in pixels of this canvas @param [Integer, ...] background_color The initial background color of this canvas. This can be a color value or any value that {ChunkyPNG::Color#parse} can handle.
@overload initialize(width, height, initial)
@param [Integer] width The width in pixels of this canvas @param [Integer] height The height in pixels of this canvas @param [Array<Integer>] initial The initial pizel values. Must be an array with <tt>width * height</tt> elements.
# File lib/chunky_png/canvas.rb 79 def initialize(width, height, initial = ChunkyPNG::Color::TRANSPARENT) 80 @width, @height = width, height 81 82 if initial.is_a?(Array) 83 pixel_count = width * height 84 unless initial.length == pixel_count 85 raise ArgumentError, "The initial array should have #{width}x#{height} = #{pixel_count} elements!" 86 end 87 @pixels = initial 88 else 89 @pixels = Array.new(width * height, ChunkyPNG::Color.parse(initial)) 90 end 91 end
Public Instance Methods
Returns a single pixel’s color value from this canvas. @param [Integer] x The x-coordinate of the pixel (column) @param [Integer] y The y-coordinate of the pixel (row) @return [Integer] The current color value at the provided coordinates. @raise [ChunkyPNG::OutOfBounds] when the coordinates are outside of the
image's dimensions.
@see get_pixel
# File lib/chunky_png/canvas.rb 174 def [](x, y) 175 assert_xy!(x, y) 176 @pixels[y * width + x] 177 end
Replaces a single pixel in this canvas. @param [Integer] x The x-coordinate of the pixel (column) @param [Integer] y The y-coordinate of the pixel (row) @param [Integer] color The new color for the provided coordinates. @return [Integer] The new color value for this pixel, i.e.
<tt>color</tt>.
@raise [ChunkyPNG::OutOfBounds] when the coordinates are outside of the
image's dimensions.
@see set_pixel
# File lib/chunky_png/canvas.rb 135 def []=(x, y, color) 136 assert_xy!(x, y) 137 @pixels[y * width + x] = ChunkyPNG::Color.parse(color) 138 end
Returns the area of this canvas in number of pixels. @return [Integer] The number of pixels in this canvas
# File lib/chunky_png/canvas.rb 122 def area 123 pixels.length 124 end
Returns an extracted column as vector of pixels. @param [Integer] x The 0-based column index. @return [Array<Integer>] The vector of pixels in the requested column.
# File lib/chunky_png/canvas.rb 200 def column(x) 201 assert_x!(x) 202 (0...height).inject([]) { |pixels, y| pixels << get_pixel(x, y) } 203 end
Returns the dimension (width x height) for this canvas. @return [ChunkyPNG::Dimension] A dimension instance with the width and
height set for this canvas.
# File lib/chunky_png/canvas.rb 116 def dimension 117 ChunkyPNG::Dimension.new(width, height) 118 end
Equality check to compare this canvas with other matrices. @param other The object to compare this Matrix to. @return [true, false] True if the size and pixel values of the other
canvas are exactly the same as this canvas's size and pixel values.
# File lib/chunky_png/canvas.rb 277 def eql?(other) 278 other.is_a?(self.class) && 279 other.pixels == pixels && 280 other.width == width && 281 other.height == height 282 end
Returns a single pixel from this canvas, without checking bounds. The return value for this method is undefined if the coordinates are out of bounds.
@param (see []
) @return [Integer] The current pixel at the provided coordinates.
# File lib/chunky_png/canvas.rb 185 def get_pixel(x, y) 186 @pixels[y * width + x] 187 end
Checks whether the given coordinates are in the range of the canvas @param [ChunkyPNG::Point, Array, Hash, String] point_like The point to
check.
@return [true, false] True if the x and y coordinates of the point are
within the limits of this canvas.
@see ChunkyPNG.Point
# File lib/chunky_png/canvas.rb 233 def include_point?(*point_like) 234 dimension.include?(ChunkyPNG::Point(*point_like)) 235 end
Checks whether the given x-coordinate is in the range of the canvas @param [Integer] x The y-coordinate of the pixel (column) @return [true, false] True if the x-coordinate is in the range of this
canvas.
# File lib/chunky_png/canvas.rb 262 def include_x?(x) 263 x >= 0 && x < width 264 end
Checks whether the given x- and y-coordinate are in the range of the canvas
@param [Integer] x The x-coordinate of the pixel (column) @param [Integer] y The y-coordinate of the pixel (row) @return [true, false] True if the x- and y-coordinate is in the range of
this canvas.
# File lib/chunky_png/canvas.rb 246 def include_xy?(x, y) 247 y >= 0 && y < height && x >= 0 && x < width 248 end
Checks whether the given y-coordinate is in the range of the canvas @param [Integer] y The y-coordinate of the pixel (row) @return [true, false] True if the y-coordinate is in the range of this
canvas.
# File lib/chunky_png/canvas.rb 254 def include_y?(y) 255 y >= 0 && y < height 256 end
Initializes a new Canvas
instances when being cloned. @param [ChunkyPNG::Canvas] other The canvas to duplicate @return [void] @private
# File lib/chunky_png/canvas.rb 97 def initialize_copy(other) 98 @width, @height = other.width, other.height 99 @pixels = other.pixels.dup 100 end
Alternative implementation of the inspect method. @return [String] A nicely formatted string representation of this canvas. @private
# File lib/chunky_png/canvas.rb 299 def inspect 300 inspected = +"<#{self.class.name} #{width}x#{height} [" 301 for y in 0...height 302 inspected << "\n\t[" << row(y).map { |p| ChunkyPNG::Color.to_hex(p) }.join(" ") << "]" 303 end 304 inspected << "\n]>" 305 end
Returns the palette used for this canvas. @return [ChunkyPNG::Palette] A palette which contains all the colors that
are being used for this image.
# File lib/chunky_png/canvas.rb 269 def palette 270 ChunkyPNG::Palette.from_canvas(self) 271 end
Replaces a column of pixels on this canvas. @param [Integer] x The 0-based column index. @param [Array<Integer>] vector The vector of pixels to replace the column
with.
@return [void]
# File lib/chunky_png/canvas.rb 220 def replace_column!(x, vector) 221 assert_x!(x) && assert_height!(vector.length) 222 for y in 0...height do 223 set_pixel(x, y, vector[y]) 224 end 225 end
Replaces a row of pixels on this canvas. @param [Integer] y The 0-based row index. @param [Array<Integer>] vector The vector of pixels to replace the row
with.
@return [void]
# File lib/chunky_png/canvas.rb 210 def replace_row!(y, vector) 211 assert_y!(y) && assert_width!(vector.length) 212 pixels[y * width, width] = vector 213 end
Returns an extracted row as vector of pixels @param [Integer] y The 0-based row index @return [Array<Integer>] The vector of pixels in the requested row
# File lib/chunky_png/canvas.rb 192 def row(y) 193 assert_y!(y) 194 pixels.slice(y * width, width) 195 end
Replaces a single pixel in this canvas, without bounds checking.
This method return value and effects are undefined for coordinates out of bounds of the canvas.
@param [Integer] x The x-coordinate of the pixel (column) @param [Integer] y The y-coordinate of the pixel (row) @param [Integer] color The new color for the provided coordinates. @return [Integer] The new color value for this pixel, i.e.
<tt>color</tt>.
# File lib/chunky_png/canvas.rb 150 def set_pixel(x, y, color) 151 @pixels[y * width + x] = color 152 end
Replaces a single pixel in this canvas, with bounds checking. It will do noting if the provided coordinates are out of bounds.
@param [Integer] x The x-coordinate of the pixel (column) @param [Integer] y The y-coordinate of the pixel (row) @param [Integer] color The new color value for the provided coordinates. @return [Integer] The new color value for this pixel, i.e.
<tt>color</tt>, or <tt>nil</tt> if the coordinates are out of bounds.
# File lib/chunky_png/canvas.rb 162 def set_pixel_if_within_bounds(x, y, color) 163 return unless include_xy?(x, y) 164 @pixels[y * width + x] = color 165 end
Creates an ChunkyPNG::Image
object from this canvas. @return [ChunkyPNG::Image] This canvas wrapped in an Image
instance.
# File lib/chunky_png/canvas.rb 292 def to_image 293 ChunkyPNG::Image.from_canvas(self) 294 end
Protected Instance Methods
Throws an exception if the vector_length does not match this canvas’ height.
# File lib/chunky_png/canvas.rb 344 def assert_height!(vector_length) 345 if height != vector_length 346 raise ChunkyPNG::ExpectationFailed, 347 "The length of the vector (#{vector_length}) does not match the canvas height (#{height})!" 348 end 349 true 350 end
Throws an exception if the matrix width and height does not match this canvas’ dimensions.
# File lib/chunky_png/canvas.rb 363 def assert_size!(matrix_width, matrix_height) 364 if width != matrix_width 365 raise ChunkyPNG::ExpectationFailed, 366 "The width of the matrix does not match the canvas width!" 367 end 368 if height != matrix_height 369 raise ChunkyPNG::ExpectationFailed, 370 "The height of the matrix does not match the canvas height!" 371 end 372 true 373 end
Throws an exception if the vector_length does not match this canvas’ width.
# File lib/chunky_png/canvas.rb 354 def assert_width!(vector_length) 355 if width != vector_length 356 raise ChunkyPNG::ExpectationFailed, 357 "The length of the vector (#{vector_length}) does not match the canvas width (#{width})!" 358 end 359 true 360 end
Throws an exception if the x-coordinate is out of bounds.
# File lib/chunky_png/canvas.rb 319 def assert_x!(x) 320 unless include_x?(x) 321 raise ChunkyPNG::OutOfBounds, "Column index #{x} out of bounds!" 322 end 323 true 324 end
Throws an exception if the x- or y-coordinate is out of bounds.
# File lib/chunky_png/canvas.rb 335 def assert_xy!(x, y) 336 unless include_xy?(x, y) 337 raise ChunkyPNG::OutOfBounds, "Coordinates (#{x},#{y}) out of bounds!" 338 end 339 true 340 end
Throws an exception if the y-coordinate is out of bounds.
# File lib/chunky_png/canvas.rb 327 def assert_y!(y) 328 unless include_y?(y) 329 raise ChunkyPNG::OutOfBounds, "Row index #{y} out of bounds!" 330 end 331 true 332 end
Replaces the image, given a new width, new height, and a new pixel array.
# File lib/chunky_png/canvas.rb 310 def replace_canvas!(new_width, new_height, new_pixels) 311 unless new_pixels.length == new_width * new_height 312 raise ArgumentError, "The provided pixel array should have #{new_width * new_height} items" 313 end 314 @width, @height, @pixels = new_width, new_height, new_pixels 315 self 316 end