dds/
lib.rs

1//! Handles decoding (and someday encoding) DirectDraw Surface files.
2//!
3//! # Examples
4//!
5//! ```rust
6//! extern crate dds;
7//!
8//! use std::fs::File;
9//! use std::io::BufReader;
10//! use std::path::Path;
11//!
12//! use dds::DDS;
13//!
14//! fn main() {
15//!     let file = File::open(Path::new("../examples/dxt1.dds")).unwrap();
16//!     let mut reader = BufReader::new(file);
17//!
18//!     let dds = DDS::decode(&mut reader).unwrap();
19//! }
20//! ```
21
22
23#[macro_use]
24extern crate serde_derive;
25extern crate bincode;
26extern crate rgb;
27extern crate serde;
28
29use bincode::{serialize, deserialize, Infinite, ErrorKind};
30
31use std::cmp;
32use std::fmt;
33use std::io;
34use rgb::{ComponentBytes, RGBA};
35
36
37/// Represents an error encountered while parsing a DDS file
38#[derive(Debug)]
39pub enum ParseError {
40    IO(io::Error),
41    Deserialize(Box<ErrorKind>),
42    Parse(String),
43}
44
45impl From<io::Error> for ParseError {
46    fn from(err: io::Error) -> ParseError {
47        ParseError::IO(err)
48    }
49}
50
51impl<'a> From<&'a str> for ParseError {
52    fn from(err: &'a str) -> ParseError {
53        ParseError::Parse(err.into())
54    }
55}
56
57impl From<String> for ParseError {
58    fn from(err: String) -> ParseError {
59        ParseError::Parse(err)
60    }
61}
62
63impl From<Box<ErrorKind>> for ParseError {
64    fn from(err: Box<ErrorKind>) -> ParseError {
65        ParseError::Deserialize(err)
66    }
67}
68
69/// Represents an error encountered while encoding
70/// a `Vec<RGBA>` into `Vec<u8>`.
71#[derive(Debug)]
72pub enum EncodeError {
73    Encode(String),
74}
75
76impl<'a> From<&'a str> for EncodeError {
77    fn from(err: &'a str) -> EncodeError {
78        EncodeError::Encode(err.into())
79    }
80}
81
82impl From<String> for EncodeError {
83    fn from(err: String) -> EncodeError {
84        EncodeError::Encode(err)
85    }
86}
87
88
89/// Pixel information as represented in the DDS file
90///
91/// Direct translation of struct found here:
92/// https://msdn.microsoft.com/en-us/library/bb943984.aspx
93#[repr(C)]
94#[derive(Serialize, Deserialize, PartialEq, Debug)]
95pub struct RawPixelFormat {
96    pub size: u32,
97    pub flags: u32,
98    pub four_cc: [u8; 4],
99    pub rgb_bit_count: u32,
100    pub red_bit_mask: u32,
101    pub green_bit_mask: u32,
102    pub blue_bit_mask: u32,
103    pub alpha_bit_mask: u32,
104}
105
106
107/// Header as represented in the DDS file
108///
109/// Direct translation of struct found here:
110/// https://msdn.microsoft.com/en-us/library/bb943982.aspx
111#[repr(C)]
112#[derive(Serialize, Deserialize, PartialEq, Debug)]
113pub struct RawHeader {
114    pub size: u32,
115    pub flags: u32,
116    pub height: u32,
117    pub width: u32,
118    pub pitch_or_linear_size: u32,
119    pub depth: u32,
120    pub mipmap_count: u32,
121    pub reserved: [u32; 11],
122    pub pixel_format: RawPixelFormat,
123    pub caps: u32,
124    pub caps2: u32,
125    pub caps3: u32,
126    pub caps4: u32,
127    pub reserved2: u32,
128}
129
130/// Convenience enum for storing common pixel formats
131///
132/// See here for more information about the common formats:
133/// https://msdn.microsoft.com/en-us/library/bb943991.aspx
134#[derive(Debug, PartialEq)]
135pub enum PixelFormat {
136    A1R5G5B5,
137    A2B10G10R10,
138    A2R10G10B10,
139    A4L4,
140    A4R4G4B4,
141    A8,
142    A8B8G8R8,
143    A8L8,
144    A8R3G3B2,
145    A8R8G8B8,
146    G16R16,
147    L16,
148    L8,
149    R5G6B5,
150    R8G8B8,
151    Unknown,
152    X1R5G5B5,
153    X4R4G4B4,
154    X8B8G8R8,
155    X8R8G8B8,
156}
157
158impl fmt::Display for PixelFormat {
159    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160        write!(f, "{:?}", self)
161    }
162}
163
164/// Represents the compression format of a DDS file,
165/// aka the four-cc bytes.
166#[derive(Debug)]
167pub enum Compression {
168    DXT1,
169    DXT2,
170    DXT3,
171    DXT4,
172    DXT5,
173    DX10,
174    None,
175    Other(u8, u8, u8, u8),
176}
177
178impl Compression {
179    fn from_bytes(bytes: &[u8; 4]) -> Compression {
180        match bytes {
181            b"\x00\x00\x00\x00" => Compression::None,
182            b"DXT1" => Compression::DXT1,
183            b"DXT2" => Compression::DXT2,
184            b"DXT3" => Compression::DXT3,
185            b"DXT4" => Compression::DXT4,
186            b"DXT5" => Compression::DXT5,
187            b"DX10" => Compression::DX10,
188            _ => Compression::Other(bytes[0], bytes[1], bytes[2], bytes[3]),
189        }
190    }
191}
192
193impl fmt::Display for Compression {
194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195        write!(f, "{:?}", self)
196    }
197}
198
199/// Represents a parsed DDS header. Has several convenience attributes.
200#[derive(Debug)]
201pub struct Header {
202    /// Height of the main image
203    pub height: u32,
204
205    /// Width of the main image
206    pub width: u32,
207
208    /// How many levels of mipmaps there are
209    pub mipmap_count: u32,
210
211    /// Compression type used
212    pub compression: Compression,
213
214    /// The 4-character code for this image
215    pub fourcc: [u8; 4],
216
217    /// The pixel format used
218    pub pixel_format: PixelFormat,
219
220    /// The number of bytes used per-pixel
221    pub pixel_bytes: usize,
222
223    /// The bit masks used for each channel
224    pub channel_masks: [u32; 4],
225}
226
227impl Header {
228    // Returns layer sizes
229    fn get_layer_sizes(&self) -> Vec<(usize, usize)> {
230        // Files with only a single texture will often have
231        // the mipmap count set to 0, so we force generating
232        // at least a single level
233        (0..cmp::max(self.mipmap_count, 1))
234            .map(|i: u32| (
235                (self.height / 2u32.pow(i)) as usize,
236                (self.width / 2u32.pow(i)) as usize,
237            ))
238            .collect::<Vec<_>>()
239    }
240}
241
242
243/// Represents a parsed DDS file
244pub struct DDS {
245    /// The parsed DDS header
246    pub header: Header,
247
248    /// Mipmap layers
249    pub layers: Vec<Vec<RGBA<u8>>>,
250}
251
252
253impl DDS {
254    // Parses some common pixel formats from the raw bit masks, for convenience
255    fn parse_pixel_format(header: &RawHeader) -> PixelFormat {
256        let p = &header.pixel_format;
257
258        match (p.rgb_bit_count, p.red_bit_mask, p.green_bit_mask, p.blue_bit_mask, p.alpha_bit_mask) {
259            (16,     0x7C00,      0x3E0,       0x1F,     0x8000) => PixelFormat::A1R5G5B5,
260            (32,      0x3FF,    0xFFC00, 0x3FF00000, 0xC0000000) => PixelFormat::A2B10G10R10,
261            (32, 0x3FF00000,    0xFFC00,      0x3FF, 0xC0000000) => PixelFormat::A2R10G10B10,
262            ( 8,        0xF,        0x0,        0x0,       0xF0) => PixelFormat::A4L4,
263            (16,      0xF00,       0xF0,        0xF,     0xF000) => PixelFormat::A4R4G4B4,
264            ( 8,        0x0,        0x0,        0x0,       0xFF) => PixelFormat::A8,
265            (32,       0xFF,     0xFF00,   0xFF0000, 0xFF000000) => PixelFormat::A8B8G8R8,
266            (16,       0xFF,        0x0,        0x0,     0xFF00) => PixelFormat::A8L8,
267            (16,       0xE0,       0x1C,        0x3,     0xFF00) => PixelFormat::A8R3G3B2,
268            (32,   0xFF0000,     0xFF00,       0xFF, 0xFF000000) => PixelFormat::A8R8G8B8,
269            (32,     0xFFFF, 0xFFFF0000,        0x0,        0x0) => PixelFormat::G16R16,
270            (16,     0xFFFF,        0x0,        0x0,        0x0) => PixelFormat::L16,
271            ( 8,       0xFF,        0x0,        0x0,        0x0) => PixelFormat::L8,
272            (16,     0xF800,      0x7E0,       0x1F,        0x0) => PixelFormat::R5G6B5,
273            (24,   0xFF0000,     0xFF00,       0xFF,        0x0) => PixelFormat::R8G8B8,
274            (16,     0x7C00,      0x3E0,       0x1F,        0x0) => PixelFormat::X1R5G5B5,
275            (16,      0xF00,       0xF0,        0xF,        0x0) => PixelFormat::X4R4G4B4,
276            (32,       0xFF,     0xFF00,   0xFF0000,        0x0) => PixelFormat::X8B8G8R8,
277            (32,   0xFF0000,     0xFF00,       0xFF,        0x0) => PixelFormat::X8R8G8B8,
278            ( _,          _,          _,          _,          _) => PixelFormat::Unknown,
279        }
280    }
281
282    /// Parses a `Header` object from a raw `u8` buffer.
283    pub fn parse_header<R: io::Read>(buf: &mut R) -> Result<Header, ParseError> {
284        let raw_header = DDS::parse_header_raw(buf)?;
285
286        Ok(Header {
287            height: raw_header.height,
288            width: raw_header.width,
289            mipmap_count: raw_header.mipmap_count,
290            compression: Compression::from_bytes(&raw_header.pixel_format.four_cc),
291            fourcc: raw_header.pixel_format.four_cc,
292            pixel_format: DDS::parse_pixel_format(&raw_header),
293            pixel_bytes: raw_header.pixel_format.rgb_bit_count as usize / 8,
294            channel_masks: [
295                raw_header.pixel_format.red_bit_mask,
296                raw_header.pixel_format.green_bit_mask,
297                raw_header.pixel_format.blue_bit_mask,
298                raw_header.pixel_format.alpha_bit_mask,
299            ],
300        })
301    }
302
303    /// Parses the raw header from the image. Useful for getting information not contained
304    /// in the normal parsed Header struct.
305    pub fn parse_header_raw<R: io::Read>(buf: &mut R) -> Result<RawHeader, ParseError> {
306        let mut magic_buf = [0; 4];
307        let mut header_buf = [0u8; 124];
308
309        buf.read_exact(&mut magic_buf[..]).expect("Not enough bytes to read magic bytes!");
310
311        // If the file doesn't start with `DDS `, abort decoding
312        if &magic_buf != b"DDS " {
313            return Err(format!("Expected the file to start with `DDS `, got `{}` instead.", String::from_utf8_lossy(&magic_buf)).into());
314        }
315
316        buf.read_exact(&mut header_buf[..]).expect("Not enough bytes to read header!");
317
318        Ok(deserialize(&header_buf[..])?)
319    }
320    // Handles decoding an uncompressed buffer into a series of mipmap images
321    fn decode_uncompressed(header: &Header, data_buf: &mut Vec<u8>) -> Vec<Vec<RGBA<u8>>> {
322        let layer_sizes = header.get_layer_sizes();
323
324        // Take the vec of layer sizes and map to a vec of layers
325        layer_sizes
326        .iter()
327        .map(|&(h, w)| {
328            data_buf
329            // Remove the pixels we care about from the buffer
330            .drain(..h * w * header.pixel_bytes)
331            .collect::<Vec<_>>()
332            // Chunk into groups of 3 or 4, then convert to normalized [u8; 4] RGBA format
333            .chunks(header.pixel_bytes)
334            .map(|p| {
335                let pixel: u32 = p[0] as u32 + ((p[1] as u32) << 8) + ((p[2] as u32) << 16) + ((p[3] as u32) << 24);
336
337                // Given a mask, we first take the bits we care about and shift them down to start
338                // at 0. After that, we convert them to being in the range [0, 256)
339                let convert = |mask: u32| -> u8 {
340                    ((pixel & mask) >> mask.trailing_zeros() * 255 / (2u32.pow(mask.count_ones()) - 1)) as u8
341                };
342
343                RGBA {
344                    r: convert(header.channel_masks[0]),
345                    g: convert(header.channel_masks[1]),
346                    b: convert(header.channel_masks[2]),
347                    a: convert(header.channel_masks[3]),
348                }
349            })
350            .collect()
351        })
352        .collect()
353    }
354
355    // Handles decoding a DXT1-compressed 64-bit buffer into 16 pixels. Handles 1-bit alpha variant
356    // with `alpha` parameter
357    fn bytes_to_pixels_dxt1(bytes: &[u8], alpha: bool) -> Vec<RGBA<u8>> {
358        // Convert to `u32` to allow overflow for arithmetic below
359        let color0 = (((bytes[1] as u16) << 8) + bytes[0] as u16) as u32;
360        let color1 = (((bytes[3] as u16) << 8) + bytes[2] as u16) as u32;
361
362        // Iterate through each pair of bits in each `code` byte to
363        // determine the color for each pixel
364        bytes[4..]
365        .iter()
366        .rev()
367        .flat_map(|&code| {
368            (0..4)
369            .map(|i| {
370                // Implements this lookup table for calculating pixel colors.
371                // Used on a per channel basis, except for calculating
372                // `color0 > color1`.
373                //
374                // code | color0 > color1 | color0 <= color1
375                // -----------------------------------------
376                //   0  |       c0        |       c0
377                //   1  |       c1        |       c1
378                //   2  | (2*c0 + c1) / 3 |  (c0 + c1) / 2
379                //   3  | (c0 + 2*c1) / 3 |      black
380                //
381                // Returns an Option to differentiate between a black pixel and a transparent pixel
382                let lookup = |c0: u32, c1: u32, inflate_by: u32| {
383                    // Inflate colors from 5/6-bit to 8-bit
384                    let c0 = c0 * 255 / (2u32.pow(inflate_by) - 1);
385                    let c1 = c1 * 255 / (2u32.pow(inflate_by) - 1);
386
387                    match (color0 > color1, (code >> (i * 2)) & 0x3) {
388                        ( true, 0) => Some(c0),
389                        ( true, 1) => Some(c1),
390                        ( true, 2) => Some((2 * c0 + c1) / 3),
391                        ( true, 3) => Some((c0 + 2 * c1) / 3),
392                        (false, 0) => Some(c0),
393                        (false, 1) => Some(c1),
394                        (false, 2) => Some((c0 + c1) / 2),
395                        (false, 3) => None,
396                        _ => unreachable!(),
397                    }
398                };
399
400                let red0 = (color0 & 0xF800) >> 11;
401                let red1 = (color1 & 0xF800) >> 11;
402                let green0 = (color0 & 0x7E0) >> 5;
403                let green1 = (color1 & 0x7E0) >> 5;
404                let blue0 = color0 & 0x1F;
405                let blue1 = color1 & 0x1F;
406
407                // Calculate actual colors. If alpha is disabled or if any channel is non-black,
408                // show the pixel. Otherwise, hide it.
409                let r = lookup(red0, red1, 5);
410                let g = lookup(green0, green1, 6);
411                let b = lookup(blue0, blue1, 5);
412                let a = if !alpha || r.is_some() || g.is_some() || b.is_some() {
413                    255
414                } else {
415                    0
416                };
417
418                RGBA {
419                    r: r.unwrap_or(0) as u8,
420                    g: g.unwrap_or(0) as u8,
421                    b: b.unwrap_or(0) as u8,
422                    a,
423                }
424            })
425            .collect::<Vec<_>>()
426        })
427        .collect::<Vec<_>>()
428    }
429
430    // Handles decoding a DXT2/3-compressed 128-bit buffer into 16 pixels
431    fn bytes_to_pixels_dxt3(bytes: &[u8]) -> Vec<RGBA<u8>> {
432        // Convert to `u32` to allow overflow for arithmetic below
433        let color0 = (((bytes[9] as u16) << 8) + bytes[8] as u16) as u32;
434        let color1 = (((bytes[11] as u16) << 8) + bytes[10] as u16) as u32;
435
436        // Iterate through each pair of bits in each `code` byte to
437        // determine the color for each pixel
438        bytes[12..]
439        .iter()
440        .rev()
441        .enumerate()
442        .flat_map(|(i, &code)| {
443            (0..4)
444            .map(|j| {
445                let lookup = |c0: u32, c1: u32, inflate_by: u32| -> u32 {
446                    // Inflate colors from 5/6-bit to 8-bit
447                    let c0 = c0 * 255 / (2u32.pow(inflate_by) - 1);
448                    let c1 = c1 * 255 / (2u32.pow(inflate_by) - 1);
449
450                    match (code >> (j * 2)) & 0x3 {
451                        0 => c0,
452                        1 => c1,
453                        2 => (2 * c0 + c1) / 3,
454                        3 => (c0 + 2 * c1) / 3,
455                        _ => unreachable!(),
456                    }
457                };
458
459                let alpha_nibble = (bytes[2 * (3 - i) + j / 2] >> (4 * (j % 2))) & 0xF;
460
461                let red0 = (color0 & 0xF800) >> 11;
462                let red1 = (color1 & 0xF800) >> 11;
463                let green0 = (color0 & 0x7E0) >> 5;
464                let green1 = (color1 & 0x7E0) >> 5;
465                let blue0 = color0 & 0x1F;
466                let blue1 = color1 & 0x1F;
467
468                RGBA {
469                    r: lookup(red0, red1, 5) as u8,
470                    g: lookup(green0, green1, 6) as u8,
471                    b: lookup(blue0, blue1, 5) as u8,
472                    a: (alpha_nibble as u32 * 255 / 15) as u8,
473                }
474            })
475            .collect::<Vec<_>>()
476        })
477        .collect::<Vec<_>>()
478    }
479
480    // Handles decoding a DXT4/5-compressed 128-bit buffer into 16 pixels
481    fn bytes_to_pixels_dxt5(bytes: &[u8]) -> Vec<RGBA<u8>> {
482        let color0 = (((bytes[9] as u16) << 8) + bytes[8] as u16) as u32;
483        let color1 = (((bytes[11] as u16) << 8) + bytes[10] as u16) as u32;
484
485        let alpha0 = bytes[0] as u32;
486        let alpha1 = bytes[1] as u32;
487
488        // Convert 6 u8's into a single 48 bit number, to make it easier to grab 3-bit
489        // chunks out of them.
490        let alpha_info = bytes[2..8]
491        .iter()
492        .enumerate()
493        .fold(0u64, |memo, (i, &x)| memo + ((x as u64) << 8 * i) as u64);
494
495        bytes[12..]
496        .iter()
497        .rev()
498        .enumerate()
499        .flat_map(|(i, &code)| {
500            (0..4)
501            .map(|j| {
502                // Implements this lookup table for calculating pixel colors.
503                // Used on a per channel basis, except for calculating
504                // `color0 > color1`.
505                //
506                // code |      value      |
507                // ------------------------
508                //   0  |       c0        |
509                //   1  |       c1        |
510                //   2  | (2*c0 + c1) / 3 |
511                //   3  | (c0 + 2*c1) / 3 |
512                let lookup = |c0: u32, c1: u32, inflate_by: u32| -> u32 {
513                    // Inflate colors from 5/6-bit to 8-bit
514                    let c0 = c0 * 255 / (2u32.pow(inflate_by) - 1);
515                    let c1 = c1 * 255 / (2u32.pow(inflate_by) - 1);
516
517                    match (code >> (j * 2)) & 0x3 {
518                        0 => c0,
519                        1 => c1,
520                        2 => (2 * c0 + c1) / 3,
521                        3 => (c0 + 2 * c1) / 3,
522                        _ => unreachable!(),
523                    }
524                };
525
526                let red0 = (color0 & 0xF800) >> 11;
527                let red1 = (color1 & 0xF800) >> 11;
528                let green0 = (color0 & 0x7E0) >> 5;
529                let green1 = (color1 & 0x7E0) >> 5;
530                let blue0 = color0 & 0x1F;
531                let blue1 = color1 & 0x1F;
532
533
534                // Interpolate between two given alpha values based on the 3-bit lookup value
535                // stored in `alpha_info`.
536                let alpha = match (alpha0 > alpha1, (alpha_info >> (3 * (4 * (3 - i) + j))) & 0x07) {
537                    (true, 0) => alpha0,
538                    (true, 1) => alpha1,
539                    (true, 2) => (6 * alpha0 + 1 * alpha1) / 7,
540                    (true, 3) => (5 * alpha0 + 2 * alpha1) / 7,
541                    (true, 4) => (4 * alpha0 + 3 * alpha1) / 7,
542                    (true, 5) => (3 * alpha0 + 4 * alpha1) / 7,
543                    (true, 6) => (2 * alpha0 + 5 * alpha1) / 7,
544                    (true, 7) => (1 * alpha0 + 6 * alpha1) / 7,
545                    (false, 0) => alpha0,
546                    (false, 1) => alpha1,
547                    (false, 2) => (4 * alpha0 + 1 * alpha1) / 5,
548                    (false, 3) => (3 * alpha0 + 2 * alpha1) / 5,
549                    (false, 4) => (2 * alpha0 + 3 * alpha1) / 5,
550                    (false, 5) => (1 * alpha0 + 4 * alpha1) / 5,
551                    (false, 6) => 0,
552                    (false, 7) => 255,
553                    t => unreachable!(format!("This value should not have occurred: `{:?}`", t)),
554                };
555
556                RGBA {
557                    r: lookup(red0, red1, 5) as u8,
558                    g: lookup(green0, green1, 6) as u8,
559                    b: lookup(blue0, blue1, 5) as u8,
560                    a: alpha as u8,
561                }
562            })
563            .collect::<Vec<_>>()
564        })
565        .collect::<Vec<_>>()
566    }
567
568    // Handles decoding a DXT1-5 compressed buffer into a series of mipmap images
569    fn decode_dxt(header: &Header, data_buf: &mut Vec<u8>) -> Vec<Vec<RGBA<u8>>> {
570        let layer_sizes = header.get_layer_sizes();
571
572        // Take the vec of layer sizes and map to a vec of layers
573        layer_sizes
574        .iter()
575        .map(|&(height, width)| {
576            // We calculate the actual height and width here. Although the given height/width
577            // can go down to 1, the block sizes are minimum 4x4, which we enforce here. We
578            // then also round up to the nearest even divisor of 4. For example, a 47x49 texture
579            // is actually stored as a 48x52 texture.
580            let h = (cmp::max(height, 4)  as f32 / 4.0).ceil() as usize * 4;
581            let w = (cmp::max(width, 4)  as f32 / 4.0).ceil() as usize * 4;
582
583            // DXT1 compression uses 64 bits per 16 pixels, while DXT2-5 use 128 bits.
584            // Calculate how many total bytes to read out of the buffer for each layer
585            // here, as well as how big each individual chunk size is.
586            let (layer_bytes, chunk_size) = match header.compression {
587                Compression::DXT1 => (h * w / 2, 8),
588                _ => (h * w, 16),
589            };
590
591            // Pulled out to here because it doesn't like being in the `flat_map` call without
592            // type hinting. Kind of ugly with all the boxes and closures, but otherwise get an
593            // error about incompatible match arm types.
594            let chunk_transform: Box<Fn(&[u8]) -> Vec<RGBA<u8>>> = match header.compression {
595                Compression::DXT1 => Box::new(|chunk|
596                    DDS::bytes_to_pixels_dxt1(chunk, header.pixel_format != PixelFormat::Unknown)
597                ),
598                Compression::DXT2 | Compression::DXT3 => Box::new(|chunk|
599                    DDS::bytes_to_pixels_dxt3(chunk)
600                ),
601                Compression::DXT4 | Compression::DXT5 => Box::new(|chunk|
602                    DDS::bytes_to_pixels_dxt5(chunk)
603                ),
604                _ => unreachable!(format!("This function cannot handle `{:?}` images", header.compression)),
605            };
606
607            data_buf
608            // Remove the pixels we care about from the buffer
609            .drain(..layer_bytes)
610            .collect::<Vec<_>>()
611             // Chunk into blocks of appropriate size
612            .chunks(chunk_size)
613            // Turn those blocks into 16 `[u8; 4]` pixels, and flatten into a
614            // vec of pixels for the entire image. Follow here for the dirty details:
615            // https://www.khronos.org/opengl/wiki/S3_Texture_Compression
616            .flat_map(|chunk| chunk_transform(chunk))
617            .collect::<Vec<_>>()
618            // Since the 16 byte pixel blocks are actually 4x4 texels, group image
619            // into chunks of four rows each, and then transpose into a row of texels.
620            .chunks(4 * w)
621            .flat_map(|p| {
622                let mut pixels = Vec::new();
623
624                for i in (0..4).rev() {
625                    for j in 0..w / 4 {
626                        // If this is the last block in a row and the image width is not evenly
627                        // divisible by 4, we only push enough pixels to fill the rest of the block
628                        // width.
629                        let block_width = if j + 1 == w / 4 {
630                            4 - (w - width)
631                        } else {
632                            4
633                        };
634
635                        for k in 0..block_width {
636                            pixels.push(p[(i + j * 4) * 4 + k]);
637                        }
638                    }
639                }
640
641                pixels
642            })
643            // And that's it!
644            .collect::<Vec<_>>()
645        })
646        .collect::<Vec<_>>()
647    }
648
649    /// Decodes a buffer into a header and a series of mipmap images.
650    /// Handles uncompressed and DXT1-5 compressed images.
651    pub fn decode<R: io::Read>(buf: &mut R) -> Result<DDS, ParseError> {
652        let header = DDS::parse_header(buf)?;
653
654        let mut data_buf = Vec::new();
655        buf.read_to_end(&mut data_buf)?;
656
657        let layers = match header.compression {
658            Compression::None => {
659                DDS::decode_uncompressed(&header, &mut data_buf)
660            }
661            Compression::DXT1 | Compression::DXT2| Compression::DXT3 | Compression::DXT4 | Compression::DXT5 => {
662                DDS::decode_dxt(&header, &mut data_buf)
663            }
664            _ => {
665                let compression_type = String::from_utf8_lossy(&header.fourcc[..]);
666                return Err(format!("The compression type `{}` is unsupported!", compression_type).into());
667            }
668        };
669
670        Ok(DDS {
671            header,
672            layers,
673        })
674    }
675
676    /// Encodes a series of Pixels as a bunch of bytes, suitable for writing to disk, etc.
677    /// Currently only supports uncompressed RGBA images
678    pub fn encode(pixels: &Vec<RGBA<u8>>, size: (u32, u32), compression: Compression) -> Result<Vec<u8>, EncodeError> {
679        // Make sure we don't have more/less data than claimed
680        if size.0 * size.1 < pixels.len() as u32 {
681            return Err(format!("Found {} extra bytes!", pixels.len() as u32 - size.0 * size.1).into());
682        }
683
684        if size.0 * size.1 > pixels.len() as u32 {
685            return Err(format!("Need {} extra bytes!", size.0 * size.1 - pixels.len() as u32).into());
686        }
687
688        match compression {
689            Compression::None => {
690                // Start with magic number
691                let mut data = b"DDS ".to_vec();
692
693                // Add header to buffer
694                data.extend(serialize(&RawHeader {
695                    size: size.0 * size.1 * 4,
696                    flags: 0,
697                    height: size.0,
698                    width: size.1,
699                    pitch_or_linear_size: 0,
700                    depth: 0,
701                    mipmap_count: 0,
702                    reserved: [0; 11],
703                    pixel_format: RawPixelFormat {
704                        size: 0,
705                        flags: 0x41,
706                        four_cc: [0; 4],
707                        rgb_bit_count: 32,
708                        red_bit_mask: 0xFF,
709                        green_bit_mask: 0xFF00,
710                        blue_bit_mask: 0xFF0000,
711                        alpha_bit_mask: 0xFF000000,
712                    },
713                    caps: 0,
714                    caps2: 0,
715                    caps3: 0,
716                    caps4: 0,
717                    reserved2: 0,
718                }, Infinite).unwrap());
719
720                // Add layers to buffer
721                data.extend(pixels.as_bytes());
722
723                Ok(data)
724            }
725            _ => Err(format!("Cannot encode {:?}!", compression).into())
726        }
727
728    }
729}