///|
/// An in-memory RGBA raster for thumbnail previews and regression fixtures.
pub(all) struct Raster {
width : Int
height : Int
pixels : Array[Color]
} derive(Eq, Debug, ToJson)
///|
pub fn Raster::new(
width : Int,
height : Int,
fill? : Color = Color::rgb8(255, 255, 255),
) -> Raster {
let pixels = []
if width > 0 && height > 0 {
for _ in 0..<(width * height) {
pixels.push(fill)
}
}
{ width, height, pixels }
}
///|
pub fn Raster::in_bounds(self : Raster, x : Int, y : Int) -> Bool {
x >= 0 && y >= 0 && x < self.width && y < self.height
}
///|
pub fn Raster::index(self : Raster, x : Int, y : Int) -> Int {
y * self.width + x
}
///|
pub fn Raster::get(self : Raster, x : Int, y : Int) -> Color? {
if self.in_bounds(x, y) {
Some(self.pixels[self.index(x, y)])
} else {
None
}
}
///|
pub fn Raster::set(self : Raster, x : Int, y : Int, color : Color) -> Bool {
if self.in_bounds(x, y) {
self.pixels[self.index(x, y)] = color
true
} else {
false
}
}
///|
pub fn Raster::fill_rect(self : Raster, rect : Rect, color : Color) -> Unit {
let start_x = if rect.x.to_int() < 0 { 0 } else { rect.x.to_int() }
let start_y = if rect.y.to_int() < 0 { 0 } else { rect.y.to_int() }
let end_x = if rect.right().to_int() > self.width {
self.width
} else {
rect.right().to_int()
}
let end_y = if rect.bottom().to_int() > self.height {
self.height
} else {
rect.bottom().to_int()
}
for y in start_y.. Bool {
match self.get(x, y) {
Some(existing) => self.set(x, y, existing.over(color))
None => false
}
}
///|
/// Draws a filled polygon by scanning its bounding box.
pub fn Raster::fill_polygon(
self : Raster,
polygon : Array[Vec2],
color : Color,
) -> Unit {
let box_ = bounds_of_points(polygon)
let min_x = if box_.x.to_int() < 0 { 0 } else { box_.x.to_int() }
let min_y = if box_.y.to_int() < 0 { 0 } else { box_.y.to_int() }
let max_x = if box_.right().to_int() > self.width {
self.width
} else {
box_.right().to_int()
}
let max_y = if box_.bottom().to_int() > self.height {
self.height
} else {
box_.bottom().to_int()
}
for y in min_y.. Raster {
if factor <= 1 {
self
} else {
let width = self.width / factor
let height = self.height / factor
let result = Raster::new(width, height)
for y in 0.. {
total_r += color.r
total_g += color.g
total_b += color.b
total_a += color.a
count += 1
}
None => ()
}
}
}
if count > 0 {
let _ = result.set(
x,
y,
Color::rgba(
total_r / count.to_double(),
total_g / count.to_double(),
total_b / count.to_double(),
a=total_a / count.to_double(),
),
)
}
}
}
result
}
}
///|
pub fn Raster::histogram(self : Raster, bins : Int) -> Array[Int] {
let result = []
if bins > 0 {
for _ in 0..