numcodecs_jpeg2000/ffi/
image.rs

1//! Adapted from
2//! - the MIT/Apache 2.0 licensed <https://github.com/kardeiz/jp2k>, and
3//! - the MIT/Apache 2.0 licensed <https://github.com/noritada/grib-rs>
4
5use std::ptr::NonNull;
6
7use super::{codec::Decoder, stream::DecodeStream, Jpeg2000Element, Jpeg2000Error};
8
9pub struct Image {
10    image: NonNull<openjpeg_sys::opj_image_t>,
11}
12
13impl Drop for Image {
14    fn drop(&mut self) {
15        unsafe {
16            openjpeg_sys::opj_image_destroy(self.image.as_ptr());
17        }
18    }
19}
20
21impl Image {
22    pub fn from_header(
23        stream: &mut DecodeStream,
24        decoder: &mut Decoder,
25    ) -> Result<Self, Jpeg2000Error> {
26        let mut image = std::ptr::null_mut();
27
28        if unsafe { openjpeg_sys::opj_read_header(stream.as_raw(), decoder.as_raw(), &mut image) }
29            != 1
30        {
31            return Err(Jpeg2000Error::InvalidMainHeader);
32        }
33
34        let image = NonNull::new(image).ok_or(Jpeg2000Error::InvalidMainHeader)?;
35
36        Ok(Self { image })
37    }
38
39    pub fn from_gray_data<T: Jpeg2000Element>(
40        data: impl IntoIterator<Item = T>,
41        width: u32,
42        height: u32,
43    ) -> Result<Self, Jpeg2000Error> {
44        let mut image_params = openjpeg_sys::opj_image_cmptparm_t {
45            dx: 1,
46            dy: 1,
47            w: width,
48            h: height,
49            x0: 0,
50            y0: 0,
51            prec: T::NBITS,
52            bpp: T::NBITS,
53            sgnd: u32::from(T::SIGNED),
54        };
55
56        let image = NonNull::new(unsafe {
57            openjpeg_sys::opj_image_create(
58                1,
59                &mut image_params,
60                openjpeg_sys::OPJ_COLOR_SPACE::OPJ_CLRSPC_GRAY,
61            )
62        })
63        .ok_or(Jpeg2000Error::ImageCreateError)?;
64
65        unsafe {
66            (*image.as_ptr()).x0 = 0;
67            (*image.as_ptr()).y0 = 0;
68            (*image.as_ptr()).x1 = width;
69            (*image.as_ptr()).y1 = height;
70        }
71
72        unsafe {
73            let mut idata = (*(*image.as_ptr()).comps).data;
74            for d in data {
75                *idata = d.into_i32().map_err(|_| Jpeg2000Error::DataOutOfRange)?;
76                idata = idata.add(1);
77            }
78        }
79
80        Ok(Self { image })
81    }
82
83    #[allow(clippy::needless_pass_by_ref_mut)]
84    pub fn as_raw(&mut self) -> *mut openjpeg_sys::opj_image_t {
85        self.image.as_ptr()
86    }
87
88    pub fn width(&self) -> u32 {
89        unsafe { (*self.image.as_ptr()).x1 - (*self.image.as_ptr()).x0 }
90    }
91
92    pub fn height(&self) -> u32 {
93        unsafe { (*self.image.as_ptr()).y1 - (*self.image.as_ptr()).y0 }
94    }
95
96    pub fn components(&self) -> &[openjpeg_sys::opj_image_comp_t] {
97        let comps_len = unsafe { (*self.image.as_ptr()).numcomps };
98        unsafe { std::slice::from_raw_parts((*self.image.as_ptr()).comps, comps_len as usize) }
99    }
100}