nipdf_jbig2dec/
lib.rs

1use jbig2dec_sys::*;
2use std::{
3    cell::RefCell,
4    fmt,
5    fs::File,
6    io::{BufReader, Read},
7    ops::{Index, IndexMut},
8    os::raw::{c_char, c_void},
9    path::Path,
10    ptr, slice,
11};
12
13#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
14pub enum OpenFlag {
15    File,
16    Embedded,
17}
18
19impl Default for OpenFlag {
20    fn default() -> Self {
21        OpenFlag::File
22    }
23}
24mod errors;
25
26use crate::errors::Error;
27
28thread_local! {
29    static LAST_ERROR_MSG: RefCell<Option<String>> = RefCell::new(None);
30}
31
32unsafe extern "C" fn jbig2_error_callback(
33    _data: *mut c_void,
34    msg: *const c_char,
35    _severity: Jbig2Severity,
36    _seg_idx: u32,
37) {
38    use std::ffi::CStr;
39
40    if msg.is_null() {
41        return;
42    }
43    let cstr = CStr::from_ptr(msg);
44    let msg_str = cstr.to_string_lossy().into_owned();
45    LAST_ERROR_MSG.with(|e| {
46        *e.borrow_mut() = Some(msg_str);
47    });
48}
49
50/// This struct represents the document structure
51#[derive(Debug, Clone)]
52pub struct Document {
53    images: Vec<Image>,
54}
55
56impl Document {
57    /// Open a document from a path
58    pub fn open<P: AsRef<Path>>(path: P, flag: OpenFlag) -> Result<Self, Error> {
59        let mut reader = BufReader::new(File::open(path).unwrap());
60        Self::from_reader(&mut reader, None, flag)
61    }
62
63    /// Open a document from a `Read`
64    pub fn from_reader<R: Read>(
65        reader: &mut R,
66        global_stream: Option<&mut R>,
67        flag: OpenFlag,
68    ) -> Result<Self, Error> {
69        let options = match flag {
70            OpenFlag::File => Jbig2Options::JBIG2_OPTIONS_DEFAULT,
71            OpenFlag::Embedded => Jbig2Options::JBIG2_OPTIONS_EMBEDDED,
72        };
73
74        let ctx = unsafe {
75            jbig2_ctx_new(
76                ptr::null_mut(),
77                options,
78                ptr::null_mut(),
79                Some(jbig2_error_callback),
80                ptr::null_mut(),
81            )
82        };
83        if ctx.is_null() {
84            let msg = LAST_ERROR_MSG.with(|e| {
85                if let Some(err) = e.borrow_mut().take() {
86                    err
87                } else {
88                    String::new()
89                }
90            });
91            return Err(Error::CreateContextFailed(msg));
92        }
93
94        if let Some(global_stream) = global_stream {
95            let mut global_content = Vec::new();
96            global_stream.read_to_end(&mut global_content).unwrap();
97            unsafe {
98                jbig2_data_in(ctx, global_content.as_mut_ptr(), global_content.len());
99            }
100        }
101
102        let mut content = Vec::new();
103        reader.read_to_end(&mut content).unwrap();
104        unsafe {
105            jbig2_data_in(ctx, content.as_mut_ptr(), content.len());
106        }
107
108        let code = unsafe { jbig2_complete_page(ctx) };
109        if code != 0 {
110            let msg = LAST_ERROR_MSG.with(|e| {
111                if let Some(err) = e.borrow_mut().take() {
112                    err
113                } else {
114                    String::new()
115                }
116            });
117            return Err(Error::IncompletePage(msg));
118        }
119
120        let mut images = Vec::new();
121        loop {
122            let page = unsafe { jbig2_page_out(ctx) };
123            if page.is_null() {
124                break;
125            }
126            let image = unsafe { Image::from_raw(page) };
127            images.push(image);
128            unsafe { jbig2_release_page(ctx, page) };
129        }
130
131        unsafe {
132            jbig2_ctx_free(ctx);
133        }
134
135        Ok(Self { images })
136    }
137
138    /// Get images
139    pub fn images(&self) -> &[Image] {
140        &self.images
141    }
142
143    /// Number of images
144    pub fn len(&self) -> usize {
145        self.images.len()
146    }
147
148    /// Consumer `self` and return a `Vec<Image>`
149    pub fn into_inner(self) -> Vec<Image> {
150        self.images
151    }
152}
153
154impl IntoIterator for Document {
155    type IntoIter = ::std::vec::IntoIter<Self::Item>;
156    type Item = Image;
157
158    fn into_iter(self) -> Self::IntoIter {
159        self.images.into_iter()
160    }
161}
162
163impl Index<usize> for Document {
164    type Output = Image;
165
166    fn index(&self, index: usize) -> &Self::Output {
167        self.images.index(index)
168    }
169}
170
171impl IndexMut<usize> for Document {
172    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
173        self.images.index_mut(index)
174    }
175}
176
177/// This struct represents a image.
178#[derive(Clone, PartialEq)]
179pub struct Image {
180    width: u32,
181    height: u32,
182    stride: u32,
183    data: Vec<u8>,
184}
185
186impl Image {
187    unsafe fn from_raw(image: *mut Jbig2Image) -> Self {
188        let image = *image;
189        let width = image.width;
190        let height = image.height;
191        let stride = image.stride;
192        let length = (height * stride) as usize;
193        let data = slice::from_raw_parts(image.data, length).to_vec();
194        Self {
195            width,
196            height,
197            stride,
198            data,
199        }
200    }
201
202    /// Get image width
203    pub fn width(&self) -> u32 {
204        self.width
205    }
206
207    /// Get image height
208    pub fn height(&self) -> u32 {
209        self.height
210    }
211
212    /// Get image stride
213    pub fn stride(&self) -> u32 {
214        self.stride
215    }
216
217    /// Get image data as bytes
218    pub fn data(&self) -> &[u8] {
219        &self.data
220    }
221
222    /// Get image data as mutable bytes
223    pub fn data_mut(&mut self) -> &mut [u8] {
224        &mut self.data
225    }
226
227    #[cfg(feature = "png")]
228    pub fn to_png(&self) -> Result<Vec<u8>, png::EncodingError> {
229        // png natively treats 0 as black, needs to invert it.
230        let mut inverted = Vec::with_capacity(self.data.len());
231        for pixel in &self.data {
232            inverted.push(255 - *pixel);
233        }
234        let mut output = Vec::new();
235        {
236            let mut encoder = png::Encoder::new(&mut output, self.width, self.height);
237            encoder.set_color(png::ColorType::Grayscale);
238            encoder.set_depth(png::BitDepth::One);
239            let mut writer = encoder.write_header()?;
240            writer.write_image_data(&inverted)?;
241        }
242        Ok(output)
243    }
244}
245
246impl fmt::Debug for Image {
247    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
248        fmt.debug_struct("Image")
249            .field("width", &self.width)
250            .field("height", &self.height)
251            .field("stride", &self.stride)
252            .finish()
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    use super::*;
259    use image::GenericImageView;
260
261    #[test]
262    fn test_document_open() {
263        let doc = Document::open("annex-h.jbig2", OpenFlag::File).expect("open document failed");
264        for image in doc.into_iter() {
265            let data = image.to_png().unwrap();
266            let dyn_image = image::load_from_memory(&data).expect("convert to DynamicImage failed");
267            assert_eq!(dyn_image.dimensions(), (image.width(), image.height()));
268        }
269    }
270
271    #[test]
272    fn test_document_open_embedded() {
273        let doc = Document::open("embded.jbig2", super::OpenFlag::Embedded)
274            .expect("open document failed");
275        assert_eq!(1, doc.len());
276    }
277}