Skip to content

Commit 1dadb9b

Browse files
committed
Support 16-bit encoded TGA images.
The decoder does the same thing as the BMP decoder, and converts 16-bit images to 32-bit ones on load.
1 parent e176cd4 commit 1dadb9b

File tree

8 files changed

+250
-114
lines changed

8 files changed

+250
-114
lines changed

src/codecs/bmp/decoder.rs

Lines changed: 17 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,16 @@ use crate::error::{
1313
use crate::image::{self, ImageDecoder, ImageFormat};
1414
use crate::ImageDecoderRect;
1515

16+
use crate::utils::packed_color::Bitfield;
17+
use crate::utils::packed_color::{BitfieldError, Bitfields};
18+
1619
const BITMAPCOREHEADER_SIZE: u32 = 12;
1720
const BITMAPINFOHEADER_SIZE: u32 = 40;
1821
const BITMAPV2HEADER_SIZE: u32 = 52;
1922
const BITMAPV3HEADER_SIZE: u32 = 56;
2023
const BITMAPV4HEADER_SIZE: u32 = 108;
2124
const BITMAPV5HEADER_SIZE: u32 = 124;
2225

23-
static LOOKUP_TABLE_3_BIT_TO_8_BIT: [u8; 8] = [0, 36, 73, 109, 146, 182, 219, 255];
24-
static LOOKUP_TABLE_4_BIT_TO_8_BIT: [u8; 16] = [
25-
0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255,
26-
];
27-
static LOOKUP_TABLE_5_BIT_TO_8_BIT: [u8; 32] = [
28-
0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173,
29-
181, 189, 197, 206, 214, 222, 230, 239, 247, 255,
30-
];
31-
static LOOKUP_TABLE_6_BIT_TO_8_BIT: [u8; 64] = [
32-
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93,
33-
97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170,
34-
174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247,
35-
251, 255,
36-
];
37-
3826
static R5_G5_B5_COLOR_MASK: Bitfields = Bitfields {
3927
r: Bitfield { len: 5, shift: 10 },
4028
g: Bitfield { len: 5, shift: 5 },
@@ -120,14 +108,8 @@ enum DecoderError {
120108
// Failed to decompress RLE data.
121109
CorruptRleData,
122110

123-
/// The bitfield mask interleaves set and unset bits
124-
BitfieldMaskNonContiguous,
125-
/// Bitfield mask invalid (e.g. too long for specified type)
126-
BitfieldMaskInvalid,
127-
/// Bitfield (of the specified width – 16- or 32-bit) mask not present
128-
BitfieldMaskMissing(u32),
129111
/// Bitfield (of the specified width – 16- or 32-bit) masks not present
130-
BitfieldMasksMissing(u32),
112+
BitfieldError(BitfieldError),
131113

132114
/// BMP's "BM" signature wrong or missing
133115
BmpSignatureInvalid,
@@ -164,13 +146,8 @@ impl fmt::Display for DecoderError {
164146
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165147
match self {
166148
DecoderError::CorruptRleData => f.write_str("Corrupt RLE data"),
167-
DecoderError::BitfieldMaskNonContiguous => f.write_str("Non-contiguous bitfield mask"),
168-
DecoderError::BitfieldMaskInvalid => f.write_str("Invalid bitfield mask"),
169-
DecoderError::BitfieldMaskMissing(bb) => {
170-
f.write_fmt(format_args!("Missing {bb}-bit bitfield mask"))
171-
}
172-
DecoderError::BitfieldMasksMissing(bb) => {
173-
f.write_fmt(format_args!("Missing {bb}-bit bitfield masks"))
149+
DecoderError::BitfieldError(bb) => {
150+
f.write_fmt(format_args!("Bitfield error: {bb}"))
174151
}
175152
DecoderError::BmpSignatureInvalid => f.write_str("BMP signature not found"),
176153
DecoderError::MoreThanOnePlane => f.write_str("More than one plane"),
@@ -207,6 +184,15 @@ impl From<DecoderError> for ImageError {
207184
}
208185
}
209186

187+
impl From<BitfieldError> for ImageError {
188+
fn from(e: BitfieldError) -> ImageError {
189+
ImageError::Decoding(DecodingError::new(
190+
ImageFormat::Bmp.into(),
191+
DecoderError::BitfieldError(e),
192+
))
193+
}
194+
}
195+
210196
impl error::Error for DecoderError {}
211197

212198
/// Distinct image types whose saved channel width can be invalid
@@ -397,77 +383,6 @@ fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
397383
}
398384
}
399385

400-
#[derive(PartialEq, Eq)]
401-
struct Bitfield {
402-
shift: u32,
403-
len: u32,
404-
}
405-
406-
impl Bitfield {
407-
fn from_mask(mask: u32, max_len: u32) -> ImageResult<Bitfield> {
408-
if mask == 0 {
409-
return Ok(Bitfield { shift: 0, len: 0 });
410-
}
411-
let mut shift = mask.trailing_zeros();
412-
let mut len = (!(mask >> shift)).trailing_zeros();
413-
if len != mask.count_ones() {
414-
return Err(DecoderError::BitfieldMaskNonContiguous.into());
415-
}
416-
if len + shift > max_len {
417-
return Err(DecoderError::BitfieldMaskInvalid.into());
418-
}
419-
if len > 8 {
420-
shift += len - 8;
421-
len = 8;
422-
}
423-
Ok(Bitfield { shift, len })
424-
}
425-
426-
fn read(&self, data: u32) -> u8 {
427-
let data = data >> self.shift;
428-
match self.len {
429-
1 => ((data & 0b1) * 0xff) as u8,
430-
2 => ((data & 0b11) * 0x55) as u8,
431-
3 => LOOKUP_TABLE_3_BIT_TO_8_BIT[(data & 0b00_0111) as usize],
432-
4 => LOOKUP_TABLE_4_BIT_TO_8_BIT[(data & 0b00_1111) as usize],
433-
5 => LOOKUP_TABLE_5_BIT_TO_8_BIT[(data & 0b01_1111) as usize],
434-
6 => LOOKUP_TABLE_6_BIT_TO_8_BIT[(data & 0b11_1111) as usize],
435-
7 => ((data & 0x7f) << 1 | (data & 0x7f) >> 6) as u8,
436-
8 => (data & 0xff) as u8,
437-
_ => panic!(),
438-
}
439-
}
440-
}
441-
442-
#[derive(PartialEq, Eq)]
443-
struct Bitfields {
444-
r: Bitfield,
445-
g: Bitfield,
446-
b: Bitfield,
447-
a: Bitfield,
448-
}
449-
450-
impl Bitfields {
451-
fn from_mask(
452-
r_mask: u32,
453-
g_mask: u32,
454-
b_mask: u32,
455-
a_mask: u32,
456-
max_len: u32,
457-
) -> ImageResult<Bitfields> {
458-
let bitfields = Bitfields {
459-
r: Bitfield::from_mask(r_mask, max_len)?,
460-
g: Bitfield::from_mask(g_mask, max_len)?,
461-
b: Bitfield::from_mask(b_mask, max_len)?,
462-
a: Bitfield::from_mask(a_mask, max_len)?,
463-
};
464-
if bitfields.r.len == 0 || bitfields.g.len == 0 || bitfields.b.len == 0 {
465-
return Err(DecoderError::BitfieldMaskMissing(max_len).into());
466-
}
467-
Ok(bitfields)
468-
}
469-
}
470-
471386
/// A bmp decoder
472387
pub struct BmpDecoder<R> {
473388
reader: R,
@@ -1308,7 +1223,7 @@ impl<R: BufRead + Seek> BmpDecoder<R> {
13081223
ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4),
13091224
ImageType::Bitfields16 => match self.bitfields {
13101225
Some(_) => self.read_16_bit_pixel_data(buf, None),
1311-
None => Err(DecoderError::BitfieldMasksMissing(16).into()),
1226+
None => Err(BitfieldError::MasksMissing(16).into()),
13121227
},
13131228
ImageType::Bitfields32 => match self.bitfields {
13141229
Some(R8_G8_B8_COLOR_MASK) => {
@@ -1318,7 +1233,7 @@ impl<R: BufRead + Seek> BmpDecoder<R> {
13181233
self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32)
13191234
}
13201235
Some(_) => self.read_32_bit_pixel_data(buf),
1321-
None => Err(DecoderError::BitfieldMasksMissing(32).into()),
1236+
None => Err(BitfieldError::MasksMissing(32).into()),
13221237
},
13231238
}
13241239
}

src/codecs/tga/decoder.rs

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,29 @@ use super::header::{Header, ImageType, ALPHA_BIT_MASK, SCREEN_ORIGIN_BIT_MASK};
22
use crate::{
33
color::{ColorType, ExtendedColorType},
44
error::{
5-
ImageError, ImageResult, LimitError, LimitErrorKind, UnsupportedError, UnsupportedErrorKind,
5+
ImageError, ImageFormatHint, ImageResult, LimitError, LimitErrorKind, UnsupportedError,
6+
UnsupportedErrorKind,
67
},
78
image::{ImageDecoder, ImageFormat},
9+
utils::packed_color::{Bitfield, Bitfields},
10+
};
11+
use byteorder_lite::{LittleEndian, ReadBytesExt};
12+
use num_traits::ToPrimitive;
13+
use std::io::{self, Cursor, Read};
14+
15+
static R5_G5_B5_COLOR_MASK: Bitfields = Bitfields {
16+
r: Bitfield { len: 5, shift: 10 },
17+
g: Bitfield { len: 5, shift: 5 },
18+
b: Bitfield { len: 5, shift: 0 },
19+
a: Bitfield { len: 0, shift: 0 },
20+
};
21+
22+
static R5_G5_B5_A1_COLOR_MASK: Bitfields = Bitfields {
23+
r: Bitfield { len: 5, shift: 10 },
24+
g: Bitfield { len: 5, shift: 5 },
25+
b: Bitfield { len: 5, shift: 0 },
26+
a: Bitfield { len: 1, shift: 15 },
827
};
9-
use byteorder_lite::ReadBytesExt;
10-
use std::io::{self, Read};
1128

1229
struct ColorMap {
1330
/// sizes in bytes
@@ -57,6 +74,8 @@ pub struct TgaDecoder<R> {
5774

5875
header: Header,
5976
color_map: Option<ColorMap>,
77+
78+
packing: Option<&'static Bitfields>,
6079
}
6180

6281
impl<R: Read> TgaDecoder<R> {
@@ -76,6 +95,8 @@ impl<R: Read> TgaDecoder<R> {
7695

7796
header: Header::default(),
7897
color_map: None,
98+
99+
packing: None,
79100
};
80101
decoder.read_metadata()?;
81102
Ok(decoder)
@@ -103,12 +124,13 @@ impl<R: Read> TgaDecoder<R> {
103124

104125
/// Loads the color information for the decoder
105126
///
106-
/// To keep things simple, we won't handle bit depths that aren't divisible
107-
/// by 8 and are larger than 32.
127+
/// To keep things simple, we won't handle bit depths that are larger than 32.
108128
fn read_color_information(&mut self) -> ImageResult<()> {
109-
if self.header.pixel_depth % 8 != 0 || self.header.pixel_depth > 32 {
129+
if self.header.pixel_depth != 15
130+
&& (self.header.pixel_depth % 8 != 0 || self.header.pixel_depth > 32)
131+
{
110132
// Bit depth must be divisible by 8, and must be less than or equal
111-
// to 32.
133+
// to 32 OR be 15-bit
112134
return Err(ImageError::Unsupported(
113135
UnsupportedError::from_format_and_kind(
114136
ImageFormat::Tga.into(),
@@ -137,6 +159,7 @@ impl<R: Read> TgaDecoder<R> {
137159

138160
self.header.pixel_depth - num_alpha_bits
139161
};
162+
140163
let color = self.image_type.is_color();
141164

142165
match (num_alpha_bits, other_channel_bits, color) {
@@ -152,6 +175,16 @@ impl<R: Read> TgaDecoder<R> {
152175
self.color_type = ColorType::L8;
153176
self.original_color_type = Some(ExtendedColorType::A8);
154177
}
178+
(0, 15 | 16, true) => {
179+
self.color_type = ColorType::Rgb8;
180+
self.original_color_type = Some(ExtendedColorType::Rgb5);
181+
self.packing = Some(&R5_G5_B5_COLOR_MASK);
182+
}
183+
(1, 15, true) => {
184+
self.color_type = ColorType::Rgba8;
185+
self.original_color_type = Some(ExtendedColorType::Rgb5a1);
186+
self.packing = Some(&R5_G5_B5_A1_COLOR_MASK);
187+
}
155188
_ => {
156189
return Err(ImageError::Unsupported(
157190
UnsupportedError::from_format_and_kind(
@@ -350,16 +383,21 @@ impl<R: Read> ImageDecoder for TgaDecoder<R> {
350383
.unwrap_or_else(|| self.color_type().into())
351384
}
352385

386+
#[allow(clippy::identity_op)]
353387
fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
354388
assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
355389

356390
// In indexed images, we might need more bytes than pixels to read them. That's nonsensical
357391
// to encode but we'll not want to crash.
392+
//
393+
// also used for packed (<8 bit per channel) images
358394
let mut fallback_buf = vec![];
359395
// read the pixels from the data region
360396
let rawbuf = if self.image_type.is_encoded() {
361397
let pixel_data = self.read_all_encoded_data()?;
362-
if self.bytes_per_pixel <= usize::from(self.color_type.bytes_per_pixel()) {
398+
if self.bytes_per_pixel <= usize::from(self.color_type.bytes_per_pixel())
399+
&& self.packing.is_none()
400+
{
363401
buf[..pixel_data.len()].copy_from_slice(&pixel_data);
364402
&buf[..pixel_data.len()]
365403
} else {
@@ -368,7 +406,9 @@ impl<R: Read> ImageDecoder for TgaDecoder<R> {
368406
}
369407
} else {
370408
let num_raw_bytes = self.width * self.height * self.bytes_per_pixel;
371-
if self.bytes_per_pixel <= usize::from(self.color_type.bytes_per_pixel()) {
409+
if self.bytes_per_pixel <= usize::from(self.color_type.bytes_per_pixel())
410+
&& self.packing.is_none()
411+
{
372412
self.r.by_ref().read_exact(&mut buf[..num_raw_bytes])?;
373413
&buf[..num_raw_bytes]
374414
} else {
@@ -384,15 +424,70 @@ impl<R: Read> ImageDecoder for TgaDecoder<R> {
384424
if self.image_type.is_color_mapped() {
385425
let pixel_data = self.expand_color_map(rawbuf)?;
386426
// not enough data to fill the buffer, or would overflow the buffer
387-
if pixel_data.len() != buf.len() {
427+
if !self.packing.is_some() && pixel_data.len() != buf.len() {
388428
return Err(ImageError::Limits(LimitError::from_kind(
389429
LimitErrorKind::DimensionError,
390430
)));
391431
}
392-
buf.copy_from_slice(&pixel_data);
432+
433+
if self.packing.is_none() {
434+
buf.copy_from_slice(&pixel_data);
435+
} else {
436+
fallback_buf.resize(pixel_data.len(), 0);
437+
fallback_buf.copy_from_slice(&pixel_data);
438+
}
393439
}
394440

395-
self.reverse_encoding_in_output(buf);
441+
if let Some(bitfields) = &self.packing {
442+
let num_pixels = self.width * self.height;
443+
let bytes_per_unpacked_pixel = if bitfields.a.len > 0 { 4 } else { 3 };
444+
let mut stream = Cursor::new(fallback_buf);
445+
let bytes_per_packed_pixel = if self.header.map_type == 0 {
446+
self.bytes_per_pixel
447+
} else {
448+
(self.header.map_entry_size as usize + 7) / 8
449+
};
450+
451+
if num_pixels * bytes_per_unpacked_pixel != buf.len() {
452+
return Err(ImageError::Limits(LimitError::from_kind(
453+
LimitErrorKind::DimensionError,
454+
)));
455+
}
456+
457+
// this check shouldn't get hit, unsupported formats should have been rejected in `read_color_information`
458+
// but it seemed better to check this here instead of panicing below if there is an issue
459+
if !(1..=3).contains(&bytes_per_packed_pixel) {
460+
return Err(ImageError::Unsupported(
461+
UnsupportedError::from_format_and_kind(
462+
ImageFormatHint::Exact(ImageFormat::Tga),
463+
UnsupportedErrorKind::GenericFeature(
464+
"Unsupported packed pixel format".to_string(),
465+
),
466+
),
467+
));
468+
}
469+
470+
for i in 0..num_pixels {
471+
let value = match bytes_per_packed_pixel {
472+
1 => stream.read_u8().map(|i| -> u32 { i.to_u32().unwrap() }),
473+
2 => stream
474+
.read_u16::<LittleEndian>()
475+
.map(|i| -> u32 { i.to_u32().unwrap() }),
476+
3 => stream.read_u24::<LittleEndian>(),
477+
_ => unimplemented!(),
478+
}
479+
.map_err(|e| -> ImageError { ImageError::IoError(e) })?;
480+
481+
buf[i * bytes_per_unpacked_pixel + 0] = bitfields.r.read(value);
482+
buf[i * bytes_per_unpacked_pixel + 1] = bitfields.g.read(value);
483+
buf[i * bytes_per_unpacked_pixel + 2] = bitfields.b.read(value);
484+
if bytes_per_unpacked_pixel == 4 {
485+
buf[i * bytes_per_unpacked_pixel + 3] = bitfields.a.read(value);
486+
}
487+
}
488+
} else {
489+
self.reverse_encoding_in_output(buf);
490+
}
396491

397492
self.flip_vertically(buf);
398493

0 commit comments

Comments
 (0)