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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#![no_std]
#![warn(missing_docs)]
#![doc(html_logo_url = "http://plopgrizzly.com/icon.png",
html_favicon_url = "http://plopgrizzly.com/icon.png",
html_root_url = "http://plopgrizzly.com/aci_png/")]
extern crate afi;
extern crate ami;
pub enum DecodeErrorPPM {
NotPPM,
BadNum,
}
impl ::core::fmt::Debug for DecodeErrorPPM {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "Couldn't parse PPM because: {}", match *self {
DecodeErrorPPM::NotPPM => "Not a PPM file (bad header)",
DecodeErrorPPM::BadNum => "Dimensions are not numbers",
})
}
}
fn skip_line(ppm: &'static [u8], index: &mut usize) {
while ppm[*index] != b'\n' {
*index += 1;
}
*index += 1;
}
fn utf8_to_u32(ppm: &'static [u8], index: &mut usize, until: u8)
-> Result<u32, DecodeErrorPPM>
{
let zero = b'0';
let mut number = 0;
while ppm[*index] != until {
let digit = ppm[*index];
number *= 10;
if digit != zero {
if digit < zero || digit > zero + 9 {
return Err(DecodeErrorPPM::BadNum);
}
number += (digit - zero) as u32;
}
*index += 1;
}
*index += 1;
Ok(number)
}
pub fn decode(ppm: &'static [u8]) -> Result<afi::Graphic, DecodeErrorPPM> {
let mut index = 3;
if ppm[0] != b'P' || ppm[1] != b'6' {
return Err(DecodeErrorPPM::NotPPM);
}
if ppm[index] == b'#' {
skip_line(ppm, &mut index);
}
let width = utf8_to_u32(ppm, &mut index, b' ')?;
let height = utf8_to_u32(ppm, &mut index, b'\n')?;
let size = (width * height) as usize;
let mut out : ami::Vec<u32> = ami::Vec::with_capacity(size + 2);
out.push(width);
out.push(height);
skip_line(ppm, &mut index);
let graphic = {
let buf = &ppm[index..];
let mut pixel : [u8;4] = [0xFF, 0xFF, 0xFF, 0xFF];
for i in 0..size {
pixel[0] = buf[i * 4 + 0];
pixel[1] = buf[i * 4 + 1];
pixel[2] = buf[i * 4 + 2];
pixel[3] = buf[i * 4 + 3];
out.push(unsafe {::core::mem::transmute(pixel)});
}
afi::GraphicBuilder::new().rgba(out)
};
Ok(graphic)
}