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
// 图像几何增强(纯 MoonBit):pad / add_border

///|
/// 在图像四周填充指定颜色,生成新尺寸 (width+2*px, height+2*py) 的新图像。
/// pad_color 长度应等于 channels,不足则循环使用。
pub fn pad(
  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),
  }
}

///|
/// 添加边框。top/right/bottom/left 分别为四边边框宽度,border_color 为边框颜色。
pub fn add_border(
  img : @types.Image,
  top : Int,
  right : Int,
  bottom : Int,
  left : Int,
  border_color : Array[Byte],
) -> @types.Image raise @types.LoadError {
  if top < 0 || right < 0 || bottom < 0 || left < 0 {
    raise @types.LoadError::DecodeFailed("border 宽度必须非负")
  }
  let ch = img.channels
  let new_w = img.width + left + right
  let new_h = img.height + top + bottom
  let out : Array[Byte] = Array::make(new_w * new_h * ch, b'\x00')
  let color_len = border_color.length()
  if color_len == 0 {
    raise @types.LoadError::DecodeFailed("border_color 不能为空")
  }
  for y in 0..<new_h {
    for x in 0..<new_w {
      let dst_off = (y * new_w + x) * ch
      if x >= left && x < left + img.width && y >= top && y < top + img.height {
        let src_off = ((y - top) * img.width + (x - left)) * 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] = border_color[c % color_len]
        }
      }
    }
  }
  @types.Image::{
    width: new_w,
    height: new_h,
    channels: ch,
    data: Bytes::from_array(out),
  }
}