1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// 高级 Resize 操作(纯 MoonBit):resize_to_cover / resize_to_contain
// 含裁剪和填充逻辑,属于高级算法层

///|
/// Resize 并裁剪到精确尺寸(cover 模式)。
/// 先按宽高比缩放使图像"覆盖"目标尺寸,然后居中裁剪多余部分。
pub fn resize_to_cover(
  img : @types.Image,
  target_w : Int,
  target_h : Int,
) -> @types.Image raise @types.LoadError {
  if target_w <= 0 || target_h <= 0 {
    raise @types.LoadError::DecodeFailed("目标尺寸必须为正数")
  }
  let scale_w = Float::from_int(target_w) / Float::from_int(img.width)
  let scale_h = Float::from_int(target_h) / Float::from_int(img.height)
  let scale = if scale_w > scale_h { scale_w } else { scale_h }
  let scaled_w = (Float::from_int(img.width) * scale).to_int()
  let scaled_h = (Float::from_int(img.height) * scale).to_int()
  let scaled = @pure_util.resize_pure(img, scaled_w, scaled_h)
  let x = (scaled_w - target_w) / 2
  let y = (scaled_h - target_h) / 2
  crop(scaled, x, y, target_w, target_h)
}

///|
/// Resize 到目标尺寸内(contain 模式),保持宽高比,不足部分用 fill_color 填充。
pub fn resize_to_contain(
  img : @types.Image,
  target_w : Int,
  target_h : Int,
  fill_color : Array[Byte],
) -> @types.Image raise @types.LoadError {
  if target_w <= 0 || target_h <= 0 {
    raise @types.LoadError::DecodeFailed("目标尺寸必须为正数")
  }
  let scale_w = Float::from_int(target_w) / Float::from_int(img.width)
  let scale_h = Float::from_int(target_h) / Float::from_int(img.height)
  let scale = if scale_w < scale_h { scale_w } else { scale_h }
  let scaled_w = (Float::from_int(img.width) * scale).to_int()
  let scaled_h = (Float::from_int(img.height) * scale).to_int()
  let scaled = @pure_util.resize_pure(img, scaled_w, scaled_h)
  let px = (target_w - scaled_w) / 2
  let py = (target_h - scaled_h) / 2
  pad_image(scaled, px, py, fill_color)
}

///|
/// 内部 pad 辅助函数:在图像四周填充指定颜色,生成新尺寸 (width+2*px, height+2*py) 的新图像。
fn pad_image(
  img : @types.Image,
  px : Int,
  py : Int,
  pad_color : Array[Byte],
) -> @types.Image raise @types.LoadError {
  if px < 0 || py < 0 {
    raise @types.LoadError::DecodeFailed("pad 填充必须非负")
  }
  let ch = img.channels
  let new_w = img.width + 2 * px
  let new_h = img.height + 2 * py
  let out : Array[Byte] = Array::make(new_w * new_h * ch, b'\x00')
  let color_len = pad_color.length()
  if color_len == 0 {
    raise @types.LoadError::DecodeFailed("pad_color 不能为空")
  }
  // 填充
  for y in 0..<new_h {
    for x in 0..<new_w {
      let dst_off = (y * new_w + x) * ch
      if x >= px && x < px + img.width && y >= py && y < py + img.height {
        // 拷贝原始像素
        let src_off = ((y - py) * img.width + (x - px)) * ch
        for c in 0..<ch {
          out[dst_off + c] = img.data[src_off + c]
        }
      } else {
        // 填充颜色
        for c in 0..<ch {
          out[dst_off + c] = pad_color[c % color_len]
        }
      }
    }
  }
  @types.Image::{
    width: new_w,
    height: new_h,
    channels: ch,
    data: Bytes::from_array(out),
  }
}