Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Wbmp Changelog

## Versions

### 0.1.1
- Change traits on Decoder.reader from `BufRead + Seek` to `Read`

### 0.1.0
- Initial implementation, basic encoding and decoding functionality
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "wbmp"
license = "MIT OR Apache-2.0"
version = "0.1.0"
version = "0.1.1"
description = "WBMP encoder and decoder"
authors = ["shane kenny <shanekenny023@gmail.com>"]
readme = "README.md"
Expand Down
1 change: 0 additions & 1 deletion src/color.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/// Color type of the image.
///
/// Wbmp does not support color images. This enum is used to indicate the
Expand Down
35 changes: 14 additions & 21 deletions src/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use std::io::Read;

use std::io::BufRead;
use std::io::Seek;

use crate::error::{
WbmpResult, WbmpError,
};
use crate::error::{WbmpError, WbmpResult};

const CONTINUATION_MASK: u8 = 0b10000000;
const DATA_MASK: u8 = 0b01111111;
Expand All @@ -17,18 +13,17 @@ pub struct Decoder<R> {
height: u32,
}

impl<R: BufRead + Seek> Decoder<R> {

impl<R: Read> Decoder<R> {
/// Create a new decoder that decodes from the stream ```reader```.
///
/// # Errors
/// - `WbmpError::UnsupportedType` occurs if the TypeField in the image
/// headers is not set to 0.
/// headers is not set to 0.
/// - `WbmpError::UnsupportedHeaders` occurs if extension headers are
/// specified in the image. Extension headers are not required for type
/// 0 WBMP images.
/// specified in the image. Extension headers are not required for type
/// 0 WBMP images.
/// - `WbmpError::IoError` occurs if the image headers are malformed or
/// if another IoError occurs while reading from the provided `reader`
/// if another IoError occurs while reading from the provided `reader`
///
/// ## Examples
/// ```
Expand All @@ -52,14 +47,13 @@ impl<R: BufRead + Seek> Decoder<R> {
height: 0,
}
}

/// Returns the `(width, height)` of the image.
pub fn dimensions(&self) -> (u32, u32) {
(self.width, self.height)
}

fn read_metadata(&mut self) -> WbmpResult<()> {

// TypeField
let image_type_buf: &mut [u8; 1] = &mut [0; 1];
self.reader.read_exact(image_type_buf)?;
Expand Down Expand Up @@ -92,7 +86,7 @@ impl<R: BufRead + Seek> Decoder<R> {
loop {
self.reader.read_exact(width_buf)?;
println!("{:x}", width_buf[0]);
self.width = (self.width<<7) | (width_buf[0] & DATA_MASK) as u32;
self.width = (self.width << 7) | (width_buf[0] & DATA_MASK) as u32;
if width_buf[0] & CONTINUATION_MASK != CONTINUATION_MASK {
break;
}
Expand All @@ -103,8 +97,7 @@ impl<R: BufRead + Seek> Decoder<R> {
// if the continuation bit is set, shift & read the next byte as well
loop {
self.reader.read_exact(height_buf)?;
self.height = (self.height << 7) |
(height_buf[0] & DATA_MASK) as u32;
self.height = (self.height << 7) | (height_buf[0] & DATA_MASK) as u32;
if height_buf[0] & CONTINUATION_MASK != CONTINUATION_MASK {
break;
}
Expand All @@ -119,9 +112,9 @@ impl<R: BufRead + Seek> Decoder<R> {
// convert each row, ignoring padding past self.width
let data_len = (self.width * self.height) as usize;
if buf.len() < data_len {
return Err(WbmpError::UsageError(
String::from("Provided buffer does not have enough capacity")
));
return Err(WbmpError::UsageError(String::from(
"Provided buffer does not have enough capacity",
)));
}

let row_bytes = if self.width % 8 == 0 {
Expand All @@ -140,7 +133,7 @@ impl<R: BufRead + Seek> Decoder<R> {
'bytes: for byte in bit_data.iter() {
let mut s = 7;
'bits: while read_idx < data_len {
if byte & (1<<s) == (1<<s) {
if byte & (1 << s) == (1 << s) {
buf[read_idx] = 0xFF;
}

Expand Down
63 changes: 20 additions & 43 deletions src/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@

use std::io::Write;

use crate::color::ColorType;
use crate::error::{
WbmpResult, WbmpError,
};
use crate::error::{WbmpError, WbmpResult};

/// Default threshold value for `Encoder`
const DEFAULT_THRESHOLD: u8 = 0x7F;
Expand All @@ -16,7 +13,6 @@ pub struct Encoder<'a, W: 'a> {
}

impl<'a, W: Write> Encoder<'a, W> {

/// Create a new decoder that decodes from the stream ```reader```.
///
/// ## Examples
Expand Down Expand Up @@ -45,7 +41,7 @@ impl<'a, W: Write> Encoder<'a, W> {

/// Set the greyscale threshold to use.
///
/// Greyscale values below this threshold (inclusive) will result in
/// Greyscale values below this threshold (inclusive) will result in
/// black pixels while values above will be white. Default 127.
pub fn with_threshold(mut self, threshold: u8) -> Self {
self.threshold = threshold;
Expand All @@ -60,28 +56,28 @@ impl<'a, W: Write> Encoder<'a, W> {
let mut a = a >> 7;
while a > 0 {
result.insert(0, 0b10000000 | ((a & BIT_MASK) as u8));
a = a >> 7;
a >>= 7;
}
result
}

/// Encodes the image `image` with dimensions `width` by `height` and
/// Encodes the image `image` with dimensions `width` by `height` and
/// `ColorType` `color_type`.
pub fn encode(
&mut self,
image: &[u8],
width: u32,
height: u32,
&mut self,
image: &[u8],
width: u32,
height: u32,
color_type: ColorType,
) -> WbmpResult<()> {
// write headers
let type_fix_header_fields: &[u8; 2] = &[0_u8; 2];
let width_bytes = Self::bytes_from_u32(width);
let height_bytes = Self::bytes_from_u32(height);

self.writer.write(type_fix_header_fields)?;
self.writer.write(&width_bytes)?;
self.writer.write(&height_bytes)?;
let _ = self.writer.write(type_fix_header_fields)?;
let _ = self.writer.write(&width_bytes)?;
let _ = self.writer.write(&height_bytes)?;

// map and write image data
match color_type {
Expand All @@ -91,12 +87,7 @@ impl<'a, W: Write> Encoder<'a, W> {
Ok(())
}

fn encode_luma8(
&mut self,
image: &[u8],
width: u32,
height: u32,
) -> WbmpResult<()> {
fn encode_luma8(&mut self, image: &[u8], width: u32, height: u32) -> WbmpResult<()> {
let data_len = (width * height) as usize;
if data_len != image.len() {
return Err(WbmpError::InvalidImageData);
Expand All @@ -105,18 +96,15 @@ impl<'a, W: Write> Encoder<'a, W> {
for row in image.chunks(width as usize) {
let mut byte: u8 = 0;
let mut bits: u8 = 0;
for i in 0..row.len() {

let pixel = row[i];

if pixel >= self.threshold {
byte |= 1<<(7-bits);
for (i, pixel) in row.iter().enumerate() {
if *pixel >= self.threshold {
byte |= 1 << (7 - bits);
}

bits += 1;

if bits == 8 || i == width as usize - 1 {
self.writer.write(&[byte; 1])?;
let _ = self.writer.write(&[byte; 1])?;
byte = 0;
bits = 0;
}
Expand All @@ -127,12 +115,7 @@ impl<'a, W: Write> Encoder<'a, W> {
Ok(())
}

fn encode_rgba8(
&mut self,
image: &[u8],
width: u32,
height: u32,
) -> WbmpResult<()> {
fn encode_rgba8(&mut self, image: &[u8], width: u32, height: u32) -> WbmpResult<()> {
let data_len = (width * height * 4) as usize;
if data_len != image.len() {
return Err(WbmpError::InvalidImageData);
Expand All @@ -143,19 +126,16 @@ impl<'a, W: Write> Encoder<'a, W> {
let mut byte: u8 = 0;
let mut bits: u8 = 0;
for (i, pixel) in row.chunks(4).enumerate() {

let pixel = pixel.iter()
.map(|c| *c as usize)
.sum::<usize>() / 4;
let pixel = pixel.iter().map(|c| *c as usize).sum::<usize>() / 4;

if pixel >= self.threshold as usize {
byte |= 1<<(7-bits);
byte |= 1 << (7 - bits);
}

bits += 1;

if bits == 8 || i == width as usize - 1 {
self.writer.write(&[byte; 1])?;
let _ = self.writer.write(&[byte; 1])?;
byte = 0;
bits = 0;
}
Expand All @@ -165,7 +145,4 @@ impl<'a, W: Write> Encoder<'a, W> {

Ok(())
}

}


36 changes: 15 additions & 21 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::error::Error;
use std::{io, fmt};
use std::{fmt, io};

/// Wbmp error kinds
#[derive(Debug)]
pub enum WbmpError {
/// An I/O Error occurred while decoding the image.
IoError(io::Error),
/// An Unsupported Image Type Identifier was encountered while decoding
/// An Unsupported Image Type Identifier was encountered while decoding
/// the image.
UnsupportedType(u8),
/// Unsupported Extension headers were encountered while decoding the
/// Unsupported Extension headers were encountered while decoding the
/// image.
UnsupportedHeaders,
/// The image does not support the requested operation
Expand All @@ -22,24 +22,18 @@ impl fmt::Display for WbmpError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
WbmpError::IoError(ref e) => e.fmt(fmt),
WbmpError::UsageError(ref f) => write!(
fmt,
"The requested operation could not be completed {}",
f,
),
WbmpError::UnsupportedType(ref f) => write!(
fmt,
"The Decoder does not support the image type `{}`",
f
),
WbmpError::UnsupportedHeaders => write!(
fmt,
"The Decoder does not support extension headers",
),
WbmpError::InvalidImageData => write!(
fmt,
"The Image data does not match the ColorType",
),
WbmpError::UsageError(ref f) => {
write!(fmt, "The requested operation could not be completed {}", f,)
}
WbmpError::UnsupportedType(ref f) => {
write!(fmt, "The Decoder does not support the image type `{}`", f)
}
WbmpError::UnsupportedHeaders => {
write!(fmt, "The Decoder does not support extension headers",)
}
WbmpError::InvalidImageData => {
write!(fmt, "The Image data does not match the ColorType",)
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
//! # Related Links
//! * <https://www.wapforum.org/what/technical/SPEC-WAESpec-19990524.pdf>

pub mod color;
pub mod decoder;
pub mod encoder;
mod error;
pub mod color;
pub mod error;

pub use crate::color::ColorType;
pub use crate::decoder::Decoder;
pub use crate::encoder::Encoder;
pub use crate::color::ColorType;
Loading