///|
/// Bicubic resize using the Catmull-Rom spline: each output pixel blends a
/// 4x4 source neighborhood with cubic weights, giving noticeably smoother
/// results than bilinear on photographic content while staying local. Uses
/// the same center-aligned sampling and clamp-to-edge policy as the other
/// resizers, so a same-size resize stays an identity up to rounding.
///|
/// Catmull-Rom kernel weight for the four taps around fractional offset
/// `t` in [0, 1): returns the weights of taps at offsets -1, 0, +1, +2.
fn catmull_weights(t : Double) -> (Double, Double, Double, Double) {
let t2 = t * t
let t3 = t2 * t
// Standard Catmull-Rom (a = -0.5) expanded per tap.
let w0 = -0.5 * t3 + t2 - 0.5 * t
let w1 = 1.5 * t3 - 2.5 * t2 + 1.0
let w2 = -1.5 * t3 + 2.0 * t2 + 0.5 * t
let w3 = 0.5 * t3 - 0.5 * t2
(w0, w1, w2, w3)
}
///|
/// Bicubic (Catmull-Rom) resize to `new_width` x `new_height` (both clamped
/// to at least 1). All four channels including alpha are interpolated; the
/// cubic can overshoot near edges, so results are clamped back to 0..255.
/// An empty source produces transparent pixels at the requested size.
pub fn Image::resize_bicubic(
self : Image,
new_width : Int,
new_height : Int,
) -> Image {
let w = if new_width < 1 { 1 } else { new_width }
let h = if new_height < 1 { 1 } else { new_height }
let out = Image::new(w, h)
if self.width == 0 || self.height == 0 {
return out
}
for y in 0..