1#![warn(warnings)]
2#![cfg_attr(test, deny(warnings))]
3
4extern crate byteorder;
35
36use std::convert::{AsRef};
37use std::error::Error;
38use std::fmt;
39use std::fs;
40use std::io;
41use std::io::{Cursor, Read, Write};
42use std::iter::Iterator;
43
44use ::CompressionType::*;
45use ::BmpVersion::*;
46
47pub use decoder::{BmpError, BmpErrorKind, BmpResult};
48
49#[cfg(test)]
50mod tests;
51
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
56pub struct Pixel {
57 pub r: u8,
58 pub g: u8,
59 pub b: u8
60}
61
62#[macro_export]
64macro_rules! px {
65 ($r:expr, $g:expr, $b:expr) => {
66 Pixel { r: $r as u8, g: $g as u8, b: $b as u8 }
67 }
68}
69
70macro_rules! file_size {
71 ($bpp:expr, $width:expr, $height:expr) => {{
72 let header_size = 2 + 12 + 40;
73 let row_size = (($bpp as f32 * $width as f32 + 31.0) / 32.0).floor() as u32 * 4;
74 (header_size as u32, $height as u32 * row_size)
75 }}
76}
77
78pub mod consts;
80
81mod decoder;
82pub mod encoder;
83
84#[derive(Clone, Debug, Eq, PartialEq)]
85enum BmpVersion {
86 Version1,
87 Version2,
88 Version3,
89 Version3NT,
90 Version4,
91}
92
93impl AsRef<str> for BmpVersion {
94 fn as_ref(&self) -> &str {
95 match *self {
96 Version1 => "BMP Version 1",
97 Version2 => "BMP Version 2",
98 Version3 => "BMP Version 3",
99 Version3NT => "BMP Version 3 NT",
100 Version4 => "BMP Version 4",
101 }
102 }
103}
104
105#[derive(Clone, Debug, Eq, PartialEq)]
106enum CompressionType {
107 Uncompressed,
108 Rle8bit,
109 Rle4bit,
110 BitfieldsEncoding,
112}
113
114impl CompressionType {
115 fn from_u32(val: u32) -> CompressionType {
116 match val {
117 1 => Rle8bit,
118 2 => Rle4bit,
119 3 => BitfieldsEncoding,
120 _ => Uncompressed,
121 }
122 }
123}
124
125impl AsRef<str> for CompressionType {
126 fn as_ref(&self) -> &str {
127 match *self {
128 Rle8bit => "RLE 8-bit",
129 Rle4bit => "RLE 4-bit",
130 BitfieldsEncoding => "Bitfields Encoding",
131 Uncompressed => "Uncompressed",
132 }
133 }
134}
135
136#[derive(Clone, Debug, Eq, PartialEq)]
137struct BmpHeader {
138 file_size: u32,
139 creator1: u16,
140 creator2: u16,
141 pixel_offset: u32
142}
143
144impl BmpHeader {
145 pub fn new(header_size: u32, data_size: u32) -> BmpHeader {
146 BmpHeader {
147 file_size: header_size + data_size,
148 creator1: 0 ,
149 creator2: 0 ,
150 pixel_offset: header_size
151 }
152 }
153}
154
155#[derive(Clone, Debug, Eq, PartialEq)]
156struct BmpDibHeader {
157 header_size: u32,
158 width: i32,
159 height: i32,
160 num_planes: u16,
161 bits_per_pixel: u16,
162 compress_type: u32,
163 data_size: u32,
164 hres: i32,
165 vres: i32,
166 num_colors: u32,
167 num_imp_colors: u32,
168}
169
170impl BmpDibHeader {
171 pub fn new(width: i32, height: i32) -> BmpDibHeader {
172 let row_size = ((24.0 * width as f32 + 31.0) / 32.0).floor() as u32 * 4;
173 let pixel_array_size = row_size * height as u32;
174
175 BmpDibHeader {
176 header_size: 40,
177 width: width,
178 height: height,
179 num_planes: 1,
180 bits_per_pixel: 24,
181 compress_type: 0,
182 data_size: pixel_array_size,
183 hres: 1000,
184 vres: 1000,
185 num_colors: 0,
186 num_imp_colors: 0
187 }
188 }
189}
190
191#[derive(Clone, Eq, PartialEq)]
201pub struct Image {
202 header: BmpHeader,
203 dib_header: BmpDibHeader,
204 color_palette: Option<Vec<Pixel>>,
205 width: u32,
206 height: u32,
207 padding: u32,
208 data: Vec<Pixel>
209}
210
211impl fmt::Debug for Image {
212 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
213 try!(write!(f, "Image {}\n", '{'));
214 try!(write!(f, "\theader: {:?},\n", self.header));
215 try!(write!(f, "\tdib_header: {:?},\n", self.dib_header));
216 try!(write!(f, "\tcolor_palette: {:?},\n", self.color_palette));
217 try!(write!(f, "\twidth: {:?},\n", self.width));
218 try!(write!(f, "\theight: {:?},\n", self.height));
219 try!(write!(f, "\tpadding: {:?},\n", self.padding));
220 write!(f, "{}", '}')
221 }
222}
223
224impl Image {
225 pub fn new(width: u32, height: u32) -> Image {
236 let mut data = Vec::with_capacity((width * height) as usize);
237 for _ in 0 .. width * height {
238 data.push(px!(0, 0, 0));
239 }
240
241 let (header_size, data_size) = file_size!(24, width, height);
242 Image {
243 header: BmpHeader::new(header_size, data_size),
244 dib_header: BmpDibHeader::new(width as i32, height as i32),
245 color_palette: None,
246 width: width,
247 height: height,
248 padding: width % 4,
249 data: data
250 }
251 }
252
253 #[inline]
255 pub fn get_width(&self) -> u32 {
256 self.width
257 }
258
259 #[inline]
261 pub fn get_height(&self) -> u32 {
262 self.height
263 }
264
265 #[inline]
276 pub fn set_pixel(&mut self, x: u32, y: u32, val: Pixel) {
277 self.data[((self.height - y - 1) * self.width + x) as usize] = val;
278 }
279
280 #[inline]
291 pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
292 self.data[((self.height - y - 1) * self.width + x) as usize]
293 }
294
295 #[inline]
308 pub fn coordinates(&self) -> ImageIndex {
309 ImageIndex::new(self.width as u32, self.height as u32)
310 }
311
312 pub fn save(&self, name: &str) -> io::Result<()> {
328 let bmp_data = try!(encoder::encode_image(self));
330 let mut bmp_file = try!(fs::File::create(name));
331 try!(bmp_file.write(&bmp_data));
332 Ok(())
333 }
334}
335
336pub fn open(name: &str) -> BmpResult<Image> {
348 let mut bytes = Vec::new();
349 let mut f = try!(fs::File::open(name));
350 try!(f.read_to_end(&mut bytes));
351 let mut bmp_data = Cursor::new(bytes);
352
353 decoder::decode_image(&mut bmp_data)
354}
355
356#[derive(Clone, Copy)]
361pub struct ImageIndex {
362 width: u32,
363 height: u32,
364 x: u32,
365 y: u32
366}
367
368impl ImageIndex {
369 fn new(width: u32, height: u32) -> ImageIndex {
370 ImageIndex {
371 width: width,
372 height: height,
373 x: 0,
374 y: 0
375 }
376 }
377}
378
379impl Iterator for ImageIndex {
380 type Item = (u32, u32);
381
382 fn next(&mut self) -> Option<(u32, u32)> {
383 if self.x < self.width && self.y < self.height {
384 let this = Some((self.x, self.y));
385 self.x += 1;
386 if self.x == self.width {
387 self.x = 0;
388 self.y += 1;
389 }
390 this
391 } else {
392 None
393 }
394 }
395}