numcodecs_jpeg2000/ffi/
codec.rs

1//! Adapted from the MIT/Apache 2.0 licensed <https://github.com/Neopallium/jpeg2k>
2
3use std::ptr::NonNull;
4
5use super::Jpeg2000Error;
6
7pub struct Decoder {
8    codec: NonNull<openjpeg_sys::opj_codec_t>,
9}
10
11impl Drop for Decoder {
12    fn drop(&mut self) {
13        unsafe {
14            openjpeg_sys::opj_destroy_codec(self.codec.as_ptr());
15        }
16    }
17}
18
19impl Decoder {
20    pub fn j2k() -> Result<Self, Jpeg2000Error> {
21        let codec = NonNull::new(unsafe {
22            openjpeg_sys::opj_create_decompress(openjpeg_sys::OPJ_CODEC_FORMAT::OPJ_CODEC_J2K)
23        })
24        .ok_or(Jpeg2000Error::DecoderSetupError)?;
25
26        unsafe {
27            setup_codec_logging(codec);
28        }
29
30        Ok(Self { codec })
31    }
32
33    #[allow(clippy::needless_pass_by_ref_mut)]
34    pub fn as_raw(&mut self) -> *mut openjpeg_sys::opj_codec_t {
35        self.codec.as_ptr()
36    }
37}
38
39pub struct Encoder {
40    codec: NonNull<openjpeg_sys::opj_codec_t>,
41}
42
43impl Drop for Encoder {
44    fn drop(&mut self) {
45        unsafe {
46            openjpeg_sys::opj_destroy_codec(self.codec.as_ptr());
47        }
48    }
49}
50
51impl Encoder {
52    pub fn j2k() -> Result<Self, Jpeg2000Error> {
53        let codec = NonNull::new(unsafe {
54            openjpeg_sys::opj_create_compress(openjpeg_sys::OPJ_CODEC_FORMAT::OPJ_CODEC_J2K)
55        })
56        .ok_or(Jpeg2000Error::EncoderSetupError)?;
57
58        unsafe {
59            setup_codec_logging(codec);
60        }
61
62        Ok(Self { codec })
63    }
64
65    #[allow(clippy::needless_pass_by_ref_mut)]
66    pub fn as_raw(&mut self) -> *mut openjpeg_sys::opj_codec_t {
67        self.codec.as_ptr()
68    }
69}
70
71unsafe fn setup_codec_logging(codec: NonNull<openjpeg_sys::opj_codec_t>) {
72    extern "C" fn log_info(msg: *const std::ffi::c_char, _data: *mut std::ffi::c_void) {
73        unsafe { log(msg, log::Level::Info) }
74    }
75
76    extern "C" fn log_warning(msg: *const std::ffi::c_char, _data: *mut std::ffi::c_void) {
77        unsafe { log(msg, log::Level::Warn) }
78    }
79
80    extern "C" fn log_error(msg: *const std::ffi::c_char, _data: *mut std::ffi::c_void) {
81        unsafe { log(msg, log::Level::Error) }
82    }
83
84    unsafe fn log(msg: *const std::ffi::c_char, level: log::Level) {
85        let msg = unsafe { std::ffi::CStr::from_ptr(msg) }.to_string_lossy();
86
87        log::log!(level, "{msg}");
88    }
89
90    unsafe {
91        openjpeg_sys::opj_set_info_handler(codec.as_ptr(), Some(log_info), std::ptr::null_mut());
92    }
93    unsafe {
94        openjpeg_sys::opj_set_warning_handler(
95            codec.as_ptr(),
96            Some(log_warning),
97            std::ptr::null_mut(),
98        );
99    }
100    unsafe {
101        openjpeg_sys::opj_set_error_handler(codec.as_ptr(), Some(log_error), std::ptr::null_mut());
102    }
103}