1use std::ptr;
2
3#[cfg(feature = "file-io")]
4use std::path::Path;
5
6use super::*;
7
8pub 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 pub fn width(&self) -> u32 {
34 self.0.w
35 }
36
37 pub fn height(&self) -> u32 {
39 self.0.h
40 }
41
42 pub fn precision(&self) -> u32 {
44 self.0.prec
45 }
46
47 pub fn bpp(&self) -> u32 {
49 self.0.bpp
50 }
51
52 pub fn is_alpha(&self) -> bool {
54 self.0.alpha == 1
55 }
56
57 pub fn is_signed(&self) -> bool {
59 self.0.sgnd == 1
60 }
61
62 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 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 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#[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#[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#[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
155pub 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 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 #[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 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 #[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 #[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 #[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, ¶ms)?;
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 pub fn x_offset(&self) -> u32 {
267 let img = self.image();
268 img.x0
269 }
270
271 pub fn y_offset(&self) -> u32 {
273 let img = self.image();
274 img.y0
275 }
276
277 pub fn orig_width(&self) -> u32 {
279 let img = self.image();
280 img.x1 - img.x0
281 }
282
283 pub fn orig_height(&self) -> u32 {
285 let img = self.image();
286 img.y1 - img.y0
287 }
288
289 pub fn width(&self) -> u32 {
291 self
292 .component_dimensions()
293 .map(|(w, _)| w)
294 .unwrap_or_default()
295 }
296
297 pub fn height(&self) -> u32 {
299 self
300 .component_dimensions()
301 .map(|(_, h)| h)
302 .unwrap_or_default()
303 }
304
305 pub fn color_space(&self) -> ColorSpace {
307 let img = self.image();
308 img.color_space.into()
309 }
310
311 pub fn num_components(&self) -> u32 {
313 let img = self.image();
314 img.numcomps
315 }
316
317 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 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 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 match self.color_space() {
354 ColorSpace::Unknown | ColorSpace::Unspecified => {
355 }
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#[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}