@@ -76,6 +76,23 @@ impl TgaOrientation {
76
76
}
77
77
}
78
78
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
+
79
96
impl < R : Read > TgaDecoder < R > {
80
97
/// Create a new decoder that decodes from the stream `r`
81
98
pub fn new ( mut r : R ) -> ImageResult < TgaDecoder < R > > {
@@ -85,7 +102,7 @@ impl<R: Read> TgaDecoder<R> {
85
102
let width = header. image_width as usize ;
86
103
let height = header. image_height as usize ;
87
104
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 ;
89
106
90
107
if width == 0 || height == 0 {
91
108
return Err ( ImageError :: Decoding ( DecodingError :: new (
@@ -94,15 +111,6 @@ impl<R: Read> TgaDecoder<R> {
94
111
) ) ) ;
95
112
}
96
113
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
- }
106
114
if image_type. is_color_mapped ( ) {
107
115
if header. map_type != 1 {
108
116
return Err ( ImageError :: Decoding ( DecodingError :: new (
@@ -126,49 +134,14 @@ impl<R: Read> TgaDecoder<R> {
126
134
}
127
135
}
128
136
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
-
164
137
// 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 ( ) {
166
139
header. map_entry_size
167
140
} else {
168
141
header. pixel_depth
169
142
} ;
170
143
let num_other_bits = total_pixel_bits
171
- . checked_sub ( num_alpha_bits )
144
+ . checked_sub ( num_attrib_bits )
172
145
. ok_or_else ( || {
173
146
ImageError :: Decoding ( DecodingError :: new (
174
147
ImageFormat :: Tga . into ( ) ,
@@ -179,12 +152,19 @@ impl<R: Read> TgaDecoder<R> {
179
152
// Determine color type
180
153
let color_type;
181
154
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 ( ) ) {
183
156
// really, the encoding is BGR and BGRA, this is fixed up with
184
157
// `TgaDecoder::reverse_encoding`.
185
158
( 0 , 32 , true ) => color_type = ColorType :: Rgba8 ,
186
159
( 8 , 24 , true ) => color_type = ColorType :: Rgba8 ,
187
160
( 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
+ }
188
168
( 8 , 8 , false ) => color_type = ColorType :: La8 ,
189
169
( 0 , 8 , false ) => color_type = ColorType :: L8 ,
190
170
( 8 , 0 , false ) => {
@@ -202,6 +182,52 @@ impl<R: Read> TgaDecoder<R> {
202
182
}
203
183
}
204
184
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
+
205
231
Ok ( TgaDecoder {
206
232
r,
207
233
@@ -396,6 +422,15 @@ impl<R: Read> ImageDecoder for TgaDecoder<R> {
396
422
rawbuf. extend_from_slice ( & buf[ ..num_raw_bytes] ) ;
397
423
398
424
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
+ }
399
434
}
400
435
401
436
self . reverse_encoding_in_output ( buf) ;
0 commit comments