use std::cmp;
use std::io;
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::iter::{repeat, Iterator, Rev};
use std::slice::ChunksMut;
use byteorder::{LittleEndian, ReadBytesExt};
use color::ColorType;
use image::{self, ImageDecoder, ImageDecoderExt, ImageError, ImageResult, Progress};
const BITMAPCOREHEADER_SIZE: u32 = 12;
const BITMAPINFOHEADER_SIZE: u32 = 40;
const BITMAPV2HEADER_SIZE: u32 = 52;
const BITMAPV3HEADER_SIZE: u32 = 56;
const BITMAPV4HEADER_SIZE: u32 = 108;
const BITMAPV5HEADER_SIZE: u32 = 124;
static LOOKUP_TABLE_3_BIT_TO_8_BIT: [u8; 8] = [0, 36, 73, 109, 146, 182, 219, 255];
static LOOKUP_TABLE_4_BIT_TO_8_BIT: [u8; 16] = [
0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255,
];
static LOOKUP_TABLE_5_BIT_TO_8_BIT: [u8; 32] = [
0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173,
181, 189, 197, 206, 214, 222, 230, 239, 247, 255,
];
static LOOKUP_TABLE_6_BIT_TO_8_BIT: [u8; 64] = [
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93,
97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170,
174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247,
251, 255,
];
static R5_G5_B5_COLOR_MASK: Bitfields = Bitfields {
r: Bitfield { len: 5, shift: 10 },
g: Bitfield { len: 5, shift: 5 },
b: Bitfield { len: 5, shift: 0 },
a: Bitfield { len: 0, shift: 0 },
};
const R8_G8_B8_COLOR_MASK: Bitfields = Bitfields {
r: Bitfield { len: 8, shift: 24 },
g: Bitfield { len: 8, shift: 16 },
b: Bitfield { len: 8, shift: 8 },
a: Bitfield { len: 0, shift: 0 },
};
const RLE_ESCAPE: u8 = 0;
const RLE_ESCAPE_EOL: u8 = 0;
const RLE_ESCAPE_EOF: u8 = 1;
const RLE_ESCAPE_DELTA: u8 = 2;
const MAX_WIDTH_HEIGHT: i32 = 0xFFFF;
#[derive(PartialEq, Copy, Clone)]
enum ImageType {
Palette,
RGB16,
RGB24,
RGB32,
RGBA32,
RLE8,
RLE4,
Bitfields16,
Bitfields32,
}
#[derive(PartialEq)]
enum BMPHeaderType {
Core,
Info,
V2,
V3,
V4,
V5,
}
#[derive(PartialEq)]
enum FormatFullBytes {
RGB24,
RGB32,
RGBA32,
Format888,
}
enum Chunker<'a> {
FromTop(ChunksMut<'a, u8>),
FromBottom(Rev<ChunksMut<'a, u8>>),
}
pub struct RowIterator<'a> {
chunks: Chunker<'a>,
}
impl<'a> Iterator for RowIterator<'a> {
type Item = &'a mut [u8];
#[inline(always)]
fn next(&mut self) -> Option<&'a mut [u8]> {
match self.chunks {
Chunker::FromTop(ref mut chunks) => chunks.next(),
Chunker::FromBottom(ref mut chunks) => chunks.next(),
}
}
}
fn check_for_overflow(width: i32, length: i32, channels: usize) -> ImageResult<()> {
num_bytes(width, length, channels)
.map(|_| ())
.ok_or_else(|| {
ImageError::FormatError(
"Image would require a buffer that is too large to be represented!".to_owned(),
)
})
}
fn num_bytes(width: i32, length: i32, channels: usize) -> Option<usize> {
if width <= 0 || length <= 0 {
None
} else {
match channels.checked_mul(width as usize) {
Some(n) => n.checked_mul(length as usize),
None => None,
}
}
}
const MAX_INITIAL_PIXELS: usize = 8192 * 4096;
fn blank_bytes<'a, T: Iterator<Item = &'a mut [u8]>>(iterator: T) {
for chunk in iterator {
for b in chunk {
*b = 0;
}
}
}
#[inline(never)]
#[cold]
fn extend_buffer(buffer: &mut Vec<u8>, full_size: usize, blank: bool) -> &mut [u8] {
let old_size = buffer.len();
let extend = full_size - buffer.len();
buffer.extend(repeat(0xFF).take(extend));
assert_eq!(buffer.len(), full_size);
let ret = if extend >= old_size {
let (new, old) = buffer.split_at_mut(extend);
old.copy_from_slice(&new[..old_size]);
new
} else {
let overlap = old_size - extend;
let (lower, upper) = buffer.split_at_mut(old_size);
upper.copy_from_slice(&lower[overlap..]);
let (new, old) = lower.split_at_mut(extend);
old[..overlap].copy_from_slice(&new[..overlap]);
new
};
if blank {
for b in ret.iter_mut() {
*b = 0;
}
};
ret
}
fn with_rows<F>(
buffer: &mut Vec<u8>,
width: i32,
height: i32,
channels: usize,
top_down: bool,
mut func: F,
) -> io::Result<()>
where
F: FnMut(&mut [u8]) -> io::Result<()>,
{
let row_width = channels.checked_mul(width as usize).unwrap();
let full_image_size = row_width.checked_mul(height as usize).unwrap();
if !top_down {
for row in buffer.chunks_mut(row_width).rev() {
try!(func(row));
}
if buffer.len() < full_image_size {
let new_space = extend_buffer(buffer, full_image_size, false);
for row in new_space.chunks_mut(row_width).rev() {
try!(func(row));
}
}
} else {
for row in buffer.chunks_mut(row_width) {
try!(func(row));
}
if buffer.len() < full_image_size {
let extend = full_image_size - buffer.len();
buffer.extend(repeat(0xFF).take(extend));
let len = buffer.len();
for row in buffer[len - row_width..].chunks_mut(row_width) {
try!(func(row));
}
};
}
Ok(())
}
fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
pixel_iter: &mut ChunksMut<u8>,
palette: &[(u8, u8, u8)],
indices: T,
n_pixels: usize,
) -> bool {
for idx in indices.take(n_pixels) {
if let Some(pixel) = pixel_iter.next() {
let (r, g, b) = palette[*idx as usize];
pixel[0] = r;
pixel[1] = g;
pixel[2] = b;
} else {
return false;
}
}
true
}
fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
pixel_iter: &mut ChunksMut<u8>,
palette: &[(u8, u8, u8)],
indices: T,
mut n_pixels: usize,
) -> bool {
for idx in indices {
macro_rules! set_pixel {
($i:expr) => {
if n_pixels == 0 {
break;
}
if let Some(pixel) = pixel_iter.next() {
let (r, g, b) = palette[$i as usize];
pixel[0] = r;
pixel[1] = g;
pixel[2] = b;
} else {
return false;
}
n_pixels -= 1;
};
}
set_pixel!(idx >> 4);
set_pixel!(idx & 0xf);
}
true
}
fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
pixel_iter: &mut ChunksMut<u8>,
palette: &[(u8, u8, u8)],
indices: T,
) {
for idx in indices {
let mut bit = 0x80;
loop {
if let Some(pixel) = pixel_iter.next() {
let (r, g, b) = palette[((idx & bit) != 0) as usize];
pixel[0] = r;
pixel[1] = g;
pixel[2] = b;
} else {
return;
}
bit >>= 1;
if bit == 0 {
break;
}
}
}
}
#[derive(PartialEq, Eq)]
struct Bitfield {
shift: u32,
len: u32,
}
impl Bitfield {
fn from_mask(mask: u32, max_len: u32) -> ImageResult<Bitfield> {
if mask == 0 {
return Ok(Bitfield { shift: 0, len: 0 });
}
let mut shift = mask.trailing_zeros();
let mut len = (!(mask >> shift)).trailing_zeros();
if len != mask.count_ones() {
return Err(ImageError::FormatError(
"Non-contiguous bitfield mask".to_string(),
));
}
if len + shift > max_len {
return Err(ImageError::FormatError("Invalid bitfield mask".to_string()));
}
if len > 8 {
shift += len - 8;
len = 8;
}
Ok(Bitfield { shift, len })
}
fn read(&self, data: u32) -> u8 {
let data = data >> self.shift;
match self.len {
1 => ((data & 0b1) * 0xff) as u8,
2 => ((data & 0b11) * 0x55) as u8,
3 => LOOKUP_TABLE_3_BIT_TO_8_BIT[(data & 0b00_0111) as usize],
4 => LOOKUP_TABLE_4_BIT_TO_8_BIT[(data & 0b00_1111) as usize],
5 => LOOKUP_TABLE_5_BIT_TO_8_BIT[(data & 0b01_1111) as usize],
6 => LOOKUP_TABLE_6_BIT_TO_8_BIT[(data & 0b11_1111) as usize],
7 => ((data & 0x7f) << 1 | (data & 0x7f) >> 6) as u8,
8 => (data & 0xff) as u8,
_ => panic!(),
}
}
}
#[derive(PartialEq, Eq)]
struct Bitfields {
r: Bitfield,
g: Bitfield,
b: Bitfield,
a: Bitfield,
}
impl Bitfields {
fn from_mask(
r_mask: u32,
g_mask: u32,
b_mask: u32,
a_mask: u32,
max_len: u32,
) -> ImageResult<Bitfields> {
let bitfields = Bitfields {
r: try!(Bitfield::from_mask(r_mask, max_len)),
g: try!(Bitfield::from_mask(g_mask, max_len)),
b: try!(Bitfield::from_mask(b_mask, max_len)),
a: try!(Bitfield::from_mask(a_mask, max_len)),
};
if bitfields.r.len == 0 || bitfields.g.len == 0 || bitfields.b.len == 0 {
return Err(ImageError::FormatError("Missing bitfield mask".to_string()));
}
Ok(bitfields)
}
}
pub struct BMPDecoder<R> {
r: R,
bmp_header_type: BMPHeaderType,
width: i32,
height: i32,
data_offset: u64,
top_down: bool,
no_file_header: bool,
add_alpha_channel: bool,
has_loaded_metadata: bool,
image_type: ImageType,
bit_count: u16,
colors_used: u32,
palette: Option<Vec<(u8, u8, u8)>>,
bitfields: Option<Bitfields>,
}
enum RLEInsn {
EndOfFile,
EndOfRow,
Delta(u8, u8),
Absolute(u8, Vec<u8>),
PixelRun(u8, u8),
}
struct RLEInsnIterator<'a, R: 'a + Read> {
r: &'a mut R,
image_type: ImageType,
}
impl<'a, R: Read> Iterator for RLEInsnIterator<'a, R> {
type Item = RLEInsn;
fn next(&mut self) -> Option<RLEInsn> {
let control_byte = match self.r.read_u8() {
Ok(b) => b,
Err(_) => return None,
};
match control_byte {
RLE_ESCAPE => {
let op = match self.r.read_u8() {
Ok(b) => b,
Err(_) => return None,
};
match op {
RLE_ESCAPE_EOL => Some(RLEInsn::EndOfRow),
RLE_ESCAPE_EOF => Some(RLEInsn::EndOfFile),
RLE_ESCAPE_DELTA => {
let xdelta = match self.r.read_u8() {
Ok(n) => n,
Err(_) => return None,
};
let ydelta = match self.r.read_u8() {
Ok(n) => n,
Err(_) => return None,
};
Some(RLEInsn::Delta(xdelta, ydelta))
}
_ => {
let mut length = op as usize;
if self.image_type == ImageType::RLE4 {
length = (length + 1) / 2;
}
length += length & 1;
let mut buffer = vec![0; length];
match self.r.read_exact(&mut buffer) {
Ok(()) => Some(RLEInsn::Absolute(op, buffer)),
Err(_) => None,
}
}
}
}
_ => match self.r.read_u8() {
Ok(palette_index) => Some(RLEInsn::PixelRun(control_byte, palette_index)),
Err(_) => None,
},
}
}
}
impl<R: Read + Seek> BMPDecoder<R> {
pub fn new(r: R) -> ImageResult<BMPDecoder<R>> {
let mut decoder = BMPDecoder {
r,
bmp_header_type: BMPHeaderType::Info,
width: 0,
height: 0,
data_offset: 0,
top_down: false,
no_file_header: false,
add_alpha_channel: false,
has_loaded_metadata: false,
image_type: ImageType::Palette,
bit_count: 0,
colors_used: 0,
palette: None,
bitfields: None,
};
decoder.read_metadata()?;
Ok(decoder)
}
#[cfg(feature = "ico")]
pub(crate) fn new_with_ico_format(r: R) -> ImageResult<BMPDecoder<R>> {
let mut decoder = BMPDecoder {
r,
bmp_header_type: BMPHeaderType::Info,
width: 0,
height: 0,
data_offset: 0,
top_down: false,
no_file_header: false,
add_alpha_channel: false,
has_loaded_metadata: false,
image_type: ImageType::Palette,
bit_count: 0,
colors_used: 0,
palette: None,
bitfields: None,
};
decoder.read_metadata_in_ico_format()?;
Ok(decoder)
}
#[cfg(feature = "ico")]
pub(crate) fn reader(&mut self) -> &mut R {
&mut self.r
}
fn read_file_header(&mut self) -> ImageResult<()> {
if self.no_file_header {
return Ok(());
}
let mut signature = [0; 2];
try!(self.r.read_exact(&mut signature));
if signature != b"BM"[..] {
return Err(ImageError::FormatError(
"BMP signature not found".to_string(),
));
}
try!(self.r.read_u32::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
self.data_offset = u64::from(self.r.read_u32::<LittleEndian>()?);
Ok(())
}
fn read_bitmap_core_header(&mut self) -> ImageResult<()> {
self.width = i32::from(self.r.read_u16::<LittleEndian>()?);
self.height = i32::from(self.r.read_u16::<LittleEndian>()?);
try!(check_for_overflow(
self.width,
self.height,
self.num_channels()
));
if try!(self.r.read_u16::<LittleEndian>()) != 1 {
return Err(ImageError::FormatError(
"Invalid number of planes.".to_string(),
));
}
self.bit_count = try!(self.r.read_u16::<LittleEndian>());
self.image_type = match self.bit_count {
1 | 4 | 8 => ImageType::Palette,
24 => ImageType::RGB24,
_ => return Err(ImageError::FormatError("Invalid bit count".to_string())),
};
Ok(())
}
fn read_bitmap_info_header(&mut self) -> ImageResult<()> {
self.width = try!(self.r.read_i32::<LittleEndian>());
self.height = try!(self.r.read_i32::<LittleEndian>());
if self.width < 0 {
return Err(ImageError::FormatError("Negative width".to_string()));
} else if self.width > MAX_WIDTH_HEIGHT || self.height > MAX_WIDTH_HEIGHT {
return Err(ImageError::FormatError("Image too large".to_string()));
}
if self.height == i32::min_value() {
return Err(ImageError::FormatError("Invalid height".to_string()));
}
if self.height < 0 {
self.height *= -1;
self.top_down = true;
}
try!(check_for_overflow(
self.width,
self.height,
self.num_channels()
));
if try!(self.r.read_u16::<LittleEndian>()) != 1 {
return Err(ImageError::FormatError(
"Invalid number of planes.".to_string(),
));
}
self.bit_count = try!(self.r.read_u16::<LittleEndian>());
let image_type_u32 = try!(self.r.read_u32::<LittleEndian>());
if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 {
return Err(ImageError::FormatError(
"Invalid image type for top-down image.".to_string(),
));
}
self.image_type = match image_type_u32 {
0 => match self.bit_count {
1 | 4 | 8 => ImageType::Palette,
16 => ImageType::RGB16,
24 => ImageType::RGB24,
32 => if self.add_alpha_channel {
ImageType::RGBA32
} else {
ImageType::RGB32
},
_ => return Err(ImageError::FormatError("Invalid RGB bit count".to_string())),
},
1 => match self.bit_count {
8 => ImageType::RLE8,
_ => {
return Err(ImageError::FormatError(
"Invalid RLE8 bit count".to_string(),
))
}
},
2 => match self.bit_count {
4 => ImageType::RLE4,
_ => {
return Err(ImageError::FormatError(
"Invalid RLE4 bit count".to_string(),
))
}
},
3 => match self.bit_count {
16 => ImageType::Bitfields16,
32 => ImageType::Bitfields32,
_ => {
return Err(ImageError::FormatError(
"Invalid bitfields bit count".to_string(),
))
}
},
_ => {
return Err(ImageError::UnsupportedError(
"Unsupported image type".to_string(),
))
}
};
try!(self.r.read_u32::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
self.colors_used = try!(self.r.read_u32::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
Ok(())
}
fn read_bitmasks(&mut self) -> ImageResult<()> {
let r_mask = try!(self.r.read_u32::<LittleEndian>());
let g_mask = try!(self.r.read_u32::<LittleEndian>());
let b_mask = try!(self.r.read_u32::<LittleEndian>());
let a_mask = match self.bmp_header_type {
BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => {
try!(self.r.read_u32::<LittleEndian>())
}
_ => 0,
};
self.bitfields = match self.image_type {
ImageType::Bitfields16 => Some(try!(Bitfields::from_mask(
r_mask, g_mask, b_mask, a_mask, 16
))),
ImageType::Bitfields32 => Some(try!(Bitfields::from_mask(
r_mask, g_mask, b_mask, a_mask, 32
))),
_ => None,
};
if self.bitfields.is_some() && a_mask != 0 {
self.add_alpha_channel = true;
}
Ok(())
}
fn read_metadata(&mut self) -> ImageResult<()> {
if !self.has_loaded_metadata {
try!(self.read_file_header());
let bmp_header_offset = try!(self.r.seek(SeekFrom::Current(0)));
let bmp_header_size = try!(self.r.read_u32::<LittleEndian>());
let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size);
self.bmp_header_type = match bmp_header_size {
BITMAPCOREHEADER_SIZE => BMPHeaderType::Core,
BITMAPINFOHEADER_SIZE => BMPHeaderType::Info,
BITMAPV2HEADER_SIZE => BMPHeaderType::V2,
BITMAPV3HEADER_SIZE => BMPHeaderType::V3,
BITMAPV4HEADER_SIZE => BMPHeaderType::V4,
BITMAPV5HEADER_SIZE => BMPHeaderType::V5,
_ => {
return Err(ImageError::UnsupportedError(
"Unsupported Bitmap Header".to_string(),
))
}
};
match self.bmp_header_type {
BMPHeaderType::Core => {
try!(self.read_bitmap_core_header());
}
BMPHeaderType::Info
| BMPHeaderType::V2
| BMPHeaderType::V3
| BMPHeaderType::V4
| BMPHeaderType::V5 => {
try!(self.read_bitmap_info_header());
}
};
match self.image_type {
ImageType::Bitfields16 | ImageType::Bitfields32 => try!(self.read_bitmasks()),
_ => {}
};
try!(self.r.seek(SeekFrom::Start(bmp_header_end)));
match self.image_type {
ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => try!(self.read_palette()),
_ => {}
};
if self.no_file_header {
self.data_offset = try!(self.r.seek(SeekFrom::Current(0)));
}
self.has_loaded_metadata = true;
}
Ok(())
}
#[cfg(feature = "ico")]
#[doc(hidden)]
pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> {
self.no_file_header = true;
self.add_alpha_channel = true;
try!(self.read_metadata());
self.height /= 2;
Ok(())
}
fn get_palette_size(&mut self) -> ImageResult<usize> {
match self.colors_used {
0 => Ok(1 << self.bit_count),
_ => {
if self.colors_used > 1 << self.bit_count {
return Err(ImageError::FormatError(format!(
"Palette size {} exceeds maximum size for BMP with bit count of {}",
self.colors_used, self.bit_count
)));
}
Ok(self.colors_used as usize)
}
}
}
fn bytes_per_color(&self) -> usize {
match self.bmp_header_type {
BMPHeaderType::Core => 3,
_ => 4,
}
}
fn read_palette(&mut self) -> ImageResult<()> {
const MAX_PALETTE_SIZE: usize = 256;
let bytes_per_color = self.bytes_per_color();
let palette_size = try!(self.get_palette_size());
let max_length = MAX_PALETTE_SIZE * bytes_per_color;
let length = palette_size * bytes_per_color;
let mut buf = Vec::with_capacity(max_length);
buf.resize(cmp::min(length, max_length), 0);
try!(self.r.by_ref().read_exact(&mut buf));
if length < max_length {
buf.resize(max_length, 0);
} else if length > max_length {
try!(self.r.seek(SeekFrom::Current((length - max_length) as i64)));
};
let p: Vec<(u8, u8, u8)> = (0..MAX_PALETTE_SIZE)
.map(|i| {
let b = buf[bytes_per_color * i];
let g = buf[bytes_per_color * i + 1];
let r = buf[bytes_per_color * i + 2];
(r, g, b)
})
.collect();
self.palette = Some(p);
Ok(())
}
fn num_channels(&self) -> usize {
if self.add_alpha_channel {
4
} else {
3
}
}
fn create_pixel_data(&self) -> Vec<u8> {
let row_width = self.num_channels() * self.width as usize;
let max_pixels = self.num_channels() * MAX_INITIAL_PIXELS;
let max_starting_size = max_pixels + row_width - (max_pixels % row_width);
vec![0xFF; cmp::min(row_width * self.height as usize, max_starting_size)]
}
fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> {
let stride = self.width as usize * self.num_channels();
if self.top_down {
RowIterator {
chunks: Chunker::FromTop(pixel_data.chunks_mut(stride)),
}
} else {
RowIterator {
chunks: Chunker::FromBottom(pixel_data.chunks_mut(stride).rev()),
}
}
}
fn read_palettized_pixel_data(&mut self) -> ImageResult<Vec<u8>> {
let mut pixel_data = self.create_pixel_data();
let num_channels = self.num_channels();
let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize;
let mut indices = vec![0; row_byte_length];
let palette = self.palette.as_ref().unwrap();
let bit_count = self.bit_count;
let reader = &mut self.r;
let width = self.width as usize;
try!(reader.seek(SeekFrom::Start(self.data_offset)));
try!(with_rows(
&mut pixel_data,
self.width,
self.height,
num_channels,
self.top_down,
|row| {
try!(reader.read_exact(&mut indices));
let mut pixel_iter = row.chunks_mut(num_channels);
match bit_count {
1 => {
set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter());
}
4 => {
set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width);
}
8 => {
set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width);
}
_ => panic!(),
};
Ok(())
}
));
Ok(pixel_data)
}
fn read_16_bit_pixel_data(&mut self, bitfields: Option<&Bitfields>) -> ImageResult<Vec<u8>> {
let mut pixel_data = self.create_pixel_data();
let num_channels = self.num_channels();
let row_padding_len = self.width as usize % 2 * 2;
let row_padding = &mut [0; 2][..row_padding_len];
let bitfields = match bitfields {
Some(b) => b,
None => self.bitfields.as_ref().unwrap(),
};
let reader = &mut self.r;
try!(reader.seek(SeekFrom::Start(self.data_offset)));
try!(with_rows(
&mut pixel_data,
self.width,
self.height,
num_channels,
self.top_down,
|row| {
for pixel in row.chunks_mut(num_channels) {
let data = u32::from(reader.read_u16::<LittleEndian>()?);
pixel[0] = bitfields.r.read(data);
pixel[1] = bitfields.g.read(data);
pixel[2] = bitfields.b.read(data);
if num_channels == 4 {
pixel[3] = bitfields.a.read(data);
}
}
reader.read_exact(row_padding)
}
));
Ok(pixel_data)
}
fn read_32_bit_pixel_data(&mut self) -> ImageResult<Vec<u8>> {
let mut pixel_data = self.create_pixel_data();
let num_channels = self.num_channels();
let bitfields = self.bitfields.as_ref().unwrap();
let reader = &mut self.r;
try!(reader.seek(SeekFrom::Start(self.data_offset)));
try!(with_rows(
&mut pixel_data,
self.width,
self.height,
num_channels,
self.top_down,
|row| {
for pixel in row.chunks_mut(num_channels) {
let data = try!(reader.read_u32::<LittleEndian>());
pixel[0] = bitfields.r.read(data);
pixel[1] = bitfields.g.read(data);
pixel[2] = bitfields.b.read(data);
if num_channels == 4 {
pixel[3] = bitfields.a.read(data);
}
}
Ok(())
}
));
Ok(pixel_data)
}
fn read_full_byte_pixel_data(&mut self, format: &FormatFullBytes) -> ImageResult<Vec<u8>> {
let mut pixel_data = self.create_pixel_data();
let num_channels = self.num_channels();
let row_padding_len = match *format {
FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4,
_ => 0,
};
let row_padding = &mut [0; 4][..row_padding_len];
try!(self.r.seek(SeekFrom::Start(self.data_offset)));
let reader = &mut self.r;
try!(with_rows(
&mut pixel_data,
self.width,
self.height,
num_channels,
self.top_down,
|row| {
for pixel in row.chunks_mut(num_channels) {
if *format == FormatFullBytes::Format888 {
try!(reader.read_u8());
}
try!(reader.read_exact(&mut pixel[0..3]));
pixel[0..3].reverse();
if *format == FormatFullBytes::RGB32 {
try!(reader.read_u8());
}
if *format == FormatFullBytes::RGBA32 {
try!(reader.read_exact(&mut pixel[3..4]));
}
}
reader.read_exact(row_padding)
}
));
Ok(pixel_data)
}
fn read_rle_data(&mut self, image_type: ImageType) -> ImageResult<Vec<u8>> {
try!(self.r.seek(SeekFrom::Start(self.data_offset)));
let full_image_size = try!(
num_bytes(self.width, self.height, self.num_channels()).ok_or_else(|| {
ImageError::FormatError("Image buffer would be too large!".to_owned())
})
);
let mut pixel_data = self.create_pixel_data();
let (skip_pixels, skip_rows, eof_hit) =
try!(self.read_rle_data_step(&mut pixel_data, image_type, 0, 0));
if pixel_data.len() < full_image_size && !eof_hit {
let new = extend_buffer(&mut pixel_data, full_image_size, true);
try!(self.read_rle_data_step(new, image_type, skip_pixels, skip_rows));
}
Ok(pixel_data)
}
fn read_rle_data_step(
&mut self,
mut pixel_data: &mut [u8],
image_type: ImageType,
skip_pixels: u8,
skip_rows: u8,
) -> ImageResult<(u8, u8, bool)> {
let num_channels = self.num_channels();
let mut delta_rows_left = 0;
let mut delta_pixels_left = skip_pixels;
let mut eof_hit = false;
{
let mut row_iter = self.rows(&mut pixel_data);
blank_bytes((&mut row_iter).take(skip_rows.into()));
let mut insns_iter = RLEInsnIterator {
r: &mut self.r,
image_type,
};
let p = self.palette.as_ref().unwrap();
'row_loop: while let Some(row) = row_iter.next() {
let mut pixel_iter = row.chunks_mut(num_channels);
blank_bytes((&mut pixel_iter).take(delta_pixels_left.into()));
delta_pixels_left = 0;
'rle_loop: loop {
if let Some(insn) = insns_iter.next() {
match insn {
RLEInsn::EndOfFile => {
blank_bytes(pixel_iter);
blank_bytes(row_iter);
eof_hit = true;
break 'row_loop;
}
RLEInsn::EndOfRow => {
blank_bytes(pixel_iter);
break 'rle_loop;
}
RLEInsn::Delta(x_delta, y_delta) => {
if y_delta > 0 {
for n in 1..y_delta {
if let Some(row) = row_iter.next() {
for b in row {
*b = 0;
}
} else {
delta_pixels_left = x_delta;
delta_rows_left = y_delta - n;
break 'row_loop;
}
}
}
for _ in 0..x_delta {
if let Some(pixel) = pixel_iter.next() {
for b in pixel {
*b = 0;
}
} else {
break;
}
}
}
RLEInsn::Absolute(length, indices) => {
match image_type {
ImageType::RLE8 => {
if !set_8bit_pixel_run(
&mut pixel_iter,
p,
indices.iter(),
length as usize,
) {
break 'row_loop;
}
}
ImageType::RLE4 => {
if !set_4bit_pixel_run(
&mut pixel_iter,
p,
indices.iter(),
length as usize,
) {
break 'row_loop;
}
}
_ => panic!(),
}
}
RLEInsn::PixelRun(n_pixels, palette_index) => {
match image_type {
ImageType::RLE8 => {
if !set_8bit_pixel_run(
&mut pixel_iter,
p,
repeat(&palette_index),
n_pixels as usize,
) {
break 'rle_loop;
}
}
ImageType::RLE4 => {
if !set_4bit_pixel_run(
&mut pixel_iter,
p,
repeat(&palette_index),
n_pixels as usize,
) {
break 'rle_loop;
}
}
_ => panic!(),
}
}
}
} else {
return Err(ImageError::FormatError("Not enough RLE data".to_string()));
}
}
}
}
Ok((delta_pixels_left, delta_rows_left, eof_hit))
}
pub(crate) fn read_image_data(&mut self) -> ImageResult<Vec<u8>> {
match self.image_type {
ImageType::Palette => self.read_palettized_pixel_data(),
ImageType::RGB16 => self.read_16_bit_pixel_data(Some(&R5_G5_B5_COLOR_MASK)),
ImageType::RGB24 => self.read_full_byte_pixel_data(&FormatFullBytes::RGB24),
ImageType::RGB32 => self.read_full_byte_pixel_data(&FormatFullBytes::RGB32),
ImageType::RGBA32 => self.read_full_byte_pixel_data(&FormatFullBytes::RGBA32),
ImageType::RLE8 => self.read_rle_data(ImageType::RLE8),
ImageType::RLE4 => self.read_rle_data(ImageType::RLE4),
ImageType::Bitfields16 => match self.bitfields {
Some(_) => self.read_16_bit_pixel_data(None),
None => Err(ImageError::FormatError(
"Missing 16-bit bitfield masks".to_string(),
)),
},
ImageType::Bitfields32 => match self.bitfields {
Some(R8_G8_B8_COLOR_MASK) => {
self.read_full_byte_pixel_data(&FormatFullBytes::Format888)
}
Some(_) => self.read_32_bit_pixel_data(),
None => Err(ImageError::FormatError(
"Missing 32-bit bitfield masks".to_string(),
)),
},
}
}
}
impl<R: Read + Seek> ImageDecoder for BMPDecoder<R> {
type Reader = Cursor<Vec<u8>>;
fn dimensions(&self) -> (u64, u64) {
(self.width as u64, self.height as u64)
}
fn colortype(&self) -> ColorType {
if self.add_alpha_channel {
ColorType::RGBA(8)
} else {
ColorType::RGB(8)
}
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
self.read_image_data()
}
}
impl<R: Read + Seek> ImageDecoderExt for BMPDecoder<R> {
fn read_rect_with_progress<F: Fn(Progress)>(
&mut self,
x: u64,
y: u64,
width: u64,
height: u64,
buf: &mut [u8],
progress_callback: F,
) -> ImageResult<()> {
let start = self.r.seek(SeekFrom::Current(0))?;
let data = self.read_image_data();
self.r.seek(SeekFrom::Start(start))?;
let data = data?;
image::load_rect(x, y, width, height, buf, progress_callback, self, |_, _| unreachable!(),
|_, buf| { buf.copy_from_slice(&data); Ok(buf.len()) })?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::Bitfield;
#[test]
fn test_bitfield_len() {
for len in 1..9 {
let bitfield = Bitfield { shift: 0, len };
for i in 0..(1 << len) {
let read = bitfield.read(i);
let calc = (i as f64 / ((1 << len) - 1) as f64 * 255f64).round() as u8;
if read != calc {
println!("len:{} i:{} read:{} calc:{}", len, i, read, calc);
}
assert_eq!(read, calc);
}
}
}
}