@@ -76,6 +76,23 @@ impl TgaOrientation {
7676 }
7777}
7878
79+ /// This contains the nearest integers to the rational numbers
80+ /// `(255 x) / 31`, for each `x` between 0 and 31, inclusive.
81+ static LOOKUP_TABLE_5_BIT_TO_8_BIT : [ u8 ; 32 ] = [
82+ 0 , 8 , 16 , 25 , 33 , 41 , 49 , 58 , 66 , 74 , 82 , 90 , 99 , 107 , 115 , 123 , 132 , 140 , 148 , 156 , 165 , 173 ,
83+ 181 , 189 , 197 , 206 , 214 , 222 , 230 , 239 , 247 , 255 ,
84+ ] ;
85+
86+ /// Convert TGA's 15/16-bit pixel format to its 24 bit pixel format
87+ fn expand_rgb15_to_rgb24 ( data : [ u8 ; 2 ] ) -> [ u8 ; 3 ] {
88+ let val = u16:: from_le_bytes ( data) ;
89+ [
90+ LOOKUP_TABLE_5_BIT_TO_8_BIT [ ( val & 0b11111 ) as usize ] ,
91+ LOOKUP_TABLE_5_BIT_TO_8_BIT [ ( ( val >> 5 ) & 0b11111 ) as usize ] ,
92+ LOOKUP_TABLE_5_BIT_TO_8_BIT [ ( ( val >> 10 ) & 0b11111 ) as usize ] ,
93+ ]
94+ }
95+
7996impl < R : Read > TgaDecoder < R > {
8097 /// Create a new decoder that decodes from the stream `r`
8198 pub fn new ( mut r : R ) -> ImageResult < TgaDecoder < R > > {
@@ -85,17 +102,8 @@ impl<R: Read> TgaDecoder<R> {
85102 let width = header. image_width as usize ;
86103 let height = header. image_height as usize ;
87104 let raw_bytes_per_pixel = ( header. pixel_depth as usize ) . div_ceil ( 8 ) ;
88- let num_alpha_bits = header. image_desc & ALPHA_BIT_MASK ;
105+ let num_attrib_bits = header. image_desc & ALPHA_BIT_MASK ;
89106
90- // Validate header
91- if ![ 8 , 16 , 24 , 32 ] . contains ( & header. pixel_depth ) || ![ 0 , 8 ] . contains ( & num_alpha_bits) {
92- return Err ( ImageError :: Unsupported (
93- UnsupportedError :: from_format_and_kind (
94- ImageFormat :: Tga . into ( ) ,
95- UnsupportedErrorKind :: Color ( ExtendedColorType :: Unknown ( header. pixel_depth ) ) ,
96- ) ,
97- ) ) ;
98- }
99107 if image_type. is_color_mapped ( ) {
100108 if header. map_type != 1 {
101109 return Err ( ImageError :: Decoding ( DecodingError :: new (
@@ -119,49 +127,14 @@ impl<R: Read> TgaDecoder<R> {
119127 }
120128 }
121129
122- // TODO: validate the rest of the fields in the header.
123-
124- // Read image ID (and ignore it)
125- let mut tmp = [ 0u8 ; 256 ] ;
126- r. read_exact ( & mut tmp[ 0 ..header. id_length as usize ] ) ?;
127-
128- // Read color map
129- let mut color_map = None ;
130- if header. map_type == 1 {
131- let entry_size = ( header. map_entry_size as usize ) . div_ceil ( 8 ) ;
132- if ![ 2 , 3 , 4 ] . contains ( & entry_size) {
133- return Err ( ImageError :: Unsupported (
134- UnsupportedError :: from_format_and_kind (
135- ImageFormat :: Tga . into ( ) ,
136- UnsupportedErrorKind :: GenericFeature (
137- "Unsupported color map entry size" . into ( ) ,
138- ) ,
139- ) ,
140- ) ) ;
141- }
142-
143- let mut bytes = Vec :: new ( ) ;
144- r. read_exact_vec ( & mut bytes, entry_size * header. map_length as usize ) ?;
145-
146- // Color maps are technically allowed in non-color-mapped images, so check that we
147- // actually need the color map before storing it.
148- if image_type. is_color_mapped ( ) {
149- color_map = Some ( ColorMap {
150- entry_size,
151- start_offset : header. map_origin as usize ,
152- bytes,
153- } ) ;
154- }
155- }
156-
157130 // Compute output pixel depth
158- let total_pixel_bits = if header . map_type == 1 {
131+ let total_pixel_bits = if image_type . is_color_mapped ( ) {
159132 header. map_entry_size
160133 } else {
161134 header. pixel_depth
162135 } ;
163136 let num_other_bits = total_pixel_bits
164- . checked_sub ( num_alpha_bits )
137+ . checked_sub ( num_attrib_bits )
165138 . ok_or_else ( || {
166139 ImageError :: Decoding ( DecodingError :: new (
167140 ImageFormat :: Tga . into ( ) ,
@@ -172,12 +145,19 @@ impl<R: Read> TgaDecoder<R> {
172145 // Determine color type
173146 let color_type;
174147 let mut original_color_type = None ;
175- match ( num_alpha_bits , num_other_bits, image_type. is_color ( ) ) {
148+ match ( num_attrib_bits , num_other_bits, image_type. is_color ( ) ) {
176149 // really, the encoding is BGR and BGRA, this is fixed up with
177150 // `TgaDecoder::reverse_encoding`.
178151 ( 0 , 32 , true ) => color_type = ColorType :: Rgba8 ,
179152 ( 8 , 24 , true ) => color_type = ColorType :: Rgba8 ,
180153 ( 0 , 24 , true ) => color_type = ColorType :: Rgb8 ,
154+ ( 1 , 15 , true ) | ( 0 , 15 , true ) | ( 0 , 16 , true ) => {
155+ // the 'A' bit for 5-bit-per-primary images is an 'attribute'
156+ // bit, and cannot safely be interpreted as an alpha channel.
157+ // (It may contain all zero values or a pattern unrelated to the image.)
158+ color_type = ColorType :: Rgb8 ;
159+ original_color_type = Some ( ExtendedColorType :: Rgb5 ) ;
160+ }
181161 ( 8 , 8 , false ) => color_type = ColorType :: La8 ,
182162 ( 0 , 8 , false ) => color_type = ColorType :: L8 ,
183163 ( 8 , 0 , false ) => {
@@ -195,6 +175,52 @@ impl<R: Read> TgaDecoder<R> {
195175 }
196176 }
197177
178+ // TODO: validate the rest of the fields in the header.
179+
180+ // Read image ID (and ignore it)
181+ let mut tmp = [ 0u8 ; 256 ] ;
182+ r. read_exact ( & mut tmp[ 0 ..header. id_length as usize ] ) ?;
183+
184+ // Read color map
185+ let mut color_map = None ;
186+ if header. map_type == 1 {
187+ if ![ 15 , 16 , 24 , 32 ] . contains ( & header. map_entry_size ) {
188+ return Err ( ImageError :: Unsupported (
189+ UnsupportedError :: from_format_and_kind (
190+ ImageFormat :: Tga . into ( ) ,
191+ UnsupportedErrorKind :: GenericFeature (
192+ "Unsupported color map entry size" . into ( ) ,
193+ ) ,
194+ ) ,
195+ ) ) ;
196+ }
197+ let mut entry_size = ( header. map_entry_size as usize ) . div_ceil ( 8 ) ;
198+
199+ let mut bytes = Vec :: new ( ) ;
200+ r. read_exact_vec ( & mut bytes, entry_size * header. map_length as usize ) ?;
201+
202+ // Color maps are technically allowed in non-color-mapped images, so check that we
203+ // actually need the color map before storing it.
204+ if image_type. is_color_mapped ( ) {
205+ // Pre-expand 5-bit-per-primary values to simplify later decoding
206+ if [ 15 , 16 ] . contains ( & header. map_entry_size ) {
207+ let mut expanded = Vec :: new ( ) ;
208+ for entry in bytes. chunks_exact ( 2 ) {
209+ expanded
210+ . extend_from_slice ( & expand_rgb15_to_rgb24 ( entry. try_into ( ) . unwrap ( ) ) ) ;
211+ }
212+ bytes = expanded;
213+ entry_size = 3 ;
214+ }
215+
216+ color_map = Some ( ColorMap {
217+ entry_size,
218+ start_offset : header. map_origin as usize ,
219+ bytes,
220+ } ) ;
221+ }
222+ }
223+
198224 Ok ( TgaDecoder {
199225 r,
200226
@@ -389,6 +415,13 @@ impl<R: Read> ImageDecoder for TgaDecoder<R> {
389415 rawbuf. extend_from_slice ( & buf[ ..num_raw_bytes] ) ;
390416
391417 self . expand_color_map ( & rawbuf, buf, color_map) ?;
418+ } else if self . original_color_type == Some ( ExtendedColorType :: Rgb5 ) {
419+ let mut rawbuf = vec_try_with_capacity ( num_raw_bytes) ?;
420+ rawbuf. extend_from_slice ( & buf[ ..num_raw_bytes] ) ;
421+
422+ for ( src, dst) in rawbuf. chunks_exact ( 2 ) . zip ( buf. chunks_exact_mut ( 3 ) ) {
423+ dst. copy_from_slice ( & expand_rgb15_to_rgb24 ( src. try_into ( ) . unwrap ( ) ) ) ;
424+ }
392425 }
393426
394427 self . reverse_encoding_in_output ( buf) ;
0 commit comments