jpeg2k/
j2k_image.rs

1use std::ptr;
2
3#[cfg(feature = "file-io")]
4use std::path::Path;
5
6use super::*;
7
8/// A Jpeg2000 Image Component.
9pub struct ImageComponent(pub(crate) sys::opj_image_comp_t);
10
11impl std::fmt::Debug for ImageComponent {
12  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13    f.debug_struct("ImageComponent")
14      .field("dx", &self.0.dx)
15      .field("dy", &self.0.dy)
16      .field("w", &self.0.w)
17      .field("h", &self.0.h)
18      .field("x0", &self.0.x0)
19      .field("y0", &self.0.y0)
20      .field("prec", &self.0.prec)
21      .field("bpp", &self.0.bpp)
22      .field("sgnd", &self.0.sgnd)
23      .field("resno_decoded", &self.0.resno_decoded)
24      .field("factor", &self.0.factor)
25      .field("data", &self.0.data)
26      .field("alpha", &self.0.alpha)
27      .finish()
28  }
29}
30
31impl ImageComponent {
32  /// Component width.
33  pub fn width(&self) -> u32 {
34    self.0.w
35  }
36
37  /// Component height.
38  pub fn height(&self) -> u32 {
39    self.0.h
40  }
41
42  /// Component precision.
43  pub fn precision(&self) -> u32 {
44    self.0.prec
45  }
46
47  /// Image depth in bits.
48  pub fn bpp(&self) -> u32 {
49    self.0.bpp
50  }
51
52  /// Is component an alpha channel.
53  pub fn is_alpha(&self) -> bool {
54    self.0.alpha == 1
55  }
56
57  /// Is component data signed.
58  pub fn is_signed(&self) -> bool {
59    self.0.sgnd == 1
60  }
61
62  /// Component data.
63  pub fn data(&self) -> &[i32] {
64    let len = (self.0.w * self.0.h) as usize;
65    unsafe { std::slice::from_raw_parts(self.0.data, len) }
66  }
67
68  /// Component data scaled to unsigned 8bit.
69  pub fn data_u8(&self) -> Box<dyn Iterator<Item = u8>> {
70    let len = (self.0.w * self.0.h) as usize;
71    if self.is_signed() {
72      let data = unsafe { std::slice::from_raw_parts(self.0.data, len) };
73      let old_max = (1 << (self.precision() - 1)) as i64;
74      const NEW_MAX: i64 = 1 << (8 - 1);
75      Box::new(
76        data
77          .iter()
78          .map(move |p| ((((*p as i64) * NEW_MAX) / old_max) + NEW_MAX) as u8),
79      )
80    } else {
81      let data = unsafe { std::slice::from_raw_parts(self.0.data as *const u32, len) };
82      let old_max = ((1 << self.precision()) - 1) as u64;
83      const NEW_MAX: u64 = (1 << 8) - 1;
84      Box::new(
85        data
86          .iter()
87          .map(move |p| (((*p as u64) * NEW_MAX) / old_max) as u8),
88      )
89    }
90  }
91
92  /// Component data scaled to unsigned 16bit.
93  pub fn data_u16(&self) -> Box<dyn Iterator<Item = u16>> {
94    let len = (self.0.w * self.0.h) as usize;
95    if self.is_signed() {
96      let data = unsafe { std::slice::from_raw_parts(self.0.data, len) };
97      let old_max = (1 << (self.precision() - 1)) as i64;
98      const NEW_MAX: i64 = 1 << (16 - 1);
99      Box::new(
100        data
101          .iter()
102          .map(move |p| ((((*p as i64) * NEW_MAX) / old_max) + NEW_MAX) as u16),
103      )
104    } else {
105      let data = unsafe { std::slice::from_raw_parts(self.0.data as *const u32, len) };
106      let old_max = ((1 << self.precision()) - 1) as u64;
107      const NEW_MAX: u64 = (1 << 16) - 1;
108      Box::new(
109        data
110          .iter()
111          .map(move |p| (((*p as u64) * NEW_MAX) / old_max) as u16),
112      )
113    }
114  }
115}
116
117/// Image Data.
118#[derive(Debug, Clone, Copy)]
119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
120pub enum ImageFormat {
121  L8,
122  La8,
123  Rgb8,
124  Rgba8,
125  L16,
126  La16,
127  Rgb16,
128  Rgba16,
129}
130
131/// Image Pixel Data.
132#[derive(Debug, Clone)]
133#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
134pub enum ImagePixelData {
135  L8(Vec<u8>),
136  La8(Vec<u8>),
137  Rgb8(Vec<u8>),
138  Rgba8(Vec<u8>),
139  L16(Vec<u16>),
140  La16(Vec<u16>),
141  Rgb16(Vec<u16>),
142  Rgba16(Vec<u16>),
143}
144
145/// Image Data.
146#[derive(Debug, Clone)]
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148pub struct ImageData {
149  pub width: u32,
150  pub height: u32,
151  pub format: ImageFormat,
152  pub data: ImagePixelData,
153}
154
155/// A Jpeg2000 Image.
156pub struct Image {
157  img: ptr::NonNull<sys::opj_image_t>,
158}
159
160impl Drop for Image {
161  fn drop(&mut self) {
162    #[cfg(feature = "openjpeg-sys")]
163    unsafe {
164      sys::opj_image_destroy(self.img.as_ptr());
165    }
166    #[cfg(feature = "openjp2")]
167    sys::opj_image_destroy(self.img.as_ptr());
168  }
169}
170
171impl std::fmt::Debug for Image {
172  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173    let img = unsafe { &*self.as_ptr() };
174    f.debug_struct("Image")
175      .field("x_offset", &self.x_offset())
176      .field("y_offset", &self.y_offset())
177      .field("width", &self.orig_width())
178      .field("height", &self.orig_height())
179      .field("color_space", &self.color_space())
180      .field("has_icc_profile", &self.has_icc_profile())
181      .field("numcomps", &img.numcomps)
182      .field("comps", &self.components())
183      .finish()
184  }
185}
186
187impl Image {
188  pub(crate) fn new(ptr: *mut sys::opj_image_t) -> Result<Self> {
189    let img =
190      ptr::NonNull::new(ptr).ok_or_else(|| Error::NullPointerError("Image: NULL `opj_image_t`"))?;
191    Ok(Self { img })
192  }
193
194  /// Load a Jpeg 2000 image from bytes.  It will detect the J2K format.
195  pub fn from_bytes(buf: &[u8]) -> Result<Self> {
196    let stream = Stream::from_bytes(buf)?;
197    Self::from_stream(stream, Default::default())
198  }
199
200  /// Load a Jpeg 2000 image from file.  It will detect the J2K format.
201  #[cfg(feature = "file-io")]
202  pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
203    let stream = Stream::from_file(path)?;
204    Self::from_stream(stream, Default::default())
205  }
206
207  /// Load a Jpeg 2000 image from bytes.  It will detect the J2K format.
208  pub fn from_bytes_with(buf: &[u8], params: DecodeParameters) -> Result<Self> {
209    let stream = Stream::from_bytes(buf)?;
210    Self::from_stream(stream, params)
211  }
212
213  /// Load a Jpeg 2000 image from file.  It will detect the J2K format.
214  #[cfg(feature = "file-io")]
215  pub fn from_file_with<P: AsRef<Path>>(path: P, params: DecodeParameters) -> Result<Self> {
216    let stream = Stream::from_file(path)?;
217    Self::from_stream(stream, params)
218  }
219
220  /// Save image to Jpeg 2000 file.  It will detect the J2K format.
221  #[cfg(feature = "file-io")]
222  pub fn save_as_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
223    let stream = Stream::to_file(path)?;
224    self.to_stream(stream, Default::default())
225  }
226
227  /// Save image to Jpeg 2000 file.  It will detect the J2K format.
228  #[cfg(feature = "file-io")]
229  pub fn save_as_file_with<P: AsRef<Path>>(&self, path: P, params: EncodeParameters) -> Result<()> {
230    let stream = Stream::to_file(path)?;
231    self.to_stream(stream, params)
232  }
233
234  fn from_stream(stream: Stream<'_>, mut params: DecodeParameters) -> Result<Self> {
235    let decoder = Decoder::new(stream)?;
236    decoder.setup(&mut params)?;
237
238    let img = decoder.read_header()?;
239
240    decoder.set_decode_area(&img, &params)?;
241
242    decoder.decode(&img)?;
243
244    Ok(img)
245  }
246
247  #[cfg(feature = "file-io")]
248  fn to_stream(&self, stream: Stream<'_>, params: EncodeParameters) -> Result<()> {
249    let encoder = Encoder::new(stream)?;
250    encoder.setup(params, &self)?;
251
252    encoder.encode(&self)?;
253
254    Ok(())
255  }
256
257  fn image(&self) -> &sys::opj_image_t {
258    unsafe { &(*self.img.as_ptr()) }
259  }
260
261  pub(crate) fn as_ptr(&self) -> *mut sys::opj_image_t {
262    self.img.as_ptr()
263  }
264
265  /// Horizontal offset.
266  pub fn x_offset(&self) -> u32 {
267    let img = self.image();
268    img.x0
269  }
270
271  /// Vertical offset.
272  pub fn y_offset(&self) -> u32 {
273    let img = self.image();
274    img.y0
275  }
276
277  /// Full resolution image width.  Not reduced by the scaling factor.
278  pub fn orig_width(&self) -> u32 {
279    let img = self.image();
280    img.x1 - img.x0
281  }
282
283  /// Full resolution image height.  Not reduced by the scaling factor.
284  pub fn orig_height(&self) -> u32 {
285    let img = self.image();
286    img.y1 - img.y0
287  }
288
289  /// Decoded image width.  Reduced by the scaling factor.
290  pub fn width(&self) -> u32 {
291    self
292      .component_dimensions()
293      .map(|(w, _)| w)
294      .unwrap_or_default()
295  }
296
297  /// Decoded image height.  Reduced by the scaling factor.
298  pub fn height(&self) -> u32 {
299    self
300      .component_dimensions()
301      .map(|(_, h)| h)
302      .unwrap_or_default()
303  }
304
305  /// Color space.
306  pub fn color_space(&self) -> ColorSpace {
307    let img = self.image();
308    img.color_space.into()
309  }
310
311  /// Number of components.
312  pub fn num_components(&self) -> u32 {
313    let img = self.image();
314    img.numcomps
315  }
316
317  /// Has ICC Profile.
318  pub fn has_icc_profile(&self) -> bool {
319    let img = self.image();
320    !img.icc_profile_buf.is_null()
321  }
322
323  fn component_dimensions(&self) -> Option<(u32, u32)> {
324    self
325      .components()
326      .get(0)
327      .map(|comp| (comp.width(), comp.height()))
328  }
329
330  /// Image components.
331  pub fn components(&self) -> &[ImageComponent] {
332    let img = self.image();
333    let numcomps = img.numcomps;
334    unsafe { std::slice::from_raw_parts(img.comps as *mut ImageComponent, numcomps as usize) }
335  }
336
337  /// Convert image components into pixels.
338  ///
339  /// `alpha_default` - The default value for the alpha channel if there is no alpha component.
340  pub fn get_pixels(&self, alpha_default: Option<u32>) -> Result<ImageData> {
341    let comps = self.components();
342    let (width, height) = comps
343      .get(0)
344      .map(|c| (c.width(), c.height()))
345      .ok_or_else(|| Error::UnsupportedComponentsError(0))?;
346    let max_prec = comps
347      .iter()
348      .fold(std::u32::MIN, |max, c| max.max(c.precision()));
349    let has_alpha = comps.iter().any(|c| c.is_alpha());
350    let format;
351
352    // Check for support color space.
353    match self.color_space() {
354      ColorSpace::Unknown | ColorSpace::Unspecified => {
355        // Assume either Grey/RGB/RGBA based on number of components.
356      }
357      ColorSpace::SRGB | ColorSpace::Gray => (),
358      cs => {
359        return Err(Error::UnsupportedColorSpaceError(cs));
360      }
361    }
362
363    let data = match (comps, has_alpha, max_prec) {
364      ([r], _, 1..=8) => {
365        if let Some(alpha) = alpha_default {
366          format = ImageFormat::La8;
367          ImagePixelData::La8(r.data_u8().flat_map(|r| [r, alpha as u8]).collect())
368        } else {
369          format = ImageFormat::L8;
370          ImagePixelData::L8(r.data_u8().map(|r| r).collect())
371        }
372      }
373      ([r], _, 9..=16) => {
374        if let Some(alpha) = alpha_default {
375          format = ImageFormat::La16;
376          ImagePixelData::La16(r.data_u16().flat_map(|r| [r, alpha as u16]).collect())
377        } else {
378          format = ImageFormat::L16;
379          ImagePixelData::L16(r.data_u16().collect())
380        }
381      }
382      ([r, a], true, 1..=8) => {
383        format = ImageFormat::La8;
384        ImagePixelData::La8(
385          r.data_u8()
386            .zip(a.data_u8())
387            .flat_map(|(r, a)| [r, a])
388            .collect(),
389        )
390      }
391      ([r, a], true, 9..=16) => {
392        format = ImageFormat::La16;
393        ImagePixelData::La16(
394          r.data_u16()
395            .zip(a.data_u16())
396            .flat_map(|(r, a)| [r, a])
397            .collect(),
398        )
399      }
400      ([r, g, b], false, 1..=8) => {
401        if let Some(alpha) = alpha_default {
402          format = ImageFormat::Rgba8;
403          ImagePixelData::Rgba8(
404            r.data_u8()
405              .zip(g.data_u8().zip(b.data_u8()))
406              .flat_map(|(r, (g, b))| [r, g, b, alpha as u8])
407              .collect(),
408          )
409        } else {
410          format = ImageFormat::Rgb8;
411          ImagePixelData::Rgb8(
412            r.data_u8()
413              .zip(g.data_u8().zip(b.data_u8()))
414              .flat_map(|(r, (g, b))| [r, g, b])
415              .collect(),
416          )
417        }
418      }
419      ([r, g, b], false, 9..=16) => {
420        if let Some(alpha) = alpha_default {
421          format = ImageFormat::Rgba16;
422          ImagePixelData::Rgba16(
423            r.data_u16()
424              .zip(g.data_u16().zip(b.data_u16()))
425              .flat_map(|(r, (g, b))| [r, g, b, alpha as u16])
426              .collect(),
427          )
428        } else {
429          format = ImageFormat::Rgb16;
430          ImagePixelData::Rgb16(
431            r.data_u16()
432              .zip(g.data_u16().zip(b.data_u16()))
433              .flat_map(|(r, (g, b))| [r, g, b])
434              .collect(),
435          )
436        }
437      }
438      ([r, g, b, a], _, 1..=8) => {
439        format = ImageFormat::Rgba8;
440        ImagePixelData::Rgba8(
441          r.data_u8()
442            .zip(g.data_u8().zip(b.data_u8().zip(a.data_u8())))
443            .flat_map(|(r, (g, (b, a)))| [r, g, b, a])
444            .collect(),
445        )
446      }
447      ([r, g, b, a], _, 9..=16) => {
448        format = ImageFormat::Rgba16;
449        ImagePixelData::Rgba16(
450          r.data_u16()
451            .zip(g.data_u16().zip(b.data_u16().zip(a.data_u16())))
452            .flat_map(|(r, (g, (b, a)))| [r, g, b, a])
453            .collect(),
454        )
455      }
456      _ => {
457        return Err(Error::UnsupportedComponentsError(self.num_components()));
458      }
459    };
460    Ok(ImageData {
461      width,
462      height,
463      format,
464      data,
465    })
466  }
467}
468
469/// Try to convert a loaded Jpeg 2000 image into a `image::DynamicImage`.
470#[cfg(feature = "image")]
471impl TryFrom<&Image> for ::image::DynamicImage {
472  type Error = Error;
473
474  fn try_from(img: &Image) -> Result<::image::DynamicImage> {
475    use image::*;
476    let ImageData {
477      width,
478      height,
479      data,
480      ..
481    } = img.get_pixels(None)?;
482    match data {
483      crate::ImagePixelData::L8(data) => {
484        let gray = GrayImage::from_vec(width, height, data)
485          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
486
487        Ok(DynamicImage::ImageLuma8(gray))
488      }
489      crate::ImagePixelData::La8(data) => {
490        let gray = GrayAlphaImage::from_vec(width, height, data)
491          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
492
493        Ok(DynamicImage::ImageLumaA8(gray))
494      }
495      crate::ImagePixelData::Rgb8(data) => {
496        let rgb = RgbImage::from_vec(width, height, data)
497          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
498
499        Ok(DynamicImage::ImageRgb8(rgb))
500      }
501      crate::ImagePixelData::Rgba8(data) => {
502        let rgba = RgbaImage::from_vec(width, height, data)
503          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
504
505        Ok(DynamicImage::ImageRgba8(rgba))
506      }
507      crate::ImagePixelData::L16(data) => {
508        let gray = ImageBuffer::from_vec(width, height, data)
509          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
510
511        Ok(DynamicImage::ImageLuma16(gray))
512      }
513      crate::ImagePixelData::La16(data) => {
514        let gray = ImageBuffer::from_vec(width, height, data)
515          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
516
517        Ok(DynamicImage::ImageLumaA16(gray))
518      }
519      crate::ImagePixelData::Rgb16(data) => {
520        let rgb = ImageBuffer::from_vec(width, height, data)
521          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
522
523        Ok(DynamicImage::ImageRgb16(rgb))
524      }
525      crate::ImagePixelData::Rgba16(data) => {
526        let rgba = ImageBuffer::from_vec(width, height, data)
527          .expect("Shouldn't happen.  Report to jpeg2k if you see this.");
528
529        Ok(DynamicImage::ImageRgba16(rgba))
530      }
531    }
532  }
533}