///|
/// Cropping and padding: the two size-changing operations that book-end most
/// pipelines. Both work on whole pixels and preserve every channel exactly,
/// so `crop` after a matching `pad` round-trips an image bit-for-bit.
///|
/// Extracts the `w` x `h` rectangle whose top-left corner is `(x, y)`. The
/// requested rectangle is clamped to the source bounds, so the result is
/// never larger than the overlap with the image; out-of-range or empty
/// requests yield a 1x1 transparent image. Pixels are copied verbatim.
pub fn Image::crop(self : Image, x : Int, y : Int, w : Int, h : Int) -> Image {
// Clamp the rectangle to the image.
let x0 = if x < 0 { 0 } else if x > self.width { self.width } else { x }
let y0 = if y < 0 { 0 } else if y > self.height { self.height } else { y }
let x1_raw = x + w
let y1_raw = y + h
let x1 = if x1_raw < x0 {
x0
} else if x1_raw > self.width {
self.width
} else {
x1_raw
}
let y1 = if y1_raw < y0 {
y0
} else if y1_raw > self.height {
self.height
} else {
y1_raw
}
let cw = x1 - x0
let ch = y1 - y0
if cw <= 0 || ch <= 0 {
return Image::new(1, 1) // empty selection -> 1x1 transparent
}
let out = Image::new(cw, ch)
for row in 0.. Image {
let l = if left < 0 { 0 } else { left }
let t = if top < 0 { 0 } else { top }
let ri = if right < 0 { 0 } else { right }
let bo = if bottom < 0 { 0 } else { bottom }
let nw = l + self.width + ri
let nh = t + self.height + bo
let out = Image::new(nw, nh)
// Fill everything with the border color first.
for p in 0..<(nw * nh) {
let base = p * 4
out.data[base] = r
out.data[base + 1] = g
out.data[base + 2] = b
out.data[base + 3] = a
}
// Blit the original into place.
for y in 0..