@@ -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,7 +102,7 @@ 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
90107 if width == 0 || height == 0 {
91108 return Err ( ImageError :: Decoding ( DecodingError :: new (
@@ -94,15 +111,6 @@ impl<R: Read> TgaDecoder<R> {
94111 ) ) ) ;
95112 }
96113
97- // Validate header
98- if ![ 8 , 16 , 24 , 32 ] . contains ( & header. pixel_depth ) || ![ 0 , 8 ] . contains ( & num_alpha_bits) {
99- return Err ( ImageError :: Unsupported (
100- UnsupportedError :: from_format_and_kind (
101- ImageFormat :: Tga . into ( ) ,
102- UnsupportedErrorKind :: Color ( ExtendedColorType :: Unknown ( header. pixel_depth ) ) ,
103- ) ,
104- ) ) ;
105- }
106114 if image_type. is_color_mapped ( ) {
107115 if header. map_type != 1 {
108116 return Err ( ImageError :: Decoding ( DecodingError :: new (
@@ -126,49 +134,14 @@ impl<R: Read> TgaDecoder<R> {
126134 }
127135 }
128136
129- // TODO: validate the rest of the fields in the header.
130-
131- // Read image ID (and ignore it)
132- let mut tmp = [ 0u8 ; 256 ] ;
133- r. read_exact ( & mut tmp[ 0 ..header. id_length as usize ] ) ?;
134-
135- // Read color map
136- let mut color_map = None ;
137- if header. map_type == 1 {
138- let entry_size = ( header. map_entry_size as usize ) . div_ceil ( 8 ) ;
139- if ![ 2 , 3 , 4 ] . contains ( & entry_size) {
140- return Err ( ImageError :: Unsupported (
141- UnsupportedError :: from_format_and_kind (
142- ImageFormat :: Tga . into ( ) ,
143- UnsupportedErrorKind :: GenericFeature (
144- "Unsupported color map entry size" . into ( ) ,
145- ) ,
146- ) ,
147- ) ) ;
148- }
149-
150- let mut bytes = Vec :: new ( ) ;
151- r. read_exact_vec ( & mut bytes, entry_size * header. map_length as usize ) ?;
152-
153- // Color maps are technically allowed in non-color-mapped images, so check that we
154- // actually need the color map before storing it.
155- if image_type. is_color_mapped ( ) {
156- color_map = Some ( ColorMap {
157- entry_size,
158- start_offset : header. map_origin as usize ,
159- bytes,
160- } ) ;
161- }
162- }
163-
164137 // Compute output pixel depth
165- let total_pixel_bits = if header . map_type == 1 {
138+ let total_pixel_bits = if image_type . is_color_mapped ( ) {
166139 header. map_entry_size
167140 } else {
168141 header. pixel_depth
169142 } ;
170143 let num_other_bits = total_pixel_bits
171- . checked_sub ( num_alpha_bits )
144+ . checked_sub ( num_attrib_bits )
172145 . ok_or_else ( || {
173146 ImageError :: Decoding ( DecodingError :: new (
174147 ImageFormat :: Tga . into ( ) ,
@@ -179,12 +152,19 @@ impl<R: Read> TgaDecoder<R> {
179152 // Determine color type
180153 let color_type;
181154 let mut original_color_type = None ;
182- match ( num_alpha_bits , num_other_bits, image_type. is_color ( ) ) {
155+ match ( num_attrib_bits , num_other_bits, image_type. is_color ( ) ) {
183156 // really, the encoding is BGR and BGRA, this is fixed up with
184157 // `TgaDecoder::reverse_encoding`.
185158 ( 0 , 32 , true ) => color_type = ColorType :: Rgba8 ,
186159 ( 8 , 24 , true ) => color_type = ColorType :: Rgba8 ,
187160 ( 0 , 24 , true ) => color_type = ColorType :: Rgb8 ,
161+ ( 1 , 15 , true ) | ( 0 , 15 , true ) | ( 0 , 16 , true ) => {
162+ // the 'A' bit for 5-bit-per-primary images is an 'attribute'
163+ // bit, and cannot safely be interpreted as an alpha channel.
164+ // (It may contain all zero values or a pattern unrelated to the image.)
165+ color_type = ColorType :: Rgb8 ;
166+ original_color_type = Some ( ExtendedColorType :: Rgb5x1 ) ;
167+ }
188168 ( 8 , 8 , false ) => color_type = ColorType :: La8 ,
189169 ( 0 , 8 , false ) => color_type = ColorType :: L8 ,
190170 ( 8 , 0 , false ) => {
@@ -202,6 +182,52 @@ impl<R: Read> TgaDecoder<R> {
202182 }
203183 }
204184
185+ // TODO: validate the rest of the fields in the header.
186+
187+ // Read image ID (and ignore it)
188+ let mut tmp = [ 0u8 ; 256 ] ;
189+ r. read_exact ( & mut tmp[ 0 ..header. id_length as usize ] ) ?;
190+
191+ // Read color map
192+ let mut color_map = None ;
193+ if header. map_type == 1 {
194+ if ![ 15 , 16 , 24 , 32 ] . contains ( & header. map_entry_size ) {
195+ return Err ( ImageError :: Unsupported (
196+ UnsupportedError :: from_format_and_kind (
197+ ImageFormat :: Tga . into ( ) ,
198+ UnsupportedErrorKind :: GenericFeature (
199+ "Unsupported color map entry size" . into ( ) ,
200+ ) ,
201+ ) ,
202+ ) ) ;
203+ }
204+ let mut entry_size = ( header. map_entry_size as usize ) . div_ceil ( 8 ) ;
205+
206+ let mut bytes = Vec :: new ( ) ;
207+ r. read_exact_vec ( & mut bytes, entry_size * header. map_length as usize ) ?;
208+
209+ // Color maps are technically allowed in non-color-mapped images, so check that we
210+ // actually need the color map before storing it.
211+ if image_type. is_color_mapped ( ) {
212+ // Pre-expand 5-bit-per-primary values to simplify later decoding
213+ if [ 15 , 16 ] . contains ( & header. map_entry_size ) {
214+ let mut expanded = Vec :: new ( ) ;
215+ for entry in bytes. chunks_exact ( 2 ) {
216+ expanded
217+ . extend_from_slice ( & expand_rgb15_to_rgb24 ( entry. try_into ( ) . unwrap ( ) ) ) ;
218+ }
219+ bytes = expanded;
220+ entry_size = 3 ;
221+ }
222+
223+ color_map = Some ( ColorMap {
224+ entry_size,
225+ start_offset : header. map_origin as usize ,
226+ bytes,
227+ } ) ;
228+ }
229+ }
230+
205231 Ok ( TgaDecoder {
206232 r,
207233
@@ -396,6 +422,15 @@ impl<R: Read> ImageDecoder for TgaDecoder<R> {
396422 rawbuf. extend_from_slice ( & buf[ ..num_raw_bytes] ) ;
397423
398424 self . expand_color_map ( & rawbuf, buf, color_map) ?;
425+ } else if self . original_color_type == Some ( ExtendedColorType :: Rgb5x1 ) {
426+ // Expand the 15-bit to 24-bit representation for non-color-mapped images;
427+ // the expansion for color-mapped 15-bit images was already done in the color map
428+ let mut rawbuf = vec_try_with_capacity ( num_raw_bytes) ?;
429+ rawbuf. extend_from_slice ( & buf[ ..num_raw_bytes] ) ;
430+
431+ for ( src, dst) in rawbuf. chunks_exact ( 2 ) . zip ( buf. chunks_exact_mut ( 3 ) ) {
432+ dst. copy_from_slice ( & expand_rgb15_to_rgb24 ( src. try_into ( ) . unwrap ( ) ) ) ;
433+ }
399434 }
400435
401436 self . reverse_encoding_in_output ( buf) ;
0 commit comments