///|
/// A perceptual-ish luminance value in the 0..255 range.
pub fn Rgba::luma(self : Rgba) -> Byte {
((
self.red().to_int() * 77 +
self.green().to_int() * 150 +
self.blue().to_int() * 29
) /
256).to_byte()
}
///|
pub fn Rgba::with_alpha(self : Rgba, alpha : Byte) -> Rgba {
rgba(self.red(), self.green(), self.blue(), alpha)
}
///|
pub fn Rgba::grayscale(self : Rgba) -> Rgba {
let value = self.luma()
rgba(value, value, value, self.alpha())
}
///|
pub fn Rgba::invert(self : Rgba) -> Rgba {
rgba(255 - self.red(), 255 - self.green(), 255 - self.blue(), self.alpha())
}
///|
pub fn Rgba::distance(self : Rgba, other : Rgba) -> Int {
let r = self.red().to_int() - other.red().to_int()
let g = self.green().to_int() - other.green().to_int()
let b = self.blue().to_int() - other.blue().to_int()
r * r + g * g + b * b
}
///|
/// Linear interpolation in byte space.
pub fn mix_color(
left : Rgba,
right : Rgba,
numerator : Int,
denominator : Int,
) -> Rgba {
if denominator <= 0 {
right
} else {
let amount = if numerator < 0 {
0
} else if numerator > denominator {
denominator
} else {
numerator
}
rgba(
((
left.red().to_int() * (denominator - amount) +
right.red().to_int() * amount
) /
denominator).to_byte(),
((
left.green().to_int() * (denominator - amount) +
right.green().to_int() * amount
) /
denominator).to_byte(),
((
left.blue().to_int() * (denominator - amount) +
right.blue().to_int() * amount
) /
denominator).to_byte(),
((
left.alpha().to_int() * (denominator - amount) +
right.alpha().to_int() * amount
) /
denominator).to_byte(),
)
}
}
///|
/// Pixel summary used to choose quantization and preview settings.
pub(all) struct CanvasStats {
pixel_count : Int
opaque_count : Int
transparent_count : Int
minimum_luma : Byte
maximum_luma : Byte
average_luma : Int
} derive(Debug)
///|
pub fn CanvasStats::pixel_count(self : CanvasStats) -> Int {
self.pixel_count
}
///|
pub fn CanvasStats::opaque_count(self : CanvasStats) -> Int {
self.opaque_count
}
///|
pub fn CanvasStats::transparent_count(self : CanvasStats) -> Int {
self.transparent_count
}
///|
pub fn CanvasStats::minimum_luma(self : CanvasStats) -> Byte {
self.minimum_luma
}
///|
pub fn CanvasStats::maximum_luma(self : CanvasStats) -> Byte {
self.maximum_luma
}
///|
pub fn CanvasStats::average_luma(self : CanvasStats) -> Int {
self.average_luma
}
///|
pub fn Canvas::stats(self : Canvas) -> CanvasStats {
if self.pixels.length() == 0 {
CanvasStats::{
pixel_count: 0,
opaque_count: 0,
transparent_count: 0,
minimum_luma: 0,
maximum_luma: 0,
average_luma: 0,
}
} else {
let mut opaque_pixels = 0
let mut transparent = 0
let mut minimum = 255
let mut maximum = 0
let mut total = 0
for color in self.pixels {
if color.alpha() == 255 {
opaque_pixels += 1
}
if color.alpha() == 0 {
transparent += 1
}
let luma = color.luma().to_int()
if luma < minimum {
minimum = luma
}
if luma > maximum {
maximum = luma
}
total += luma
}
CanvasStats::{
pixel_count: self.pixels.length(),
opaque_count: opaque_pixels,
transparent_count: transparent,
minimum_luma: minimum.to_byte(),
maximum_luma: maximum.to_byte(),
average_luma: total / self.pixels.length(),
}
}
}
///|
/// Apply a deterministic color transform selected by a small enum.
pub(all) enum ColorTransform {
Identity
Grayscale
Invert
Opaque
Transparent
} derive(Eq, Debug)
///|
fn apply_color_transform(color : Rgba, transform : ColorTransform) -> Rgba {
match transform {
Identity => color
Grayscale => color.grayscale()
Invert => color.invert()
Opaque => color.with_alpha(255)
Transparent => color.with_alpha(0)
}
}
///|
pub fn Canvas::map_colors(self : Canvas, transform : ColorTransform) -> Canvas {
let result = self.copy()
for i in 0.. Canvas {
self.map_colors(Grayscale)
}
///|
pub fn Canvas::invert(self : Canvas) -> Canvas {
self.map_colors(Invert)
}
///|
pub fn Canvas::tint(self : Canvas, tint~ : Rgba, strength~ : Int) -> Canvas {
let amount = if strength < 0 {
0
} else if strength > 255 {
255
} else {
strength
}
let result = self.copy()
for i in 0.. Canvas {
if self.width != target.width || self.height != target.height {
target.copy()
} else {
let result = self.copy()
for i in 0.. UInt {
let mut hash = 2166136261U
for color in self.pixels {
hash = (hash ^ color.red().to_uint()) * 16777619U
hash = (hash ^ color.green().to_uint()) * 16777619U
hash = (hash ^ color.blue().to_uint()) * 16777619U
hash = (hash ^ color.alpha().to_uint()) * 16777619U
}
hash
}