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
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Low-level PNG API
//!
//! A PNG file consists of a sequence of [`Chunk`](enum.Chunk.html)s in a
//! specific order.
//!
//! # PNG Chunk Order
//! ## Key
//! - **Required** - Count must be exactly one.
//! - **Optional** - Count must be exactly one or zero.
//! - **Multiple** - Count can be any number, including zero.
//!
//! ## Order
//! The PNG/APNG chunk order must be as follows:
//!
//! - **Required** `ImageHeader` "IHDR"
//! - In any order:
//!   - **Optional** `Chromaticities`
//!   - **Optional** `Gamma` "gAMA"
//!   - **Optional** `ColorProfile` "iCCP"
//!   - **Optional** `SignificantBits` "sBIT"
//!   - **Optional** `SRgb` "sRGB"
//!   - **Optional** `Physical` "pHYs"
//!   - **Multiple** `SuggestedPalette` "sPLT"
//!   - **Optional** `Time` "tIME" (If didn't appear earlier)
//!   - **Multiple** `InternationalText` "iTXt"
//!   - **Multiple** `Text` "tEXt"
//!   - **Multiple** `CompressedText` "zTXt"
//!   - **Optional** `AnimationControl` "acTL" (APNG)
//!   - **Optional** `FrameControl` "fcTL" (APNG)
//!   - **Optional** `ImageOffset` "oFFs" (*Extension*)
//!   - **Optional** `PixelCalibration` "pCAL" (*Extension*)
//!   - **Optional** `SubjectPhysical` "sCAL" (*Extension*)
//!   - **Multiple** `GifGraphicControlExt` "gIFg" (*Extension*)
//!   - **Multiple** `GifApplicationExt` "gIFx" (*Extension*)
//! - **Optional** `Palette` "PLTE"
//! - In any order:
//!   - **Optional** `Background` "bKGD"
//!   - **Optional** `PaletteHistogram` "hIST"
//!   - **Optional** `Transparency` "tRNS"
//!   - **Optional** `Physical` "pHYs" (If didn't appear before PLTE)
//!   - **Multiple** `SuggestedPalette` "sPLT"
//!   - **Optional** `Time` "tIME" (If didn't appear earlier)
//!   - **Multiple** `InternationalText` "iTXt"
//!   - **Multiple** `Text` "tEXt"
//!   - **Multiple** `CompressedText` "zTXt"
//!   - **Optional** `AnimationControl` "acTL" (APNG, If didn't appear earlier)
//!   - **Optional** `FrameControl` "fcTL" (APNG, If didn't appear earlier)
//!   - **Optional** `ImageOffset` "oFFs" (*Extension*, If didn't appear
//!     earlier)
//!   - **Optional** `PixelCalibration` "pCAL" (*Extension*, If didn't appear
//!     earlier)
//!   - **Optional** `SubjectPhysical` "sCAL" (*Extension*, If didn't appear
//!     earlier)
//!   - **Multiple** `GifGraphicControlExt` "gIFg" (*Extension*)
//!   - **Multiple** `GifApplicationExt` "gIFx" (*Extension*)
//! - **Multiple** `ImageData` "IDAT"
//! - In any order:
//!   - **Optional** `Time` "tIME" (If didn't appear earlier)
//!   - **Multiple** `InternationalText` "iTXt"
//!   - **Multiple** `Text` "tEXt"
//!   - **Multiple** `CompressedText` "zTXt"
//!   - **Multiple** `FrameControl` "fcTL" (APNG)
//!   - **Multiple** `FrameData` "fdAT" (APNG, must be somewhere after "fcTL")
//!   - **Multiple** `GifGraphicControlExt` "gIFg" (*Extension*)
//!   - **Multiple** `GifApplicationExt` "gIFx" (*Extension*)
//! - **Required** `ImageEnd` "IEND"

use crate::{
    decode::{Error as DecoderError, Result as DecoderResult},
    encode::{Error as EncoderError, Result as EncoderResult},
};

mod bkgd;
mod idat;
mod iend;
mod ihdr;
mod itxt;
mod phys;
mod plte;
mod text;
mod time;
mod trns;
mod unknown;
mod ztxt;

pub use self::{
    // Optional
    bkgd::Background,
    // Required
    idat::ImageData,
    // Required
    iend::ImageEnd,
    // Required
    ihdr::{ColorType, ImageHeader},
    // Optional
    itxt::InternationalText,
    // Optional
    phys::Physical,
    // Required
    plte::Palette,
    // Optional
    text::Text,
    // Optional
    time::Time,
    // Optional
    trns::Transparency,
    // Optional
    unknown::Unknown,
    // Optional
    ztxt::CompressedText,
};

/// A chunk within a PNG file.
#[derive(Debug)]
pub enum Chunk {
    /// Required: Image Header
    ImageHeader(ImageHeader),
    /// Required: Image Data
    ImageData(ImageData),
    /// Required: Image End
    ImageEnd(ImageEnd),

    /// Maybe Required: Palette chunk.
    Palette(Palette),

    /// Optional: Background color chunk.
    Background(Background),
    /// Optional: International text chunk.
    InternationalText(InternationalText),
    /// Optional: Physical dimensions chunk
    Physical(Physical),
    /// Optional: Non-International text chunk.
    Text(Text),
    /// Optional: Time chunk.
    Time(Time),
    /// Optional: Alpha palette chunk.
    Transparency(Transparency),
    /// Optional: Z text chunk.
    CompressedText(CompressedText),
    /// Unknown chunk
    Unknown(Unknown),
}

impl Chunk {
    pub(super) fn is_idat(&self) -> bool {
        matches!(self, Chunk::ImageData(_))
    }

    pub(super) fn is_iend(&self) -> bool {
        matches!(self, Chunk::ImageEnd(_))
    }
}