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::{Jpeg2000Element, Jpeg2000Error, codec::Decoder, stream::DecodeStream};
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 {
29            openjpeg_sys::opj_read_header(stream.as_raw(), decoder.as_raw(), &raw mut image)
30        } != 1
31        {
32            return Err(Jpeg2000Error::InvalidMainHeader);
33        }
34
35        let image = NonNull::new(image).ok_or(Jpeg2000Error::InvalidMainHeader)?;
36
37        Ok(Self { image })
38    }
39
40    pub fn from_gray_data<T: Jpeg2000Element>(
41        data: impl IntoIterator<Item = T>,
42        width: u32,
43        height: u32,
44    ) -> Result<Self, Jpeg2000Error> {
45        let mut image_params = openjpeg_sys::opj_image_cmptparm_t {
46            dx: 1,
47            dy: 1,
48            w: width,
49            h: height,
50            x0: 0,
51            y0: 0,
52            prec: T::NBITS,
53            bpp: T::NBITS,
54            sgnd: u32::from(T::SIGNED),
55        };
56
57        let image = NonNull::new(unsafe {
58            openjpeg_sys::opj_image_create(
59                1,
60                &raw mut image_params,
61                openjpeg_sys::OPJ_COLOR_SPACE::OPJ_CLRSPC_GRAY,
62            )
63        })
64        .ok_or(Jpeg2000Error::ImageCreateError)?;
65
66        unsafe {
67            (*image.as_ptr()).x0 = 0;
68            (*image.as_ptr()).y0 = 0;
69            (*image.as_ptr()).x1 = width;
70            (*image.as_ptr()).y1 = height;
71        }
72
73        unsafe {
74            let mut idata = (*(*image.as_ptr()).comps).data;
75            for d in data {
76                *idata = d.into_i32().map_err(|_| Jpeg2000Error::DataOutOfRange)?;
77                idata = idata.add(1);
78            }
79        }
80
81        Ok(Self { image })
82    }
83
84    #[allow(clippy::needless_pass_by_ref_mut)]
85    pub const fn as_raw(&mut self) -> *mut openjpeg_sys::opj_image_t {
86        self.image.as_ptr()
87    }
88
89    pub fn width(&self) -> u32 {
90        unsafe { (*self.image.as_ptr()).x1 - (*self.image.as_ptr()).x0 }
91    }
92
93    pub fn height(&self) -> u32 {
94        unsafe { (*self.image.as_ptr()).y1 - (*self.image.as_ptr()).y0 }
95    }
96
97    pub fn components(&self) -> &[openjpeg_sys::opj_image_comp_t] {
98        let comps_len = unsafe { (*self.image.as_ptr()).numcomps };
99        unsafe { std::slice::from_raw_parts((*self.image.as_ptr()).comps, comps_len as usize) }
100    }
101}