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
// 纯 MoonBit PNM 格式编码器:PPM (P6) + PGM (P5)
// 移植自 src/format/pnm_encode.mbt,仅替换类型引用:
//   @core.Image -> @types.Image

///|
/// 编码为 PPM (P6 binary RGB) 格式。
/// 灰度输入自动转为 RGB,RGBA 输入丢弃 alpha。
pub fn encode_ppm_pure(img : @types.Image) -> Bytes {
  let w = img.width
  let h = img.height
  let ch = img.channels
  let n = w * h
  // 构建 RGB 像素数据
  let pixel_data : Array[Byte] = Array::make(n * 3, b'\x00')
  for i in 0..<n {
    let r = img.data[i * ch]
    let g = if ch >= 2 { img.data[i * ch + 1] } else { r }
    let b = if ch >= 3 { img.data[i * ch + 2] } else { r }
    pixel_data[i * 3] = r
    pixel_data[i * 3 + 1] = g
    pixel_data[i * 3 + 2] = b
  }
  // 头部: "P6\n{w} {h}\n255\n"
  let header = "P6\n" + w.to_string() + " " + h.to_string() + "\n255\n"
  let header_bytes = @encoding/utf8.encode(header)
  let result : Array[Byte] = []
  for i in 0..<header_bytes.length() {
    result.push(header_bytes[i])
  }
  for i in 0..<pixel_data.length() {
    result.push(pixel_data[i])
  }
  Bytes::from_array(result)
}

///|
/// 编码为 PGM (P5 binary grayscale) 格式。
/// RGB 输入自动转为灰度(BT.601),RGBA 丢弃 alpha。
pub fn encode_pgm_pure(img : @types.Image) -> Bytes {
  let w = img.width
  let h = img.height
  let ch = img.channels
  let n = w * h
  // 构建灰度像素数据
  let pixel_data : Array[Byte] = Array::make(n, b'\x00')
  for i in 0..<n {
    if ch == 1 {
      pixel_data[i] = img.data[i]
    } else {
      let r = img.data[i * ch].to_int()
      let g = img.data[i * ch + 1].to_int()
      let b = img.data[i * ch + 2].to_int()
      pixel_data[i] = ((r * 299 + g * 587 + b * 114) / 1000).to_byte()
    }
  }
  // 头部: "P5\n{w} {h}\n255\n"
  let header = "P5\n" + w.to_string() + " " + h.to_string() + "\n255\n"
  let header_bytes = @encoding/utf8.encode(header)
  let result : Array[Byte] = []
  for i in 0..<header_bytes.length() {
    result.push(header_bytes[i])
  }
  for i in 0..<pixel_data.length() {
    result.push(pixel_data[i])
  }
  Bytes::from_array(result)
}

///|
/// 自动选择 PNM 格式编码。
/// channels <= 1 → PGM (P5),否则 → PPM (P6)。
pub fn encode_pnm_pure(img : @types.Image) -> Bytes {
  if img.channels <= 1 {
    encode_pgm_pure(img)
  } else {
    encode_ppm_pure(img)
  }
}