Skip to main content

hayro_syntax/filter/
mod.rs

1//! Results from decoding filtered data streams.
2
3mod ascii_85;
4pub(crate) mod ascii_hex;
5#[cfg(feature = "images")]
6mod ccitt;
7#[cfg(feature = "images")]
8mod dct;
9#[cfg(feature = "images")]
10mod jbig2;
11#[cfg(feature = "images")]
12mod jpx;
13mod lzw_flate;
14mod run_length;
15
16use crate::object::Dict;
17use crate::object::Name;
18use crate::object::dict::keys::*;
19use crate::object::stream::{DecodeFailure, FilterResult, ImageDecodeParams};
20use core::ops::Deref;
21
22/// A data filter.
23#[derive(Debug, Copy, Clone, PartialEq, Eq)]
24pub enum Filter {
25    /// ASCII hexadecimal encoding.
26    AsciiHexDecode,
27    /// ASCII base-85 encoding.
28    Ascii85Decode,
29    /// Lempel-Ziv-Welch (LZW) compression.
30    LzwDecode,
31    /// DEFLATE compression (zlib/gzip).
32    FlateDecode,
33    /// Run-length encoding compression.
34    RunLengthDecode,
35    /// CCITT Group 3 or Group 4 fax compression.
36    CcittFaxDecode,
37    /// JBIG2 compression for bi-level images.
38    Jbig2Decode,
39    /// JPEG (DCT) compression.
40    DctDecode,
41    /// JPEG 2000 compression.
42    JpxDecode,
43    /// Encryption filter.
44    Crypt,
45}
46
47impl Filter {
48    fn debug_name(&self) -> &'static str {
49        match self {
50            Self::AsciiHexDecode => "ascii_hex",
51            Self::Ascii85Decode => "ascii_85",
52            Self::LzwDecode => "lzw",
53            Self::FlateDecode => "flate",
54            Self::RunLengthDecode => "run-length",
55            Self::CcittFaxDecode => "ccit_fax",
56            Self::Jbig2Decode => "jbig2",
57            Self::DctDecode => "dct",
58            Self::JpxDecode => "jpx",
59            Self::Crypt => "crypt",
60        }
61    }
62
63    pub(crate) fn from_name(name: Name<'_>) -> Option<Self> {
64        match name.deref() {
65            ASCII_HEX_DECODE | ASCII_HEX_DECODE_ABBREVIATION => Some(Self::AsciiHexDecode),
66            ASCII85_DECODE | ASCII85_DECODE_ABBREVIATION => Some(Self::Ascii85Decode),
67            LZW_DECODE | LZW_DECODE_ABBREVIATION => Some(Self::LzwDecode),
68            FLATE_DECODE | FLATE_DECODE_ABBREVIATION => Some(Self::FlateDecode),
69            RUN_LENGTH_DECODE | RUN_LENGTH_DECODE_ABBREVIATION => Some(Self::RunLengthDecode),
70            CCITTFAX_DECODE | CCITTFAX_DECODE_ABBREVIATION => Some(Self::CcittFaxDecode),
71            JBIG2_DECODE => Some(Self::Jbig2Decode),
72            DCT_DECODE | DCT_DECODE_ABBREVIATION => Some(Self::DctDecode),
73            JPX_DECODE => Some(Self::JpxDecode),
74            CRYPT => Some(Self::Crypt),
75            _ => {
76                warn!("unknown filter: {}", name.as_str());
77
78                None
79            }
80        }
81    }
82
83    pub(crate) fn apply(
84        &self,
85        data: &[u8],
86        params: &Dict<'_>,
87        #[cfg_attr(not(feature = "images"), allow(unused))] image_params: &ImageDecodeParams,
88    ) -> Result<FilterResult<'static>, DecodeFailure> {
89        let res = match self {
90            Self::AsciiHexDecode => ascii_hex::decode(data)
91                .map(FilterResult::from_data)
92                .ok_or(DecodeFailure::StreamDecode),
93            Self::Ascii85Decode => ascii_85::decode(data)
94                .map(FilterResult::from_data)
95                .ok_or(DecodeFailure::StreamDecode),
96            Self::RunLengthDecode => run_length::decode(data)
97                .map(FilterResult::from_data)
98                .ok_or(DecodeFailure::StreamDecode),
99            Self::LzwDecode => lzw_flate::lzw::decode(data, params)
100                .map(FilterResult::from_data)
101                .ok_or(DecodeFailure::StreamDecode),
102            Self::FlateDecode => lzw_flate::flate::decode(data, params)
103                .map(FilterResult::from_data)
104                .ok_or(DecodeFailure::StreamDecode),
105            #[cfg(feature = "images")]
106            Self::DctDecode => {
107                dct::decode(data, params, image_params).ok_or(DecodeFailure::ImageDecode)
108            }
109            #[cfg(feature = "images")]
110            Self::CcittFaxDecode => {
111                ccitt::decode(data, params, image_params).ok_or(DecodeFailure::ImageDecode)
112            }
113            #[cfg(feature = "images")]
114            Self::Jbig2Decode => {
115                jbig2::decode(data, params, image_params).ok_or(DecodeFailure::ImageDecode)
116            }
117            #[cfg(feature = "images")]
118            Self::JpxDecode => jpx::decode(data, image_params).ok_or(DecodeFailure::ImageDecode),
119            #[cfg(not(feature = "images"))]
120            Self::DctDecode | Self::CcittFaxDecode | Self::Jbig2Decode | Self::JpxDecode => {
121                warn!("image decoding is not supported (enable the `images` feature)");
122                Err(DecodeFailure::ImageDecode)
123            }
124            _ => Err(DecodeFailure::StreamDecode),
125        };
126
127        if res.is_err() {
128            warn!("failed to apply filter {}", self.debug_name());
129        }
130
131        res
132    }
133}