///|
/// Smaller of two integers, kept local so the block/window filters stay
/// dependency-free.
fn imin(a : Int, b : Int) -> Int {
if a < b {
a
} else {
b
}
}
///|
/// Sepia tone: the classic warm photographic look, using the widely used
/// Microsoft sepia coefficients scaled by 1000 for exact integer math.
pub fn Image::sepia(self : Image) -> Image {
self.map_rgb(fn(r, g, b) {
let nr = (393 * r + 769 * g + 189 * b) / 1000
let ng = (349 * r + 686 * g + 168 * b) / 1000
let nb = (272 * r + 534 * g + 131 * b) / 1000
(nr, ng, nb)
})
}
///|
/// Binary threshold: pixels whose luma is at least `level` become white, the
/// rest black. Useful for masks and high-contrast stylization.
pub fn Image::threshold(self : Image, level : Int) -> Image {
self.map_rgb(fn(r, g, b) {
let y = (299 * r + 587 * g + 114 * b) / 1000
let v = if y >= level { 255 } else { 0 }
(v, v, v)
})
}
///|
/// Pixelate (mosaic): replaces each `block` x `block` tile with its average
/// color. Edge tiles are clipped to the image bounds.
pub fn Image::pixelate(self : Image, block : Int) -> Image {
let size = if block < 1 { 1 } else { block }
let out = Image::new(self.width, self.height)
let blocks_y = (self.height + size - 1) / size
let blocks_x = (self.width + size - 1) / size
for byi in 0.. Byte {
let vals = FixedArray::make(9, 0)
let mut k = 0
for dy in -1..<2 {
for dx in -1..<2 {
let sx = clamp_coord(x + dx, img.width)
let sy = clamp_coord(y + dy, img.height)
vals[k] = img.data[(sy * img.width + sx) * 4 + ch].to_int()
k = k + 1
}
}
for i in 1..<9 {
let v = vals[i]
let mut j = i - 1
while j >= 0 && vals[j] > v {
vals[j + 1] = vals[j]
j = j - 1
}
vals[j + 1] = v
}
clamp_byte(vals[4])
}
///|
/// 3x3 median filter applied independently to R, G and B; alpha is preserved.
pub fn Image::median(self : Image) -> Image {
let out = Image::new(self.width, self.height)
for y in 0.. Image {
let n = self.pixel_count()
let hist = FixedArray::make(256, 0)
for p in 0.. Image {
let l = if levels < 2 { 2 } else if levels > 256 { 256 } else { levels }
self.map_rgb(fn(r, g, b) {
let q = fn(c : Int) -> Int { c * l / 256 * 255 / (l - 1) }
(q(r), q(g), q(b))
})
}