1pub mod err {
48 #[derive(Debug)]
49 pub enum Error {
50 NulError(std::ffi::NulError),
51 Io(std::io::Error),
52 Boxed(Box<dyn std::error::Error + Send + Sync>),
53 }
54
55 impl Error {
56 pub fn boxed<E: Into<Box<dyn std::error::Error + 'static + Send + Sync>>>(e: E) -> Self {
57 Error::Boxed(e.into())
58 }
59 }
60
61 impl std::fmt::Display for Error {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 use Error::*;
64 match self {
65 NulError(ref e) => {
66 write!(f, "{}", e)?;
67 }
68 Io(ref e) => {
69 write!(f, "{}", e)?;
70 }
71 Boxed(ref e) => {
72 write!(f, "{}", e)?;
73 }
74 }
75
76 Ok(())
77 }
78 }
79
80 impl From<std::ffi::NulError> for Error {
81 fn from(t: std::ffi::NulError) -> Self {
82 Error::NulError(t)
83 }
84 }
85
86 impl std::error::Error for Error {}
87
88 pub type Result<T> = std::result::Result<T, Error>;
89}
90
91#[cfg(feature = "docs-rs")]
92#[path = "ffi.ref.rs"]
93mod ffi;
94
95#[cfg(not(feature = "docs-rs"))]
96mod ffi;
97
98use std::ffi::CString;
99use std::os::raw::c_void;
100use std::ptr::{self, NonNull};
101
102pub use ffi::{CODEC_FORMAT, COLOR_SPACE};
103
104struct InnerDecodeParams(ffi::opj_dparameters);
105
106impl Default for InnerDecodeParams {
107 fn default() -> Self {
108 let mut new = unsafe { std::mem::zeroed::<ffi::opj_dparameters>() };
109 unsafe {
110 ffi::opj_set_default_decoder_parameters(&mut new as *mut _);
111 }
112 InnerDecodeParams(new)
113 }
114}
115
116#[derive(Debug, Clone, Default)]
117struct DecodingArea {
118 x0: i32,
119 y0: i32,
120 x1: i32,
121 y1: i32,
122}
123
124#[derive(Debug, Clone, Default)]
126pub struct DecodeParams {
127 default_color_space: Option<COLOR_SPACE>,
128 reduce_factor: Option<u32>,
129 decoding_area: Option<DecodingArea>,
130 quality_layers: Option<u32>,
131 num_threads: Option<i32>,
132}
133
134impl DecodeParams {
135 pub fn with_default_colorspace(mut self, color_space: COLOR_SPACE) -> Self {
137 self.default_color_space = Some(color_space);
138 self
139 }
140
141 pub fn with_reduce_factor(mut self, reduce_factor: u32) -> Self {
143 self.reduce_factor = Some(reduce_factor);
144 self
145 }
146
147 pub fn with_num_threads(mut self, num: i32) -> Self {
148 self.num_threads = Some(num);
149 self
150 }
151
152 pub fn with_decoding_area(mut self, x0: i32, y0: i32, x1: i32, y1: i32) -> Self {
154 self.decoding_area = Some(DecodingArea { x0, y0, x1, y1 });
155 self
156 }
157
158 pub fn with_quality_layers(mut self, quality_layers: u32) -> Self {
160 self.quality_layers = Some(quality_layers);
161 self
162 }
163
164 fn value_for_discard_level(u: u32, discard_level: u32) -> u32 {
165 let div = 1 << discard_level;
166 let quot = u / div;
167 let rem = u % div;
168 if rem > 0 {
169 quot + 1
170 } else {
171 quot
172 }
173 }
174}
175
176pub struct Stream(*mut ffi::opj_stream_t);
177
178impl Drop for Stream {
179 fn drop(&mut self) {
180 unsafe {
181 ffi::opj_stream_destroy(self.0);
182 }
183 }
184}
185
186impl Stream {
187 pub fn from_file<T: Into<Vec<u8>>>(file_name: T) -> err::Result<Self> {
188 let file_name = CString::new(file_name)?;
189 let ptr = unsafe { ffi::opj_stream_create_default_file_stream(file_name.as_ptr(), 1) };
190 Ok(Stream(ptr))
191 }
192
193 pub fn from_bytes(buf: &[u8]) -> err::Result<Self> {
194 #[derive(Debug)]
195 struct SliceWithOffset<'a> {
196 buf: &'a [u8],
197 offset: usize,
198 }
199
200 unsafe extern "C" fn opj_stream_free_user_data_fn(p_user_data: *mut c_void) {
201 drop(Box::from_raw(p_user_data as *mut SliceWithOffset))
202 }
203
204 unsafe extern "C" fn opj_stream_read_fn(
205 p_buffer: *mut c_void,
206 p_nb_bytes: usize,
207 p_user_data: *mut c_void,
208 ) -> usize {
209 if p_buffer.is_null() {
210 return 0;
211 }
212
213 let user_data = p_user_data as *mut SliceWithOffset;
214
215 let len = (&*user_data).buf.len();
216
217 let offset = (&*user_data).offset;
218
219 let bytes_left = len - offset;
220
221 let bytes_read = std::cmp::min(bytes_left, p_nb_bytes);
222
223 let slice = &(&*user_data).buf[offset..offset + bytes_read];
224
225 std::ptr::copy_nonoverlapping(slice.as_ptr(), p_buffer as *mut u8, bytes_read);
226
227 (*user_data).offset += bytes_read;
228
229 bytes_read
230 }
231
232 let buf_len = buf.len();
233 let user_data = Box::new(SliceWithOffset { buf, offset: 0 });
234
235 let ptr = unsafe {
236 let jp2_stream = ffi::opj_stream_default_create(1);
237 ffi::opj_stream_set_read_function(jp2_stream, Some(opj_stream_read_fn));
238 ffi::opj_stream_set_user_data_length(jp2_stream, buf_len as u64);
239 ffi::opj_stream_set_user_data(
240 jp2_stream,
241 Box::into_raw(user_data) as *mut c_void,
242 Some(opj_stream_free_user_data_fn),
243 );
244 jp2_stream
245 };
246
247 Ok(Stream(ptr))
248 }
249}
250
251pub struct Codec(NonNull<ffi::opj_codec_t>);
252
253impl Drop for Codec {
254 fn drop(&mut self) {
255 unsafe {
256 ffi::opj_destroy_codec(self.0.as_ptr());
257 }
258 }
259}
260
261impl Codec {
262 pub fn jp2() -> Self {
263 Self::create(CODEC_FORMAT::OPJ_CODEC_JP2).expect("Known format `JP2` should not fail")
264 }
265
266 pub fn create(format: CODEC_FORMAT) -> err::Result<Self> {
267 match NonNull::new(unsafe { ffi::opj_create_decompress(format) }) {
268 Some(ptr) => Ok(Codec(ptr)),
269 None => Err(err::Error::boxed("Setting up the decoder failed.")),
270 }
271 }
272}
273
274#[derive(Debug)]
275pub struct Info {
276 pub width: u32,
277 pub height: u32,
278}
279
280impl Info {
281 pub fn build(codec: Codec, stream: Stream) -> err::Result<Self> {
282 let mut params = InnerDecodeParams::default();
283
284 params.0.flags |= ffi::OPJ_DPARAMETERS_DUMP_FLAG;
285
286 if unsafe { ffi::opj_setup_decoder(codec.0.as_ptr(), &mut params.0) } != 1 {
287 return Err(err::Error::boxed("Setting up the decoder failed."));
288 }
289
290 let mut img = Image::new();
291
292 if unsafe { ffi::opj_read_header(stream.0, codec.0.as_ptr(), &mut img.0) } != 1 {
293 return Err(err::Error::boxed("Failed to read header."));
294 }
295
296 Ok(Info { width: img.width(), height: img.height() })
297 }
298}
299
300#[derive(Debug)]
301pub struct Image(pub *mut ffi::opj_image_t);
302
303impl Drop for Image {
304 fn drop(&mut self) {
305 unsafe {
306 ffi::opj_image_destroy(self.0);
307 }
308 }
309}
310
311impl Image {
312 fn new() -> Self {
313 Image(ptr::null_mut())
314 }
315
316 pub fn width(&self) -> u32 {
317 unsafe { (&*self.0).x1 - (&*self.0).x0 }
318 }
319
320 pub fn height(&self) -> u32 {
321 unsafe { (&*self.0).y1 - (&*self.0).y0 }
322 }
323
324 pub fn num_components(&self) -> u32 {
325 unsafe { (*self.0).numcomps }
326 }
327
328 pub fn components(&self) -> &[ffi::opj_image_comp_t] {
329 let comps_len = self.num_components();
330 unsafe { std::slice::from_raw_parts((*self.0).comps, comps_len as usize) }
331 }
332
333 pub fn factor(&self) -> u32 {
334 unsafe { (*(*self.0).comps).factor }
335 }
336
337 pub fn color_space(&self) -> COLOR_SPACE {
338 unsafe { (*self.0).color_space }
339 }
340}
341
342pub struct Component(*mut ffi::opj_image_comp_t);
343
344#[derive(Debug)]
345pub struct ImageBuffer {
346 pub buffer: Vec<u8>,
347 pub width: u32,
348 pub height: u32,
349 pub num_bands: usize,
350}
351
352impl ImageBuffer {
353 pub fn build(codec: Codec, stream: Stream, params: DecodeParams) -> err::Result<Self> {
354 let mut inner_params = InnerDecodeParams::default();
355
356 if let Some(reduce_factor) = params.reduce_factor {
357 inner_params.0.cp_reduce = reduce_factor;
358 }
359
360 if let Some(quality_layers) = params.quality_layers {
361 inner_params.0.cp_layer = quality_layers;
362 }
363
364 if unsafe { ffi::opj_setup_decoder(codec.0.as_ptr(), &mut inner_params.0) } != 1 {
365 return Err(err::Error::boxed("Setting up the decoder failed."));
366 }
367
368 if let Some(num_threads) = params.num_threads {
369 if unsafe { ffi::opj_codec_set_threads(codec.0.as_ptr(), num_threads) } != 1 {
370 return Err(err::Error::boxed("Could not set specified threads."));
371 }
372 }
373
374 let mut img = Image::new();
375
376 if unsafe { ffi::opj_read_header(stream.0, codec.0.as_ptr(), &mut img.0) } != 1 {
377 return Err(err::Error::boxed("Failed to read header."));
378 }
379
380 if let Some(DecodingArea { x0, y0, x1, y1 }) = params.decoding_area {
381 if unsafe { ffi::opj_set_decode_area(codec.0.as_ptr(), img.0, x0, y0, x1, y1) } != 1 {
382 return Err(err::Error::boxed("Setting up the decoding area failed."));
383 }
384 }
385
386 if unsafe { ffi::opj_decode(codec.0.as_ptr(), stream.0, img.0) } != 1 {
387 return Err(err::Error::boxed("Failed to read image."));
388 }
389
390 drop(codec);
395 drop(stream);
396
397 let width = img.width();
398 let height = img.height();
399 let factor = img.factor();
400
401 let width = DecodeParams::value_for_discard_level(width, factor);
402 let height = DecodeParams::value_for_discard_level(height, factor);
403
404 let num_bands;
405
406 let buffer = unsafe {
407 match img.components() {
408 [comp_r] => {
409 num_bands = 1;
410 std::slice::from_raw_parts(comp_r.data, (width * height) as usize)
411 .iter()
412 .map(|x| *x as u8)
413 .collect::<Vec<_>>()
414 }
415
416 [comp_r, comp_g, comp_b] => {
417 let r = std::slice::from_raw_parts(comp_r.data, (width * height) as usize);
418 let g = std::slice::from_raw_parts(comp_g.data, (width * height) as usize);
419 let b = std::slice::from_raw_parts(comp_b.data, (width * height) as usize);
420
421 num_bands = 3;
422
423 let buffer = Vec::with_capacity((width * height * num_bands) as usize);
424
425 r.iter().zip(g.iter()).zip(b.iter()).fold(buffer, |mut acc, ((r, g), b)| {
426 acc.extend_from_slice(&[*r as u8, *g as u8, *b as u8]);
427 acc
428 })
429 }
430 [comp_r, comp_g, comp_b, comp_a] => {
431 let r = std::slice::from_raw_parts(comp_r.data, (width * height) as usize);
432 let g = std::slice::from_raw_parts(comp_g.data, (width * height) as usize);
433 let b = std::slice::from_raw_parts(comp_b.data, (width * height) as usize);
434 let a = std::slice::from_raw_parts(comp_a.data, (width * height) as usize);
435
436 num_bands = 4;
437
438 let buffer = Vec::with_capacity((width * height * num_bands) as usize);
439
440 r.iter().zip(g.iter()).zip(b.iter()).zip(a.iter()).fold(
441 buffer,
442 |mut acc, (((r, g), b), a)| {
443 acc.extend_from_slice(&[*r as u8, *g as u8, *b as u8, *a as u8]);
444 acc
445 },
446 )
447 }
448 _ => {
449 return Err(err::Error::boxed(
450 "Operation not supported for that number of components",
451 ));
452 }
453 }
454 };
455
456 Ok(ImageBuffer { buffer, width, height, num_bands: num_bands as usize })
457 }
458}