1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use crate::parse_error::ParseError;
use nom::*;

/// TGA footer length in bytes
pub const HEADER_LEN: usize = 18;

/// Image type
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ImageType {
    /// Image contains no pixel data
    Empty = 0,

    /// Color mapped image
    ColorMapped = 1,

    /// Truecolor image
    Truecolor = 2,

    /// Monochrome (greyscale) image
    Monochrome = 3,

    /// Run length encoded color mapped image
    RleColorMapped = 9,

    /// Run length encoded RGB image
    RleTruecolor = 10,

    /// Run length encoded monochrome (greyscale) image
    RleMonochrome = 11,
}

/// TGA header structure, referenced from <https://www.fileformat.info/format/tga/egff.htm>
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TgaHeader {
    /// Image ID field length
    pub id_len: u8,

    /// Whether a color map is included in the image data
    pub has_color_map: bool,

    /// Image type
    pub image_type: ImageType,

    /// Color map origin
    pub color_map_start: u16,

    /// Length of color map
    pub color_map_len: u16,

    /// Number of bits in each color palette entry, typically 15, 16, 24, or 32 bits
    pub color_map_depth: u8,

    /// Image origin (X)
    pub x_origin: u16,

    /// Image origin (Y)
    pub y_origin: u16,

    /// Image width in pixels
    pub width: u16,

    /// Image height in pixels
    pub height: u16,

    /// Pixel bit depth (8, 16, 24, 32 bits)
    pub pixel_depth: u8,

    /// Image descriptor (unused)
    ///
    /// Bits 0:3: Number of bits per pixel designated to alpha channel
    /// Bits 4:5: Image origin:
    ///
    /// * `00` = bottom left
    /// * `01` = bottom right
    /// * `10` = top left
    /// * `11` = top right
    pub image_descriptor: u8,
}

named!(has_color_map<&[u8], bool>,
    map_res!(
        le_u8,
        |b| match b {
            0 => Ok(false),
            1 => Ok(true),
            other => Err(ParseError::UnknownColorMap(other))
        }
    )
);

named!(image_type<&[u8], ImageType>,
    map_res!(
        le_u8,
        |b| match b {
            0 => Ok(ImageType::Empty),
            1 => Ok(ImageType::ColorMapped),
            2 => Ok(ImageType::Truecolor),
            3 => Ok(ImageType::Monochrome),
            9 => Ok(ImageType::RleColorMapped),
            10 => Ok(ImageType::RleTruecolor),
            11 => Ok(ImageType::RleMonochrome),
            other => Err(ParseError::UnknownImageType(other))
        }
    )
);

named!(pub header<&[u8], TgaHeader>,
    do_parse!(
        id_len: le_u8 >>
        has_color_map: has_color_map >>
        image_type: image_type >>
        color_map_start: le_u16 >>
        color_map_len: le_u16 >>
        color_map_depth: le_u8 >>
        x_origin: le_u16 >>
        y_origin: le_u16 >>
        width: le_u16 >>
        height: le_u16 >>
        pixel_depth: le_u8 >>
        image_descriptor: le_u8 >>
        _image_ident: take!(id_len) >>
        ({
            TgaHeader {
                id_len,
                has_color_map,
                image_type,
                color_map_start,
                color_map_len,
                color_map_depth,
                x_origin,
                y_origin,
                width,
                height,
                pixel_depth,
                image_descriptor,
            }
        })
    )
);