Skip to main content

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