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#[derive(Debug, Clone)]
52pub struct Document {
53 images: Vec<Image>,
54}
55
56impl Document {
57 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 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 pub fn images(&self) -> &[Image] {
140 &self.images
141 }
142
143 pub fn len(&self) -> usize {
145 self.images.len()
146 }
147
148 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#[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 pub fn width(&self) -> u32 {
204 self.width
205 }
206
207 pub fn height(&self) -> u32 {
209 self.height
210 }
211
212 pub fn stride(&self) -> u32 {
214 self.stride
215 }
216
217 pub fn data(&self) -> &[u8] {
219 &self.data
220 }
221
222 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 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}