hayro_syntax/filter/
mod.rs

1//! Decoding data streams.
2
3mod ascii_85;
4mod ascii_hex;
5mod ccitt;
6mod dct;
7mod jbig2;
8mod jpx;
9mod lzw_flate;
10mod run_length;
11
12use crate::object::dict::Dict;
13use crate::object::dict::keys::*;
14use crate::object::name::Name;
15use crate::util::OptionLog;
16use log::warn;
17
18/// A filter.
19#[derive(Debug, Copy, Clone)]
20pub enum Filter {
21    /// The ASCII-hex filter.
22    AsciiHexDecode,
23    /// The ASCII85 filter.
24    Ascii85Decode,
25    /// The LZW filter.
26    LzwDecode,
27    /// The flate (zlib/deflate) filter.
28    FlateDecode,
29    /// The run-length filter.
30    RunLengthDecode,
31    /// The CCITT Fax filter.
32    CcittFaxDecode,
33    /// The JBIG2 filter.
34    Jbig2Decode,
35    /// The DCT (JPEG) filter.
36    DctDecode,
37    /// The JPX (JPEG 2000) filter.
38    JpxDecode,
39    /// The crypt filter.
40    Crypt,
41}
42
43/// An image color space.
44pub enum ImageColorSpace {
45    /// Grayscale color space.
46    Gray,
47    /// RGB color space.
48    Rgb,
49    /// CMYK color space.
50    Cmyk,
51}
52
53/// The result of the filter.
54pub struct FilterResult {
55    /// The decoded data.
56    pub data: Vec<u8>,
57    /// The color space of the image (will only be set for JPX streams).
58    pub color_space: Option<ImageColorSpace>,
59    /// The bits per component of the image (will only be set for JPX streams).
60    pub bits_per_component: Option<u8>,
61}
62
63impl FilterResult {
64    fn from_data(data: Vec<u8>) -> Self {
65        Self {
66            data,
67            color_space: None,
68            bits_per_component: None,
69        }
70    }
71}
72
73impl Filter {
74    fn debug_name(&self) -> &'static str {
75        match self {
76            Filter::AsciiHexDecode => "ascii_hex",
77            Filter::Ascii85Decode => "ascii_85",
78            Filter::LzwDecode => "lzw",
79            Filter::FlateDecode => "flate",
80            Filter::RunLengthDecode => "run-length",
81            Filter::CcittFaxDecode => "ccit_fax",
82            Filter::Jbig2Decode => "jbig2",
83            Filter::DctDecode => "dct",
84            Filter::JpxDecode => "jpx",
85            Filter::Crypt => "crypt",
86        }
87    }
88
89    pub(crate) fn from_name(name: &Name) -> Option<Self> {
90        match *name {
91            ASCII_HEX_DECODE | ASCII_HEX_DECODE_ABBREVIATION => Some(Filter::AsciiHexDecode),
92            ASCII85_DECODE | ASCII85_DECODE_ABBREVIATION => Some(Filter::Ascii85Decode),
93            LZW_DECODE | LZW_DECODE_ABBREVIATION => Some(Filter::LzwDecode),
94            FLATE_DECODE | FLATE_DECODE_ABBREVIATION => Some(Filter::FlateDecode),
95            RUN_LENGTH_DECODE | RUN_LENGTH_DECODE_ABBREVIATION => Some(Filter::RunLengthDecode),
96            CCITTFAX_DECODE | CCITTFAX_DECODE_ABBREVIATION => Some(Filter::CcittFaxDecode),
97            JBIG2_DECODE => Some(Filter::Jbig2Decode),
98            DCT_DECODE | DCT_DECODE_ABBREVIATION => Some(Filter::DctDecode),
99            JPX_DECODE => Some(Filter::JpxDecode),
100            CRYPT => Some(Filter::Crypt),
101            _ => {
102                warn!("unknown filter: {}", name.as_str());
103
104                None
105            }
106        }
107    }
108
109    /// Apply the filter to some data.
110    pub fn apply(&self, data: &[u8], params: Dict) -> Option<FilterResult> {
111        match self {
112            Filter::AsciiHexDecode => ascii_hex::decode(data).map(FilterResult::from_data),
113            Filter::Ascii85Decode => ascii_85::decode(data).map(FilterResult::from_data),
114            Filter::RunLengthDecode => run_length::decode(data).map(FilterResult::from_data),
115            Filter::LzwDecode => lzw_flate::lzw::decode(data, params).map(FilterResult::from_data),
116            Filter::DctDecode => dct::decode(data, params).map(FilterResult::from_data),
117            Filter::FlateDecode => {
118                lzw_flate::flate::decode(data, params).map(FilterResult::from_data)
119            }
120            Filter::CcittFaxDecode => ccitt::decode(data, params).map(FilterResult::from_data),
121            Filter::Jbig2Decode => Some(FilterResult::from_data(jbig2::decode(data, params)?)),
122            Filter::JpxDecode => jpx::decode(data),
123            _ => None,
124        }
125        .error_none(&format!("failed to apply filter {}", self.debug_name()))
126    }
127}