1use std::ffi::CStr;
2use std::os::raw::{c_char, c_void};
3use std::ptr;
4
5use log::{log_enabled, Level};
6
7use super::*;
8
9#[derive(Default, Clone, Copy)]
22pub struct DecodeArea {
23 start_x: u32,
24 start_y: u32,
25 end_x: u32,
26 end_y: u32,
27}
28
29impl std::str::FromStr for DecodeArea {
30 type Err = anyhow::Error;
31 fn from_str(s: &str) -> Result<Self, Self::Err> {
32 let dim = s
33 .splitn(4, ":")
34 .map(|v| v.parse::<u32>())
35 .collect::<Result<Vec<u32>, _>>()?;
36 Ok(Self {
37 start_x: dim.get(0).copied().unwrap_or(0),
38 start_y: dim.get(1).copied().unwrap_or(0),
39 end_x: dim.get(2).copied().unwrap_or(0),
40 end_y: dim.get(3).copied().unwrap_or(0),
41 })
42 }
43}
44
45impl DecodeArea {
46 pub fn new(start_x: u32, start_y: u32, end_x: u32, end_y: u32) -> Self {
47 Self {
48 start_x,
49 start_y,
50 end_x,
51 end_y,
52 }
53 }
54}
55
56#[derive(Clone)]
57pub struct DecodeParameters {
58 params: sys::opj_dparameters,
59 area: Option<DecodeArea>,
60 strict: bool,
61}
62
63impl Default for DecodeParameters {
64 fn default() -> Self {
65 let params = unsafe {
66 let mut ptr = std::mem::zeroed::<sys::opj_dparameters>();
67 sys::opj_set_default_decoder_parameters(&mut ptr as *mut _);
68 ptr
69 };
70 Self {
71 params,
72 area: Default::default(),
73 strict: false,
74 }
75 }
76}
77
78impl DecodeParameters {
79 pub fn new() -> Self {
80 Default::default()
81 }
82
83 pub fn reduce(mut self, reduce: u32) -> Self {
88 self.params.cp_reduce = reduce;
89 self
90 }
91
92 pub fn strict(mut self, strict: bool) -> Self {
97 self.strict = strict;
98 self
99 }
100
101 pub fn layers(mut self, layers: u32) -> Self {
109 self.params.cp_layer = layers;
110 self
111 }
112
113 pub fn decode_area(mut self, area: Option<DecodeArea>) -> Self {
117 self.area = area;
118 self
119 }
120
121 pub fn ignore_pclr_cmap_cdef(mut self) -> Self {
123 self.params.flags |= sys::OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
124 self
125 }
126
127 pub(crate) fn as_ptr(&mut self) -> &mut sys::opj_dparameters {
128 &mut self.params
129 }
130}
131
132#[derive(Clone)]
133pub struct EncodeParameters(sys::opj_cparameters);
134
135impl Default for EncodeParameters {
136 fn default() -> Self {
137 Self(unsafe {
138 let mut ptr = std::mem::zeroed::<sys::opj_cparameters>();
139 sys::opj_set_default_encoder_parameters(&mut ptr as *mut _);
140 ptr
141 })
142 }
143}
144
145pub struct CodestreamTilePartIndex(pub(crate) sys::opj_tp_index_t);
146
147impl std::fmt::Debug for CodestreamTilePartIndex {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("CodestreamTilePartIndex")
150 .field("start_pos", &self.0.start_pos)
151 .field("end_header", &self.0.end_header)
152 .field("end_pos", &self.0.end_pos)
153 .finish()
154 }
155}
156
157pub struct CodestreamPacketInfo(pub(crate) sys::opj_packet_info_t);
158
159impl std::fmt::Debug for CodestreamPacketInfo {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 f.debug_struct("CodestreamPacketInfo")
162 .field("start_pos", &self.0.start_pos)
163 .field("end_ph_pos", &self.0.end_ph_pos)
164 .field("end_pos", &self.0.end_pos)
165 .field("disto", &self.0.disto)
166 .finish()
167 }
168}
169
170pub struct CodestreamMarker(pub(crate) sys::opj_marker_info_t);
171
172impl std::fmt::Debug for CodestreamMarker {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 f.debug_struct("CodestreamMarker")
175 .field("type", &self.0.type_)
176 .field("pos", &self.0.pos)
177 .field("len", &self.0.len)
178 .finish()
179 }
180}
181
182pub struct TileCodingParamInfo(ptr::NonNull<sys::opj_tccp_info_t>);
183
184impl std::fmt::Debug for TileCodingParamInfo {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 let info = self.as_ref();
187 f.debug_struct("TileCodingParamInfo")
188 .field("compno", &info.compno)
189 .field("csty", &info.csty)
190 .field("numresolutions", &info.numresolutions)
191 .field("cblkw", &info.cblkw)
192 .field("cblkh", &info.cblkh)
193 .field("cblksty", &info.cblksty)
194 .field("qmfbid", &info.qmfbid)
195 .field("qntsty", &info.qntsty)
196 .field("stepsizes_mant", &info.stepsizes_mant)
197 .field("stepsizes_expn", &info.stepsizes_expn)
198 .field("numgbits", &info.numgbits)
199 .field("roishift", &info.roishift)
200 .field("prcw", &info.prcw)
201 .field("prch", &info.prch)
202 .finish()
203 }
204}
205
206impl TileCodingParamInfo {
207 fn as_ref(&self) -> &sys::opj_tccp_info_t {
208 unsafe { &(*self.0.as_ref()) }
209 }
210}
211
212pub struct TileInfo<'a>(pub(crate) &'a sys::opj_tile_info_v2_t);
213
214impl<'a> std::fmt::Debug for TileInfo<'a> {
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 f.debug_struct("TileInfo")
217 .field("tileno", &self.0.tileno)
218 .field("csty", &self.0.csty)
219 .field("prg", &self.0.prg)
220 .field("numlayers", &self.0.numlayers)
221 .field("mct", &self.0.mct)
222 .field("tccp_info", &self.tccp_info())
223 .finish()
224 }
225}
226
227impl<'a> TileInfo<'a> {
228 fn tccp_info(&self) -> Option<TileCodingParamInfo> {
229 ptr::NonNull::new(self.0.tccp_info).map(|info| TileCodingParamInfo(info))
230 }
231}
232
233pub struct CodestreamTileIndex(pub(crate) sys::opj_tile_index_t);
234
235impl std::fmt::Debug for CodestreamTileIndex {
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 f.debug_struct("CodestreamTileIndex")
238 .field("tileno", &self.0.tileno)
239 .field("nb_tps", &self.0.nb_tps)
240 .field("current_nb_tps", &self.0.current_nb_tps)
241 .field("current_tpsno", &self.0.current_tpsno)
242 .field("tp_index", &self.tile_parts())
243 .field("marknum", &self.0.marknum)
244 .field("marker", &self.markers())
245 .field("maxmarknum", &self.0.maxmarknum)
246 .field("nb_packet", &self.0.nb_packet)
247 .field("packet_info", &self.packets())
248 .finish()
249 }
250}
251
252impl CodestreamTileIndex {
253 pub fn tile_parts(&self) -> &[CodestreamTilePartIndex] {
255 let num = self.0.nb_tps;
256 unsafe {
257 std::slice::from_raw_parts(
258 self.0.tp_index as *mut CodestreamTilePartIndex,
259 num as usize,
260 )
261 }
262 }
263
264 pub fn markers(&self) -> &[CodestreamMarker] {
266 let num = self.0.marknum;
267 unsafe { std::slice::from_raw_parts(self.0.marker as *mut CodestreamMarker, num as usize) }
268 }
269
270 pub fn packets(&self) -> &[CodestreamPacketInfo] {
272 let num = self.0.nb_packet;
273 unsafe {
274 std::slice::from_raw_parts(
275 self.0.packet_index as *mut CodestreamPacketInfo,
276 num as usize,
277 )
278 }
279 }
280}
281
282pub struct CodestreamIndex(ptr::NonNull<sys::opj_codestream_index_t>);
283
284impl Drop for CodestreamIndex {
285 fn drop(&mut self) {
286 unsafe {
287 sys::opj_destroy_cstr_index(&mut self.0.as_ptr());
288 }
289 }
290}
291
292impl std::fmt::Debug for CodestreamIndex {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294 let idx = self.as_ref();
295 f.debug_struct("CodestreamIndex")
296 .field("main_head_start", &idx.main_head_start)
297 .field("main_head_end", &idx.main_head_end)
298 .field("codestream_size", &idx.codestream_size)
299 .field("marknum", &idx.marknum)
300 .field("marker", &self.markers())
301 .field("maxmarknum", &idx.maxmarknum)
302 .field("nb_of_tiles", &idx.nb_of_tiles)
303 .field("tile_index", &self.tile_indices())
304 .finish()
305 }
306}
307
308impl CodestreamIndex {
309 fn as_ref(&self) -> &sys::opj_codestream_index_t {
310 unsafe { &(*self.0.as_ref()) }
311 }
312
313 pub fn markers(&self) -> &[CodestreamMarker] {
315 let idx = self.as_ref();
316 let num = idx.marknum;
317 unsafe { std::slice::from_raw_parts(idx.marker as *mut CodestreamMarker, num as usize) }
318 }
319
320 pub fn tile_indices(&self) -> &[CodestreamTileIndex] {
322 let idx = self.as_ref();
323 let num = idx.nb_of_tiles;
324 unsafe { std::slice::from_raw_parts(idx.tile_index as *mut CodestreamTileIndex, num as usize) }
325 }
326}
327
328pub struct CodestreamInfo(ptr::NonNull<sys::opj_codestream_info_v2_t>);
329
330impl Drop for CodestreamInfo {
331 fn drop(&mut self) {
332 unsafe {
333 sys::opj_destroy_cstr_info(&mut self.0.as_ptr());
334 }
335 }
336}
337
338impl std::fmt::Debug for CodestreamInfo {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 let info = self.as_ref();
341 let tile_info = if info.tile_info.is_null() {
342 TileInfo(&info.m_default_tile_info)
343 } else {
344 TileInfo(unsafe { &*info.tile_info })
345 };
346 f.debug_struct("CodestreamInfo")
347 .field("tx0", &info.tx0)
348 .field("ty0", &info.ty0)
349 .field("tdx", &info.tdx)
350 .field("tdy", &info.tdy)
351 .field("tw", &info.tw)
352 .field("th", &info.th)
353 .field("nbcomps", &info.nbcomps)
354 .field("tile_info", &tile_info)
355 .finish()
356 }
357}
358
359impl CodestreamInfo {
360 fn as_ref(&self) -> &sys::opj_codestream_info_v2_t {
361 unsafe { &(*self.0.as_ref()) }
362 }
363}
364
365pub(crate) struct Codec {
366 codec: ptr::NonNull<sys::opj_codec_t>,
367}
368
369impl Drop for Codec {
370 fn drop(&mut self) {
371 unsafe {
372 sys::opj_destroy_codec(self.codec.as_ptr());
373 }
374 }
375}
376
377extern "C" fn log_info(msg: *const c_char, _data: *mut c_void) {
378 unsafe {
379 log::info!("{:?}", CStr::from_ptr(msg).to_string_lossy());
380 }
381}
382
383extern "C" fn log_warn(msg: *const c_char, _data: *mut c_void) {
384 unsafe {
385 log::warn!("{:?}", CStr::from_ptr(msg).to_string_lossy());
386 }
387}
388
389extern "C" fn log_error(msg: *const c_char, _data: *mut c_void) {
390 unsafe {
391 log::error!("{:?}", CStr::from_ptr(msg).to_string_lossy());
392 }
393}
394
395impl Codec {
396 fn new(fmt: J2KFormat, is_decoder: bool) -> Result<Self> {
397 let format: sys::CODEC_FORMAT = fmt.into();
398 let ptr = unsafe {
399 if is_decoder {
400 ptr::NonNull::new(sys::opj_create_decompress(format))
401 } else {
402 ptr::NonNull::new(sys::opj_create_compress(format))
403 }
404 };
405 if let Some(ptr) = ptr {
406 let null = ptr::null_mut();
407 unsafe {
408 if log_enabled!(Level::Info) {
409 sys::opj_set_info_handler(ptr.as_ptr(), Some(log_info), null);
410 }
411 if log_enabled!(Level::Warn) {
412 sys::opj_set_warning_handler(ptr.as_ptr(), Some(log_warn), null);
413 }
414 sys::opj_set_error_handler(ptr.as_ptr(), Some(log_error), null);
415
416 #[cfg(feature = "threads")]
417 if sys::opj_has_thread_support() == 1 {
418 let num_cpus = sys::opj_get_num_cpus();
419 if sys::opj_codec_set_threads(ptr.as_ptr(), num_cpus) != 1 {
420 log::warn!("Failed to set number of threads: {:?}", num_cpus);
421 }
422 }
423 }
424
425 Ok(Self { codec: ptr })
426 } else {
427 Err(Error::CreateCodecError(format!(
428 "Codec not supported: {:?}",
429 fmt
430 )))
431 }
432 }
433
434 pub(crate) fn as_ptr(&self) -> *mut sys::opj_codec_t {
435 self.codec.as_ptr()
436 }
437}
438
439pub(crate) struct Decoder<'a> {
440 codec: Codec,
441 stream: Stream<'a>,
442}
443
444impl<'a> Decoder<'a> {
445 pub(crate) fn new(stream: Stream<'a>) -> Result<Self> {
446 assert!(stream.is_input());
447 let fmt = stream.format();
448 let codec = Codec::new(fmt, true)?;
449 Ok(Self { codec, stream })
450 }
451
452 #[cfg(feature = "strict-mode")]
453 fn set_strict_mode(&self, mode: bool) -> Result<()> {
454 let res = unsafe { sys::opj_decoder_set_strict_mode(self.as_ptr(), mode as i32) == 1 };
455 if res {
456 Ok(())
457 } else {
458 Err(Error::CreateCodecError(format!(
459 "Failed to set strict mode on decoder."
460 )))
461 }
462 }
463
464 #[cfg(not(feature = "strict-mode"))]
465 fn set_strict_mode(&self, _mode: bool) -> Result<()> {
466 Ok(())
467 }
468
469 pub(crate) fn setup(&self, params: &mut DecodeParameters) -> Result<()> {
470 let res = unsafe { sys::opj_setup_decoder(self.as_ptr(), params.as_ptr()) == 1 };
471 if res {
472 self.set_strict_mode(params.strict)?;
473 Ok(())
474 } else {
475 Err(Error::CreateCodecError(format!(
476 "Failed to setup decoder with parameters."
477 )))
478 }
479 }
480
481 pub(crate) fn read_header(&self) -> Result<Image> {
482 let mut img: *mut sys::opj_image_t = ptr::null_mut();
483
484 let res = unsafe { sys::opj_read_header(self.stream.as_ptr(), self.as_ptr(), &mut img) };
485 let img = Image::new(img)?;
488 if res == 1 {
489 Ok(img)
490 } else {
491 Err(Error::CodecError("Failed to read header".into()))
492 }
493 }
494
495 pub(crate) fn get_codestream_index(&self) -> Result<CodestreamIndex> {
496 let index = ptr::NonNull::new(unsafe { sys::opj_get_cstr_index(self.as_ptr()) })
497 .ok_or_else(|| Error::CodecError("Failed to get codestream index".into()))?;
498 Ok(CodestreamIndex(index))
499 }
500
501 pub(crate) fn get_codestream_info(&self) -> Result<CodestreamInfo> {
502 let info = ptr::NonNull::new(unsafe { sys::opj_get_cstr_info(self.as_ptr()) })
503 .ok_or_else(|| Error::CodecError("Failed to get codestream info".into()))?;
504 Ok(CodestreamInfo(info))
505 }
506
507 pub(crate) fn set_decode_area(&self, img: &Image, params: &DecodeParameters) -> Result<()> {
508 if let Some(area) = ¶ms.area {
509 let res = unsafe {
510 sys::opj_set_decode_area(
511 self.as_ptr(),
512 img.as_ptr(),
513 area.start_x as i32,
514 area.start_y as i32,
515 area.end_x as i32,
516 area.end_y as i32,
517 )
518 };
519 if res != 1 {
520 return Err(Error::CreateCodecError(format!(
521 "Failed to set decode area."
522 )));
523 }
524 }
525 Ok(())
526 }
527
528 pub(crate) fn decode(&self, img: &Image) -> Result<()> {
529 let res = unsafe {
530 sys::opj_decode(self.as_ptr(), self.stream.as_ptr(), img.as_ptr()) == 1
531 && sys::opj_end_decompress(self.as_ptr(), self.stream.as_ptr()) == 1
532 };
533 if res {
534 Ok(())
535 } else {
536 Err(Error::CodecError("Failed to decode image".into()))
537 }
538 }
539
540 pub(crate) fn as_ptr(&self) -> *mut sys::opj_codec_t {
541 self.codec.as_ptr()
542 }
543}
544
545#[cfg(feature = "file-io")]
546pub(crate) struct Encoder<'a> {
547 codec: Codec,
548 stream: Stream<'a>,
549}
550
551#[cfg(feature = "file-io")]
552impl<'a> Encoder<'a> {
553 pub(crate) fn new(stream: Stream<'a>) -> Result<Self> {
554 assert!(!stream.is_input());
555 let fmt = stream.format();
556 let codec = Codec::new(fmt, false)?;
557 Ok(Self { codec, stream })
558 }
559
560 pub(crate) fn setup(&self, mut params: EncodeParameters, img: &Image) -> Result<()> {
561 let res = unsafe { sys::opj_setup_encoder(self.as_ptr(), &mut params.0, img.as_ptr()) };
562 if res == 1 {
563 Ok(())
564 } else {
565 Err(Error::CreateCodecError(format!(
566 "Failed to setup encoder with parameters."
567 )))
568 }
569 }
570
571 pub(crate) fn encode(&self, img: &Image) -> Result<()> {
572 let res = unsafe {
573 sys::opj_start_compress(self.as_ptr(), img.as_ptr(), self.stream.as_ptr()) == 1
574 && sys::opj_encode(self.as_ptr(), self.stream.as_ptr()) == 1
575 && sys::opj_end_compress(self.as_ptr(), self.stream.as_ptr()) == 1
576 };
577 if res {
578 Ok(())
579 } else {
580 Err(Error::CodecError("Failed to encode image".into()))
581 }
582 }
583
584 pub(crate) fn as_ptr(&self) -> *mut sys::opj_codec_t {
585 self.codec.as_ptr()
586 }
587}