Skip to content

Commit 51a247c

Browse files
committed
Wbmp encoding / decoding
1 parent 3a3f425 commit 51a247c

File tree

6 files changed

+164
-2
lines changed

6 files changed

+164
-2
lines changed

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ publish = false
88
include = ["src", "tests/reference.rs"]
99

1010
[features]
11-
default = ["pcx"]
11+
default = ["pcx", "wbmp", "otb"]
1212
pcx = ["dep:pcx"]
13+
wbmp = ["dep:wbmp"]
14+
otb = []
1315

1416
[dependencies]
1517
image = { version = "0.25.5", default-features = false }
1618
pcx = { version = "0.2.4", optional = true }
19+
wbmp = { version = "0.1.2", optional = true }
1720

1821
[dev-dependencies]
1922
image = { version = "0.25.5", default-features = false, features = ["png"] }
2023
walkdir = "2.5.0"
2124

2225
[patch.crates-io]
23-
image = { git = "https://github.com/fintelia/image", branch = "decoding-hooks" }
26+
#image = { git = "https://github.com/fintelia/image", branch = "decoding-hooks" }
27+
image = { git = "https://github.com/reshane/image", branch = "decoding-hooks" }

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Decoding support for additional image formats beyond those provided by the [`ima
66
| Extension | File Format Description |
77
| --------- | -------------------- |
88
| PCX | [Wikipedia](https://en.wikipedia.org/wiki/PCX#PCX_file_format) |
9+
| WBMP | [Wikipedia](https://en.wikipedia.org/wiki/Wireless_Application_Protocol_Bitmap_Format) |
910

1011
## New Formats
1112

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,17 @@
1818
#[cfg(feature = "pcx")]
1919
pub mod pcx;
2020

21+
#[cfg(feature = "wbmp")]
22+
pub mod wbmp;
23+
2124
/// Register all enabled extra formats with the image crate.
2225
pub fn register() {
2326
image::hooks::register_decoding_hook(
2427
image::ImageFormat::Pcx,
2528
Box::new(|r| Ok(Box::new(pcx::PCXDecoder::new(r)?))),
2629
);
30+
image::hooks::register_decoding_hook(
31+
image::ImageFormat::Wbmp,
32+
Box::new(|r| Ok(Box::new(wbmp::WbmpDecoder::new(r)?))),
33+
);
2734
}

src/wbmp.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//! WBMP (Wireless BitMaP) Format is an image format used by the WAP protocol.
2+
//!
3+
//! # Related Links
4+
//! * <https://en.wikipedia.org/wiki/Wireless_Application_Protocol_Bitmap_Format> - The WBMP format on Wikipedia
5+
//! * <https://www.wapforum.org/what/technical/SPEC-WAESpec-19990524.pdf> - The WAP Specification
6+
7+
use std::io::{BufRead, Seek, Write};
8+
9+
use image::error::{
10+
DecodingError, EncodingError, ImageFormatHint, UnsupportedError, UnsupportedErrorKind,
11+
};
12+
use image::{ColorType, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageResult};
13+
14+
use wbmp::error::WbmpError;
15+
16+
/// Encoder for Wbmp images.
17+
pub struct WbmpEncoder<'a, W> {
18+
writer: Option<W>,
19+
inner: Option<wbmp::Encoder<'a, W>>,
20+
threshold: u8,
21+
}
22+
23+
impl<'a, W: Write> WbmpEncoder<'a, W> {
24+
pub fn new(writer: W) -> Result<WbmpEncoder<'a, W>, ImageError> {
25+
let threshold = 127_u8;
26+
27+
Ok(WbmpEncoder {
28+
writer: Some(writer),
29+
inner: None,
30+
threshold,
31+
})
32+
}
33+
34+
pub fn with_threshold(mut self, threshold: u8) -> WbmpEncoder<'a, W> {
35+
self.threshold = threshold;
36+
self
37+
}
38+
}
39+
40+
impl<'a, W: Write> ImageEncoder for WbmpEncoder<'a, W> {
41+
fn write_image(
42+
mut self,
43+
buf: &[u8],
44+
width: u32,
45+
height: u32,
46+
color_type: ExtendedColorType,
47+
) -> std::result::Result<(), ImageError> {
48+
let color = match color_type {
49+
ExtendedColorType::L8 => wbmp::ColorType::Luma8,
50+
ExtendedColorType::Rgba8 => wbmp::ColorType::Rgba8,
51+
_ => {
52+
return Err(ImageError::Encoding(EncodingError::from_format_hint(
53+
ImageFormatHint::Name("Unsupported ColorType".to_string()),
54+
)));
55+
}
56+
};
57+
58+
if let Some(mut inner) = self.inner {
59+
inner.encode(buf, width, height, color)
60+
} else {
61+
let mut writer = self.writer.take().unwrap();
62+
let mut encoder = wbmp::Encoder::new(&mut writer);
63+
encoder.encode(buf, width, height, color)
64+
}
65+
.map_err(|err| match err {
66+
WbmpError::IoError(io) => ImageError::IoError(io),
67+
_ => todo!(),
68+
})?;
69+
Ok(())
70+
}
71+
}
72+
73+
/// Decoder for Wbmp images.
74+
pub struct WbmpDecoder<R>
75+
where
76+
R: BufRead + Seek,
77+
{
78+
dimensions: (u32, u32),
79+
inner: wbmp::Decoder<R>,
80+
}
81+
82+
impl<R> WbmpDecoder<R>
83+
where
84+
R: BufRead + Seek,
85+
{
86+
/// Create a new `WbmpDecoder`.
87+
pub fn new(r: R) -> Result<WbmpDecoder<R>, ImageError> {
88+
let inner = wbmp::Decoder::new(r).map_err(convert_wbmp_decode_error)?;
89+
let dimensions = inner.dimensions();
90+
91+
Ok(WbmpDecoder { dimensions, inner })
92+
}
93+
}
94+
95+
fn convert_wbmp_decode_error(err: wbmp::error::WbmpError) -> ImageError {
96+
use wbmp::error::WbmpError;
97+
match err {
98+
WbmpError::IoError(inner) => ImageError::IoError(inner),
99+
WbmpError::UnsupportedType(inner) => {
100+
ImageError::Unsupported(UnsupportedError::from_format_and_kind(
101+
ImageFormatHint::Name("WBMP".to_string()),
102+
UnsupportedErrorKind::GenericFeature(format!(
103+
"type {} is not supported for wbmp images",
104+
inner
105+
)),
106+
))
107+
}
108+
WbmpError::UnsupportedHeaders => {
109+
ImageError::Unsupported(UnsupportedError::from_format_and_kind(
110+
ImageFormatHint::Name("WBMP".to_string()),
111+
UnsupportedErrorKind::GenericFeature(
112+
"Extension headers are not supported for wbmp images".to_string(),
113+
),
114+
))
115+
}
116+
WbmpError::InvalidImageData => ImageError::Decoding(DecodingError::from_format_hint(
117+
ImageFormatHint::Name("WBMP".to_string()),
118+
)),
119+
WbmpError::UsageError(inner) => ImageError::Decoding(DecodingError::new(
120+
ImageFormatHint::Name("WBMP".to_string()),
121+
Box::new(WbmpError::UsageError(inner)),
122+
)),
123+
}
124+
}
125+
126+
impl<R: BufRead + Seek> ImageDecoder for WbmpDecoder<R> {
127+
fn dimensions(&self) -> (u32, u32) {
128+
self.dimensions
129+
}
130+
131+
fn color_type(&self) -> ColorType {
132+
ColorType::L8
133+
}
134+
135+
fn original_color_type(&self) -> ExtendedColorType {
136+
ExtendedColorType::L1
137+
}
138+
139+
fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
140+
self.inner
141+
.read_image_data(buf)
142+
.map_err(convert_wbmp_decode_error)?;
143+
Ok(())
144+
}
145+
146+
fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
147+
(*self).read_image(buf)?;
148+
Ok(())
149+
}
150+
}

tests/images/wbmp/field.png

41 KB
Loading

tests/images/wbmp/field.wbmp

33.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)