aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/decode.rs37
-rw-r--r--src/encode.rs47
-rw-r--r--src/error.rs45
-rw-r--r--src/lib.rs49
4 files changed, 139 insertions, 39 deletions
diff --git a/src/decode.rs b/src/decode.rs
index 59dae97..a9abd37 100644
--- a/src/decode.rs
+++ b/src/decode.rs
@@ -1,15 +1,22 @@
1use std::io::{self, Cursor, Read}; 1use std::io::{Cursor, Read};
2 2
3use bitvec::prelude::*; 3use bitvec::prelude::*;
4use byteorder::{LittleEndian, ReadBytesExt}; 4use byteorder::{LittleEndian, ReadBytesExt};
5 5
6use crate::error::{OBIError, OBIResult};
6use crate::{FileHeader, Image, ImageInfoHeader}; 7use crate::{FileHeader, Image, ImageInfoHeader};
7 8
8pub fn decode_image(obi_data: &mut Cursor<Vec<u8>>) -> io::Result<Image> { 9pub fn decode_image(obi_data: &mut Cursor<Vec<u8>>) -> OBIResult<Image> {
9 // file header 10 // file header
10 let version = obi_data.read_u16::<LittleEndian>()?; 11 let version = obi_data
11 let file_size = obi_data.read_u32::<LittleEndian>()?; 12 .read_u16::<LittleEndian>()
12 let data_offset = obi_data.read_u32::<LittleEndian>()?; 13 .map_err(|_| OBIError::Decode)?;
14 let file_size = obi_data
15 .read_u32::<LittleEndian>()
16 .map_err(|_| OBIError::Decode)?;
17 let data_offset = obi_data
18 .read_u32::<LittleEndian>()
19 .map_err(|_| OBIError::Decode)?;
13 let file_header = FileHeader { 20 let file_header = FileHeader {
14 version, 21 version,
15 file_size, 22 file_size,
@@ -17,10 +24,18 @@ pub fn decode_image(obi_data: &mut Cursor<Vec<u8>>) -> io::Result<Image> {
17 }; 24 };
18 25
19 // image info header 26 // image info header
20 let width = obi_data.read_u32::<LittleEndian>()?; 27 let width = obi_data
21 let height = obi_data.read_u32::<LittleEndian>()?; 28 .read_u32::<LittleEndian>()
22 let compression_type = obi_data.read_u32::<LittleEndian>()?; 29 .map_err(|_| OBIError::Decode)?;
23 let post_compression_size = obi_data.read_u32::<LittleEndian>()?; 30 let height = obi_data
31 .read_u32::<LittleEndian>()
32 .map_err(|_| OBIError::Decode)?;
33 let compression_type = obi_data
34 .read_u32::<LittleEndian>()
35 .map_err(|_| OBIError::Decode)?;
36 let post_compression_size = obi_data
37 .read_u32::<LittleEndian>()
38 .map_err(|_| OBIError::Decode)?;
24 let image_info_header = ImageInfoHeader { 39 let image_info_header = ImageInfoHeader {
25 width, 40 width,
26 height, 41 height,
@@ -30,7 +45,9 @@ pub fn decode_image(obi_data: &mut Cursor<Vec<u8>>) -> io::Result<Image> {
30 45
31 // pixmap data 46 // pixmap data
32 let mut data_bytes = vec![]; 47 let mut data_bytes = vec![];
33 obi_data.read_to_end(&mut data_bytes)?; 48 obi_data
49 .read_to_end(&mut data_bytes)
50 .map_err(|_| OBIError::Decode)?;
34 let data = data_bytes 51 let data = data_bytes
35 .iter() 52 .iter()
36 .map(|&b| { 53 .map(|&b| {
diff --git a/src/encode.rs b/src/encode.rs
index e5760a8..a8c58e0 100644
--- a/src/encode.rs
+++ b/src/encode.rs
@@ -1,34 +1,55 @@
1use std::io; 1use std::borrow::Borrow;
2 2
3use bitvec::{prelude::*, vec::BitVec}; 3use bitvec::{prelude::*, vec::BitVec};
4use byteorder::{LittleEndian, WriteBytesExt}; 4use byteorder::{LittleEndian, WriteBytesExt};
5 5
6use crate::error::{OBIError, OBIResult};
6use crate::Image; 7use crate::Image;
7 8
8pub fn encode_image(obi_image: Image) -> io::Result<Vec<u8>> { 9pub fn encode_image<I>(obi_image: I) -> OBIResult<Vec<u8>>
10where
11 I: Borrow<Image>,
12{
13 let obi_image = obi_image.borrow();
9 let mut obi_data = Vec::with_capacity(obi_image.file_header.file_size as usize); 14 let mut obi_data = Vec::with_capacity(obi_image.file_header.file_size as usize);
10 15
11 // file header 16 // file header
12 let file_header = obi_image.file_header; 17 let file_header = &obi_image.file_header;
13 obi_data.write_u16::<LittleEndian>(file_header.version)?; 18 obi_data
14 obi_data.write_u32::<LittleEndian>(file_header.file_size)?; 19 .write_u16::<LittleEndian>(file_header.version)
15 obi_data.write_u32::<LittleEndian>(file_header.data_offset)?; 20 .map_err(|_| OBIError::Encode)?;
21 obi_data
22 .write_u32::<LittleEndian>(file_header.file_size)
23 .map_err(|_| OBIError::Encode)?;
24 obi_data
25 .write_u32::<LittleEndian>(file_header.data_offset)
26 .map_err(|_| OBIError::Encode)?;
16 27
17 // image info header 28 // image info header
18 let image_info_header = obi_image.image_info_header; 29 let image_info_header = &obi_image.image_info_header;
19 obi_data.write_u32::<LittleEndian>(image_info_header.width)?; 30 obi_data
20 obi_data.write_u32::<LittleEndian>(image_info_header.height)?; 31 .write_u32::<LittleEndian>(image_info_header.width)
21 obi_data.write_u32::<LittleEndian>(image_info_header.compression_type)?; 32 .map_err(|_| OBIError::Encode)?;
22 obi_data.write_u32::<LittleEndian>(image_info_header.post_compression_size)?; 33 obi_data
34 .write_u32::<LittleEndian>(image_info_header.height)
35 .map_err(|_| OBIError::Encode)?;
36 obi_data
37 .write_u32::<LittleEndian>(image_info_header.compression_type)
38 .map_err(|_| OBIError::Encode)?;
39 obi_data
40 .write_u32::<LittleEndian>(image_info_header.post_compression_size)
41 .map_err(|_| OBIError::Encode)?;
23 42
24 // pixmap data 43 // pixmap data
25 let pixmap = obi_image.data; 44 let pixmap = &obi_image.data;
26 for byte in pixmap.chunks(8) { 45 for byte in pixmap.chunks(8) {
27 let mut bv = BitVec::<Lsb0, u8>::new(); 46 let mut bv = BitVec::<Lsb0, u8>::new();
28 for &b in byte { 47 for &b in byte {
29 bv.push(b); 48 bv.push(b);
30 } 49 }
31 obi_data.write_u8(bv.load::<u8>())?; 50 obi_data
51 .write_u8(bv.load::<u8>())
52 .map_err(|_| OBIError::Encode)?;
32 } 53 }
33 54
34 return Ok(obi_data); 55 return Ok(obi_data);
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..8c2f096
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,45 @@
1use std::{error, fmt};
2
3pub type OBIResult<T> = Result<T, OBIError>;
4
5#[derive(Debug)]
6pub enum OBIError {
7 Encode,
8 Decode,
9 Image,
10}
11
12impl fmt::Display for OBIError {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 match self {
15 OBIError::Encode => writeln!(f, "Encoding error"),
16 OBIError::Decode => writeln!(f, "Decoding error"),
17 OBIError::Image => writeln!(f, "Image manipulation error"),
18 }
19 }
20}
21
22impl error::Error for OBIError {}
23
24#[derive(Debug)]
25enum Encode {
26 Metadata(MetadataError),
27 ChunkError(u32),
28}
29
30#[derive(Debug)]
31enum Decode {
32 Metadata(MetadataError),
33 ChunkError(u32),
34}
35
36#[derive(Debug)]
37enum MetadataError {
38 VersionError,
39 FileSizeError,
40 DataOffsetError,
41 WidthError,
42 HeightError,
43 CompressionTypeError,
44 PostCompressionSizeError,
45}
diff --git a/src/lib.rs b/src/lib.rs
index cd7923c..7429101 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,8 +1,13 @@
1#![allow(unreachable_patterns)] 1#![allow(unreachable_patterns)]
2#![allow(non_snake_case)] 2#![allow(non_snake_case)]
3 3
4pub mod decode; 4use std::io;
5pub mod encode; 5
6mod decode;
7mod encode;
8pub mod error;
9
10use crate::error::{OBIError, OBIResult};
6 11
7#[non_exhaustive] 12#[non_exhaustive]
8#[derive(Copy, Clone, Debug, PartialEq)] 13#[derive(Copy, Clone, Debug, PartialEq)]
@@ -59,6 +64,7 @@ impl ImageInfoHeader {
59} 64}
60 65
61#[non_exhaustive] 66#[non_exhaustive]
67#[derive(Copy, Clone, Debug, PartialEq)]
62pub enum CompressionType { 68pub enum CompressionType {
63 RLE, 69 RLE,
64 Kosinki, 70 Kosinki,
@@ -96,23 +102,34 @@ impl Image {
96 data, 102 data,
97 } 103 }
98 } 104 }
99}
100 105
101#[cfg(test)] 106 pub fn width(&self) -> u32 {
102mod tests { 107 self.image_info_header.width
103 use super::*; 108 }
104 use std::mem::size_of; 109
110 pub fn height(&self) -> u32 {
111 self.image_info_header.height
112 }
113
114 fn to_index(&self, x: u32, y: u32) -> usize {
115 (y * self.width() + x) as usize
116 }
117
118 pub fn set_pixel(&mut self, x: u32, y: u32, val: bool) -> OBIResult<()> {
119 if x >= self.width() || y > self.height() {
120 Err(OBIError::Image)
121 } else {
122 let index = self.to_index(x, y);
123 self.data[index] = val;
124 Ok(())
125 }
126 }
105 127
106 #[test] 128 pub fn encode(&self) -> OBIResult<Vec<u8>> {
107 fn size_of_image_info_header() { 129 encode::encode_image(self)
108 let file_header_size = size_of::<ImageInfoHeader>();
109 assert_eq!(16, file_header_size);
110 } 130 }
111 131
112 #[test] 132 pub fn decode(data: &mut io::Cursor<Vec<u8>>) -> OBIResult<Image> {
113 fn encode_decode() { 133 decode::decode_image(data)
114 let img = Image::new(100, 80);
115 let encoded = encode::encode_image(img).unwrap();
116 assert_eq!(encoded.len(), 1026);
117 } 134 }
118} 135}