1use crate::box_reader::{BoxReader, BoxType};
6use crate::codestream::{CodestreamParser, CodingStyle, ImageSize, Marker, Quantization};
7use crate::error::{Jpeg2000Error, ResilienceMode, Result};
8use crate::metadata::{EnumeratedColorSpace, Jp2Metadata};
9use std::io::{Read, Seek, SeekFrom};
10
11pub struct Jpeg2000Reader<R> {
13 reader: R,
15 metadata: Option<Jp2Metadata>,
17 image_size: Option<ImageSize>,
19 coding_style: Option<CodingStyle>,
21 quantization: Option<Quantization>,
23 is_jp2: bool,
25 resilience_mode: ResilienceMode,
27 progressive_state: Option<ProgressiveDecodingState>,
29}
30
31#[derive(Debug, Clone)]
33struct ProgressiveDecodingState {
34 current_layer: u16,
36 #[allow(dead_code)]
38 max_layers: u16,
39 intermediate_data: Vec<u8>,
41 #[allow(dead_code)]
43 width: usize,
44 #[allow(dead_code)]
46 height: usize,
47}
48
49impl<R: Read + Seek> Jpeg2000Reader<R> {
50 pub fn new(mut reader: R) -> Result<Self> {
52 let mut magic = [0u8; 12];
54 let is_jp2 = match reader.read_exact(&mut magic) {
55 Ok(()) => {
56 reader.seek(SeekFrom::Start(0))?;
57 magic[4..8] == *b"jP "
58 }
59 Err(ref e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
60 reader.seek(SeekFrom::Start(0))?;
63 let mut min_magic = [0u8; 2];
64 match reader.read_exact(&mut min_magic) {
65 Ok(()) => {
66 reader.seek(SeekFrom::Start(0))?;
68 false
69 }
70 Err(_) => {
71 return Err(Jpeg2000Error::CodestreamError(
73 "File too small to be valid JPEG2000".to_string(),
74 ));
75 }
76 }
77 }
78 Err(e) => return Err(e.into()),
79 };
80
81 Ok(Self {
82 reader,
83 metadata: None,
84 image_size: None,
85 coding_style: None,
86 quantization: None,
87 is_jp2,
88 resilience_mode: ResilienceMode::default(),
89 progressive_state: None,
90 })
91 }
92
93 pub fn set_resilience_mode(&mut self, mode: ResilienceMode) {
95 self.resilience_mode = mode;
96 }
97
98 pub fn resilience_mode(&self) -> ResilienceMode {
100 self.resilience_mode
101 }
102
103 pub fn enable_error_resilience(&mut self) {
105 self.resilience_mode = ResilienceMode::Basic;
106 }
107
108 pub fn enable_full_error_resilience(&mut self) {
110 self.resilience_mode = ResilienceMode::Full;
111 }
112
113 pub fn disable_error_resilience(&mut self) {
115 self.resilience_mode = ResilienceMode::None;
116 }
117
118 pub fn parse_headers(&mut self) -> Result<()> {
120 if self.is_jp2 {
121 self.parse_jp2_headers()?;
122 } else {
123 self.parse_j2k_headers()?;
124 }
125
126 Ok(())
127 }
128
129 fn parse_jp2_headers(&mut self) -> Result<()> {
131 self.metadata = Some(Jp2Metadata::parse(&mut self.reader)?);
133
134 self.parse_optional_boxes()?;
136
137 let mut box_reader = BoxReader::new(&mut self.reader)?;
139
140 if let Some(jp2c_header) = box_reader.find_box(BoxType::ContiguousCodestream)? {
141 let codestream_data = box_reader.read_box_data(&jp2c_header)?;
143
144 let mut parser = CodestreamParser::new(std::io::Cursor::new(&codestream_data));
146 self.parse_codestream(&mut parser)?;
147 } else {
148 return Err(Jpeg2000Error::BoxParseError {
149 box_type: "jp2c".to_string(),
150 reason: "Codestream box not found".to_string(),
151 });
152 }
153
154 Ok(())
155 }
156
157 fn parse_optional_boxes(&mut self) -> Result<()> {
159 let mut box_reader = BoxReader::new(&mut self.reader)?;
160
161 box_reader.reset()?;
163 if let Some(jp2h_header) = box_reader.find_box(BoxType::Jp2Header)? {
164 let jp2h_data = box_reader.read_box_data(&jp2h_header)?;
165 let mut jp2h_cursor = std::io::Cursor::new(&jp2h_data);
166 let mut sub_reader = BoxReader::new(&mut jp2h_cursor)?;
167
168 if let Some(res_header) = sub_reader.find_box(BoxType::Resolution)? {
170 let res_data = sub_reader.read_box_data(&res_header)?;
171 let mut res_cursor = std::io::Cursor::new(&res_data);
172 let mut res_sub_reader = BoxReader::new(&mut res_cursor)?;
173
174 if let Some(resc_header) = res_sub_reader.find_box(BoxType::CaptureResolution)? {
176 let resc_data = res_sub_reader.read_box_data(&resc_header)?;
177 let mut resc_cursor = std::io::Cursor::new(&resc_data);
178 if let Some(ref mut metadata) = self.metadata {
179 metadata.capture_resolution =
180 Some(crate::metadata::Resolution::parse(&mut resc_cursor)?);
181 }
182 }
183
184 res_sub_reader.reset()?;
186 if let Some(resd_header) = res_sub_reader.find_box(BoxType::DisplayResolution)? {
187 let resd_data = res_sub_reader.read_box_data(&resd_header)?;
188 let mut resd_cursor = std::io::Cursor::new(&resd_data);
189 if let Some(ref mut metadata) = self.metadata {
190 metadata.display_resolution =
191 Some(crate::metadata::Resolution::parse(&mut resd_cursor)?);
192 }
193 }
194 }
195 }
196
197 box_reader.reset()?;
199 while let Some(xml_header) = box_reader.find_box(BoxType::Xml)? {
200 let xml_data = box_reader.read_box_data(&xml_header)?;
201 let mut xml_cursor = std::io::Cursor::new(&xml_data);
202 if let Some(ref mut metadata) = self.metadata {
203 if let Ok(xml_box) =
204 crate::metadata::XmlMetadata::parse(&mut xml_cursor, xml_header.data_size())
205 {
206 metadata.xml_boxes.push(xml_box);
207 }
208 }
209 }
210
211 box_reader.reset()?;
213 while let Some(uuid_header) = box_reader.find_box(BoxType::Uuid)? {
214 let uuid_data = box_reader.read_box_data(&uuid_header)?;
215 let mut uuid_cursor = std::io::Cursor::new(&uuid_data);
216 if let Some(ref mut metadata) = self.metadata {
217 if let Ok(uuid_box) =
218 crate::metadata::UuidBox::parse(&mut uuid_cursor, uuid_header.data_size())
219 {
220 metadata.uuid_boxes.push(uuid_box);
221 }
222 }
223 }
224
225 Ok(())
226 }
227
228 fn parse_j2k_headers(&mut self) -> Result<()> {
230 let mut codestream_data = Vec::new();
232 self.reader.read_to_end(&mut codestream_data)?;
233
234 let mut parser = CodestreamParser::new(std::io::Cursor::new(&codestream_data));
235 self.parse_codestream(&mut parser)?;
236 Ok(())
237 }
238
239 fn parse_codestream<CS: Read>(&mut self, parser: &mut CodestreamParser<CS>) -> Result<()> {
241 match parser.read_marker() {
243 Ok(Some(Marker::Soc)) => {}
244 Ok(Some(m)) => {
245 if self.resilience_mode.is_enabled() {
246 tracing::warn!(
247 "Expected SOC marker, got {:?}, continuing with resilience mode",
248 m
249 );
250 } else {
251 return Err(Jpeg2000Error::CodestreamError(format!(
252 "Expected SOC marker, got {:?}",
253 m
254 )));
255 }
256 }
257 Ok(None) => {
258 if self.resilience_mode.is_enabled() {
259 tracing::warn!(
260 "Unexpected end of stream at SOC, continuing with resilience mode"
261 );
262 } else {
263 return Err(Jpeg2000Error::CodestreamError(
264 "Unexpected end of stream".to_string(),
265 ));
266 }
267 }
268 Err(e) => {
269 if self.resilience_mode.is_enabled() {
270 tracing::warn!(
271 "Error reading SOC marker: {}, continuing with resilience mode",
272 e
273 );
274 } else {
275 return Err(e);
276 }
277 }
278 }
279
280 loop {
282 let marker_result = parser.read_marker();
283
284 match marker_result {
285 Ok(Some(Marker::Siz)) => match parser.parse_siz() {
286 Ok(siz) => self.image_size = Some(siz),
287 Err(e) => {
288 if self.resilience_mode.is_enabled() {
289 tracing::warn!(
290 "Error parsing SIZ marker: {}, using error concealment",
291 e
292 );
293 } else {
294 return Err(e);
295 }
296 }
297 },
298 Ok(Some(Marker::Cod)) => match parser.parse_cod() {
299 Ok(cod) => self.coding_style = Some(cod),
300 Err(e) => {
301 if self.resilience_mode.is_enabled() {
302 tracing::warn!("Error parsing COD marker: {}, using defaults", e);
303 } else {
304 return Err(e);
305 }
306 }
307 },
308 Ok(Some(Marker::Qcd)) => match parser.parse_qcd() {
309 Ok(qcd) => self.quantization = Some(qcd),
310 Err(e) => {
311 if self.resilience_mode.is_enabled() {
312 tracing::warn!("Error parsing QCD marker: {}, using defaults", e);
313 } else {
314 return Err(e);
315 }
316 }
317 },
318 Ok(Some(Marker::Sot)) => {
319 break;
321 }
322 Ok(Some(Marker::Eoc)) => {
323 break;
325 }
326 Ok(Some(marker)) => {
327 if marker.has_segment() {
329 match parser.read_segment_length() {
330 Ok(length) => {
331 if let Err(e) = parser.skip_segment(length) {
332 if self.resilience_mode.is_enabled() {
333 tracing::warn!(
334 "Error skipping marker segment: {}, continuing",
335 e
336 );
337 } else {
338 return Err(e);
339 }
340 }
341 }
342 Err(e) => {
343 if self.resilience_mode.is_enabled() {
344 tracing::warn!(
345 "Error reading segment length: {}, continuing",
346 e
347 );
348 } else {
349 return Err(e);
350 }
351 }
352 }
353 }
354 }
355 Ok(None) => break,
356 Err(e) => {
357 if self.resilience_mode.is_enabled() {
358 tracing::warn!("Error reading marker: {}, attempting to continue", e);
359 break;
360 } else {
361 return Err(e);
362 }
363 }
364 }
365 }
366
367 if self.image_size.is_none() {
369 if self.resilience_mode.is_full() {
370 tracing::warn!("SIZ marker not found, using error concealment with default size");
371 } else {
373 return Err(Jpeg2000Error::CodestreamError(
374 "SIZ marker not found".to_string(),
375 ));
376 }
377 }
378
379 Ok(())
380 }
381
382 pub fn width(&self) -> Result<u32> {
384 if let Some(ref size) = self.image_size {
385 Ok(size.width)
386 } else if let Some(ref metadata) = self.metadata {
387 metadata
388 .image_header
389 .as_ref()
390 .map(|h| h.width)
391 .ok_or_else(|| Jpeg2000Error::InvalidImageHeader("No image header".to_string()))
392 } else {
393 Err(Jpeg2000Error::InvalidImageHeader(
394 "Image size not available".to_string(),
395 ))
396 }
397 }
398
399 pub fn height(&self) -> Result<u32> {
401 if let Some(ref size) = self.image_size {
402 Ok(size.height)
403 } else if let Some(ref metadata) = self.metadata {
404 metadata
405 .image_header
406 .as_ref()
407 .map(|h| h.height)
408 .ok_or_else(|| Jpeg2000Error::InvalidImageHeader("No image header".to_string()))
409 } else {
410 Err(Jpeg2000Error::InvalidImageHeader(
411 "Image size not available".to_string(),
412 ))
413 }
414 }
415
416 pub fn num_components(&self) -> Result<u16> {
418 if let Some(ref size) = self.image_size {
419 Ok(size.num_components)
420 } else if let Some(ref metadata) = self.metadata {
421 metadata
422 .image_header
423 .as_ref()
424 .map(|h| h.num_components)
425 .ok_or_else(|| Jpeg2000Error::InvalidImageHeader("No image header".to_string()))
426 } else {
427 Err(Jpeg2000Error::InvalidImageHeader(
428 "Image size not available".to_string(),
429 ))
430 }
431 }
432
433 pub fn metadata(&self) -> Option<&Jp2Metadata> {
435 self.metadata.as_ref()
436 }
437
438 pub fn decode_rgb(&mut self) -> Result<Vec<u8>> {
440 tracing::warn!("Using simplified JPEG2000 decoder - not suitable for production use");
442
443 let width = self.width()? as usize;
444 let height = self.height()? as usize;
445 let num_components = self.num_components()? as usize;
446
447 let placeholder = vec![128u8; width * height * 3];
458
459 tracing::info!(
460 "JPEG2000 decoder placeholder: {}x{} with {} components",
461 width,
462 height,
463 num_components
464 );
465
466 Ok(placeholder)
467 }
468
469 pub fn decode_rgba(&mut self) -> Result<Vec<u8>> {
471 let rgb = self.decode_rgb()?;
472 let num_pixels = rgb.len() / 3;
473
474 let mut rgba = Vec::with_capacity(num_pixels * 4);
475
476 for i in 0..num_pixels {
477 rgba.push(rgb[i * 3]);
478 rgba.push(rgb[i * 3 + 1]);
479 rgba.push(rgb[i * 3 + 2]);
480 rgba.push(255);
481 }
482
483 Ok(rgba)
484 }
485
486 pub fn decode_tile(&mut self, tile_x: u32, tile_y: u32) -> Result<Vec<u8>> {
488 let image_size = self.image_size.as_ref().ok_or_else(|| {
489 Jpeg2000Error::InvalidImageHeader("Image size not available".to_string())
490 })?;
491
492 if tile_x >= image_size.num_tiles_x() || tile_y >= image_size.num_tiles_y() {
493 return Err(Jpeg2000Error::InvalidTile(format!(
494 "Tile ({}, {}) out of bounds",
495 tile_x, tile_y
496 )));
497 }
498
499 let tile_width = image_size.tile_width as usize;
501 let tile_height = image_size.tile_height as usize;
502
503 Ok(vec![128u8; tile_width * tile_height * 3])
504 }
505
506 pub fn info(&self) -> Result<ImageInfo> {
508 let width = self.width()?;
509 let height = self.height()?;
510 let num_components = self.num_components()?;
511
512 let num_tiles = if let Some(ref size) = self.image_size {
513 size.num_tiles()
514 } else {
515 1
516 };
517
518 let color_space = self
519 .metadata
520 .as_ref()
521 .and_then(|m| m.color_spec.as_ref())
522 .and_then(|c| c.enum_cs);
523
524 let num_levels = self
525 .coding_style
526 .as_ref()
527 .map(|cs| cs.num_levels)
528 .unwrap_or(0);
529
530 Ok(ImageInfo {
531 width,
532 height,
533 num_components,
534 num_tiles,
535 color_space,
536 num_decomposition_levels: num_levels,
537 is_jp2: self.is_jp2,
538 })
539 }
540
541 pub fn file_type(&self) -> Option<&crate::metadata::FileType> {
543 self.metadata.as_ref()?.file_type.as_ref()
544 }
545
546 pub fn image_header(&self) -> Option<&crate::metadata::ImageHeader> {
548 self.metadata.as_ref()?.image_header.as_ref()
549 }
550
551 pub fn color_specification(&self) -> Option<&crate::metadata::ColorSpecification> {
553 self.metadata.as_ref()?.color_spec.as_ref()
554 }
555
556 pub fn capture_resolution(&self) -> Option<&crate::metadata::Resolution> {
558 self.metadata.as_ref()?.capture_resolution.as_ref()
559 }
560
561 pub fn display_resolution(&self) -> Option<&crate::metadata::Resolution> {
563 self.metadata.as_ref()?.display_resolution.as_ref()
564 }
565
566 pub fn capture_resolution_dpi(&self) -> Option<(f64, f64)> {
568 self.capture_resolution().map(|r| r.to_dpi())
569 }
570
571 pub fn display_resolution_dpi(&self) -> Option<(f64, f64)> {
573 self.display_resolution().map(|r| r.to_dpi())
574 }
575
576 pub fn xml_metadata(&self) -> Vec<&crate::metadata::XmlMetadata> {
578 self.metadata
579 .as_ref()
580 .map(|m| m.xml_boxes.iter().collect())
581 .unwrap_or_default()
582 }
583
584 pub fn uuid_boxes(&self) -> Vec<&crate::metadata::UuidBox> {
586 self.metadata
587 .as_ref()
588 .map(|m| m.uuid_boxes.iter().collect())
589 .unwrap_or_default()
590 }
591
592 pub fn coding_style(&self) -> Option<&CodingStyle> {
594 self.coding_style.as_ref()
595 }
596
597 pub fn quantization(&self) -> Option<&Quantization> {
599 self.quantization.as_ref()
600 }
601
602 pub fn image_size_info(&self) -> Option<&ImageSize> {
604 self.image_size.as_ref()
605 }
606
607 pub fn uses_mct(&self) -> bool {
609 self.coding_style
610 .as_ref()
611 .map(|cs| cs.use_mct)
612 .unwrap_or(false)
613 }
614
615 pub fn num_quality_layers(&self) -> u16 {
617 self.coding_style
618 .as_ref()
619 .map(|cs| cs.num_layers)
620 .unwrap_or(1)
621 }
622
623 pub fn num_decomposition_levels(&self) -> u8 {
625 self.coding_style
626 .as_ref()
627 .map(|cs| cs.num_levels)
628 .unwrap_or(0)
629 }
630
631 pub fn decode_quality_layers(&mut self, max_layer: u16) -> Result<Vec<u8>> {
645 let width = self.width()? as usize;
646 let height = self.height()? as usize;
647 let num_layers = self.num_quality_layers();
648
649 if max_layer >= num_layers {
650 return Err(Jpeg2000Error::Tier2Error(format!(
651 "Requested layer {} exceeds available layers {}",
652 max_layer, num_layers
653 )));
654 }
655
656 tracing::info!(
657 "Decoding quality layers 0-{} of {} (progressive)",
658 max_layer,
659 num_layers
660 );
661
662 if self.progressive_state.is_none() {
664 self.progressive_state = Some(ProgressiveDecodingState {
665 current_layer: 0,
666 max_layers: num_layers,
667 intermediate_data: vec![0u8; width * height * 3],
668 width,
669 height,
670 });
671 }
672
673 if let Some(ref mut state) = self.progressive_state {
675 state.current_layer = max_layer;
676
677 let quality_factor = (max_layer + 1) as f32 / num_layers as f32;
686 let base_value = (128.0 * quality_factor) as u8;
687
688 for pixel in state.intermediate_data.iter_mut() {
689 *pixel = base_value;
690 }
691
692 tracing::info!(
693 "Progressive decode to layer {} (quality factor: {:.2})",
694 max_layer,
695 quality_factor
696 );
697
698 Ok(state.intermediate_data.clone())
699 } else {
700 Err(Jpeg2000Error::Other(
701 "Failed to initialize progressive state".to_string(),
702 ))
703 }
704 }
705
706 pub fn decode_progressive(&mut self) -> Result<ProgressiveDecoder<'_, R>> {
711 let num_layers = self.num_quality_layers();
712
713 Ok(ProgressiveDecoder {
714 reader: self,
715 current_layer: 0,
716 max_layers: num_layers,
717 })
718 }
719
720 pub fn progressive_layer(&self) -> Option<u16> {
722 self.progressive_state.as_ref().map(|s| s.current_layer)
723 }
724
725 pub fn reset_progressive_state(&mut self) {
727 self.progressive_state = None;
728 }
729
730 pub fn is_progressive_active(&self) -> bool {
732 self.progressive_state.is_some()
733 }
734
735 pub fn decode_region(&mut self, x: u32, y: u32, width: u32, height: u32) -> Result<Vec<u8>> {
751 let image_width = self.width()?;
752 let image_height = self.height()?;
753
754 if x + width > image_width {
756 return Err(Jpeg2000Error::InvalidDimension(format!(
757 "Region x+width ({}) exceeds image width ({})",
758 x + width,
759 image_width
760 )));
761 }
762
763 if y + height > image_height {
764 return Err(Jpeg2000Error::InvalidDimension(format!(
765 "Region y+height ({}) exceeds image height ({})",
766 y + height,
767 image_height
768 )));
769 }
770
771 tracing::info!(
772 "Decoding region: {}x{} at ({}, {}) from {}x{} image",
773 width,
774 height,
775 x,
776 y,
777 image_width,
778 image_height
779 );
780
781 let tiles = self.compute_intersecting_tiles(x, y, width, height)?;
783
784 tracing::debug!("Region intersects with {} tiles", tiles.len());
785
786 let region_size = (width * height * 3) as usize;
793 let mut region_data = vec![128u8; region_size];
794
795 for py in 0..height {
797 for px in 0..width {
798 let idx = ((py * width + px) * 3) as usize;
799 if idx + 2 < region_data.len() {
800 region_data[idx] = ((px + x) % 256) as u8;
802 region_data[idx + 1] = ((py + y) % 256) as u8;
803 region_data[idx + 2] = 128;
804 }
805 }
806 }
807
808 Ok(region_data)
809 }
810
811 pub fn decode_region_at_resolution(
828 &mut self,
829 x: u32,
830 y: u32,
831 width: u32,
832 height: u32,
833 resolution_level: u8,
834 ) -> Result<Vec<u8>> {
835 let max_levels = self.num_decomposition_levels();
836
837 if resolution_level > max_levels {
838 return Err(Jpeg2000Error::InvalidDimension(format!(
839 "Resolution level {} exceeds maximum decomposition levels {}",
840 resolution_level, max_levels
841 )));
842 }
843
844 let scale_factor = 1u32 << resolution_level;
845 let full_res_x = x * scale_factor;
846 let full_res_y = y * scale_factor;
847 let full_res_width = width * scale_factor;
848 let full_res_height = height * scale_factor;
849
850 let image_width = self.width()?;
851 let image_height = self.height()?;
852
853 if full_res_x + full_res_width > image_width || full_res_y + full_res_height > image_height
854 {
855 return Err(Jpeg2000Error::InvalidDimension(format!(
856 "Scaled region ({}x{} at {},{}) exceeds image bounds ({}x{})",
857 full_res_width, full_res_height, full_res_x, full_res_y, image_width, image_height
858 )));
859 }
860
861 tracing::info!(
862 "Decoding region {}x{} at ({},{}) with resolution level {} (scale 1/{})",
863 width,
864 height,
865 x,
866 y,
867 resolution_level,
868 scale_factor
869 );
870
871 let region_size = (width * height * 3) as usize;
877 let mut region_data = vec![128u8; region_size];
878
879 let blur_factor = scale_factor as u8;
881 for py in 0..height {
882 for px in 0..width {
883 let idx = ((py * width + px) * 3) as usize;
884 if idx + 2 < region_data.len() {
885 region_data[idx] = ((px + x) / u32::from(blur_factor) % 128 + 64) as u8;
886 region_data[idx + 1] = ((py + y) / u32::from(blur_factor) % 128 + 64) as u8;
887 region_data[idx + 2] = 128;
888 }
889 }
890 }
891
892 Ok(region_data)
893 }
894
895 fn compute_intersecting_tiles(
897 &self,
898 x: u32,
899 y: u32,
900 width: u32,
901 height: u32,
902 ) -> Result<Vec<(u32, u32)>> {
903 let image_size = self.image_size.as_ref().ok_or_else(|| {
904 Jpeg2000Error::InvalidImageHeader("Image size not available".to_string())
905 })?;
906
907 let tile_width = image_size.tile_width;
908 let tile_height = image_size.tile_height;
909 let tile_x_offset = image_size.tile_x_offset;
910 let tile_y_offset = image_size.tile_y_offset;
911
912 let start_tile_x = if x >= tile_x_offset {
914 (x - tile_x_offset) / tile_width
915 } else {
916 0
917 };
918
919 let start_tile_y = if y >= tile_y_offset {
920 (y - tile_y_offset) / tile_height
921 } else {
922 0
923 };
924
925 let end_tile_x = if x + width >= tile_x_offset {
926 ((x + width - 1 - tile_x_offset) / tile_width).min(image_size.num_tiles_x() - 1)
927 } else {
928 0
929 };
930
931 let end_tile_y = if y + height >= tile_y_offset {
932 ((y + height - 1 - tile_y_offset) / tile_height).min(image_size.num_tiles_y() - 1)
933 } else {
934 0
935 };
936
937 let mut tiles = Vec::new();
938 for ty in start_tile_y..=end_tile_y {
939 for tx in start_tile_x..=end_tile_x {
940 tiles.push((tx, ty));
941 }
942 }
943
944 Ok(tiles)
945 }
946
947 pub fn decode_region_from_tiles(
952 &mut self,
953 tiles: &[(u32, u32)],
954 region_x: u32,
955 region_y: u32,
956 region_width: u32,
957 region_height: u32,
958 ) -> Result<Vec<u8>> {
959 tracing::info!(
960 "Decoding {} tiles for region {}x{} at ({},{})",
961 tiles.len(),
962 region_width,
963 region_height,
964 region_x,
965 region_y
966 );
967
968 let region_size = (region_width * region_height * 3) as usize;
970 Ok(vec![128u8; region_size])
971 }
972}
973
974pub struct ProgressiveDecoder<'a, R> {
978 reader: &'a mut Jpeg2000Reader<R>,
979 current_layer: u16,
980 max_layers: u16,
981}
982
983impl<'a, R: Read + Seek> ProgressiveDecoder<'a, R> {
984 pub fn next_layer(&mut self) -> Result<Option<Vec<u8>>> {
986 if self.current_layer >= self.max_layers {
987 return Ok(None);
988 }
989
990 let data = self.reader.decode_quality_layers(self.current_layer)?;
991 self.current_layer += 1;
992
993 Ok(Some(data))
994 }
995
996 pub fn current_layer(&self) -> u16 {
998 self.current_layer
999 }
1000
1001 pub fn total_layers(&self) -> u16 {
1003 self.max_layers
1004 }
1005
1006 pub fn progress(&self) -> f64 {
1008 if self.max_layers == 0 {
1009 1.0
1010 } else {
1011 f64::from(self.current_layer) / f64::from(self.max_layers)
1012 }
1013 }
1014
1015 pub fn is_complete(&self) -> bool {
1017 self.current_layer >= self.max_layers
1018 }
1019
1020 pub fn skip_to_layer(&mut self, layer: u16) -> Result<Vec<u8>> {
1022 if layer >= self.max_layers {
1023 return Err(Jpeg2000Error::Tier2Error(format!(
1024 "Layer {} exceeds maximum {}",
1025 layer, self.max_layers
1026 )));
1027 }
1028
1029 self.current_layer = layer;
1030 self.reader.decode_quality_layers(layer)
1031 }
1032}
1033
1034#[derive(Debug, Clone)]
1036pub struct ImageInfo {
1037 pub width: u32,
1039 pub height: u32,
1041 pub num_components: u16,
1043 pub num_tiles: u32,
1045 pub color_space: Option<EnumeratedColorSpace>,
1047 pub num_decomposition_levels: u8,
1049 pub is_jp2: bool,
1051}
1052
1053#[cfg(test)]
1054mod tests {
1055 use super::*;
1056 use std::io::Cursor;
1057
1058 #[test]
1059 fn test_reader_creation() {
1060 let data = vec![
1062 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A, ];
1066
1067 let cursor = Cursor::new(data);
1068 let result = Jpeg2000Reader::new(cursor);
1069 assert!(result.is_ok());
1070
1071 let reader = result.expect("reader failed");
1072 assert!(reader.is_jp2);
1073 }
1074
1075 #[test]
1076 fn test_j2k_detection() {
1077 let data = vec![
1079 0xFF, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
1082
1083 let cursor = Cursor::new(data);
1084 let result = Jpeg2000Reader::new(cursor);
1085 assert!(result.is_ok());
1086
1087 let reader = result.expect("reader failed");
1088 assert!(!reader.is_jp2);
1089 }
1090
1091 #[test]
1092 fn test_resilience_mode_default() {
1093 let data = vec![
1094 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1095 ];
1096 let cursor = Cursor::new(data);
1097 let reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1098
1099 assert_eq!(reader.resilience_mode(), ResilienceMode::None);
1100 assert!(!reader.resilience_mode().is_enabled());
1101 }
1102
1103 #[test]
1104 fn test_resilience_mode_configuration() {
1105 let data = vec![
1106 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1107 ];
1108 let cursor = Cursor::new(data);
1109 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1110
1111 reader.enable_error_resilience();
1113 assert_eq!(reader.resilience_mode(), ResilienceMode::Basic);
1114 assert!(reader.resilience_mode().is_enabled());
1115
1116 reader.enable_full_error_resilience();
1118 assert_eq!(reader.resilience_mode(), ResilienceMode::Full);
1119 assert!(reader.resilience_mode().is_full());
1120
1121 reader.disable_error_resilience();
1123 assert_eq!(reader.resilience_mode(), ResilienceMode::None);
1124 }
1125
1126 #[test]
1127 fn test_progressive_state_initialization() {
1128 let data = vec![
1129 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1130 ];
1131 let cursor = Cursor::new(data);
1132 let reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1133
1134 assert!(!reader.is_progressive_active());
1135 assert!(reader.progressive_layer().is_none());
1136 }
1137
1138 #[test]
1139 fn test_progressive_state_reset() {
1140 let data = vec![
1141 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1142 ];
1143 let cursor = Cursor::new(data);
1144 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1145
1146 reader.progressive_state = Some(ProgressiveDecodingState {
1148 current_layer: 2,
1149 max_layers: 5,
1150 intermediate_data: vec![],
1151 width: 256,
1152 height: 256,
1153 });
1154
1155 assert!(reader.is_progressive_active());
1156 assert_eq!(reader.progressive_layer(), Some(2));
1157
1158 reader.reset_progressive_state();
1160 assert!(!reader.is_progressive_active());
1161 assert!(reader.progressive_layer().is_none());
1162 }
1163
1164 #[test]
1165 fn test_region_bounds_validation() {
1166 let data = vec![
1167 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1168 ];
1169 let cursor = Cursor::new(data);
1170 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1171
1172 reader.image_size = Some(ImageSize {
1174 width: 256,
1175 height: 256,
1176 x_offset: 0,
1177 y_offset: 0,
1178 tile_width: 256,
1179 tile_height: 256,
1180 tile_x_offset: 0,
1181 tile_y_offset: 0,
1182 num_components: 3,
1183 components: vec![],
1184 });
1185
1186 let result = reader.decode_region(0, 0, 128, 128);
1188 assert!(result.is_ok());
1189
1190 let result = reader.decode_region(200, 0, 100, 128);
1192 assert!(result.is_err());
1193
1194 let result = reader.decode_region(0, 200, 128, 100);
1196 assert!(result.is_err());
1197 }
1198
1199 #[test]
1200 fn test_compute_intersecting_tiles() {
1201 let data = vec![
1202 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1203 ];
1204 let cursor = Cursor::new(data);
1205 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1206
1207 reader.image_size = Some(ImageSize {
1209 width: 512,
1210 height: 512,
1211 x_offset: 0,
1212 y_offset: 0,
1213 tile_width: 128,
1214 tile_height: 128,
1215 tile_x_offset: 0,
1216 tile_y_offset: 0,
1217 num_components: 3,
1218 components: vec![],
1219 });
1220
1221 let tiles = reader.compute_intersecting_tiles(0, 0, 64, 64);
1223 assert!(tiles.is_ok());
1224 let tiles = tiles.expect("tiles");
1225 assert_eq!(tiles.len(), 1);
1226 assert_eq!(tiles[0], (0, 0));
1227
1228 let tiles = reader.compute_intersecting_tiles(64, 64, 128, 128);
1230 assert!(tiles.is_ok());
1231 let tiles = tiles.expect("tiles");
1232 assert!(!tiles.is_empty());
1233
1234 let tiles = reader.compute_intersecting_tiles(0, 0, 512, 512);
1236 assert!(tiles.is_ok());
1237 let tiles = tiles.expect("tiles");
1238 assert_eq!(tiles.len(), 16); }
1240
1241 #[test]
1242 fn test_resolution_level_scaling() {
1243 let data = vec![
1244 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1245 ];
1246 let cursor = Cursor::new(data);
1247 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1248
1249 reader.image_size = Some(ImageSize {
1251 width: 256,
1252 height: 256,
1253 x_offset: 0,
1254 y_offset: 0,
1255 tile_width: 256,
1256 tile_height: 256,
1257 tile_x_offset: 0,
1258 tile_y_offset: 0,
1259 num_components: 3,
1260 components: vec![],
1261 });
1262
1263 reader.coding_style = Some(CodingStyle {
1265 progression_order: crate::codestream::ProgressionOrder::Lrcp,
1266 num_layers: 5,
1267 use_mct: true,
1268 num_levels: 3,
1269 code_block_width: 64,
1270 code_block_height: 64,
1271 code_block_style: 0,
1272 wavelet: crate::codestream::WaveletTransform::Reversible53,
1273 });
1274
1275 let result = reader.decode_region_at_resolution(0, 0, 128, 128, 0);
1277 assert!(result.is_ok());
1278 let data = result.expect("data");
1279 assert_eq!(data.len(), 128 * 128 * 3);
1280
1281 let result = reader.decode_region_at_resolution(0, 0, 64, 64, 1);
1283 assert!(result.is_ok());
1284 let data = result.expect("data");
1285 assert_eq!(data.len(), 64 * 64 * 3);
1286
1287 let result = reader.decode_region_at_resolution(0, 0, 64, 64, 10);
1289 assert!(result.is_err());
1290 }
1291
1292 #[test]
1293 fn test_metadata_accessors() {
1294 let data = vec![
1295 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1296 ];
1297 let cursor = Cursor::new(data);
1298 let reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1299
1300 assert!(reader.file_type().is_none());
1302 assert!(reader.image_header().is_none());
1303 assert!(reader.color_specification().is_none());
1304 assert!(reader.capture_resolution().is_none());
1305 assert!(reader.display_resolution().is_none());
1306 assert!(reader.xml_metadata().is_empty());
1307 assert!(reader.uuid_boxes().is_empty());
1308 }
1309
1310 #[test]
1311 fn test_quality_layer_accessors() {
1312 let data = vec![
1313 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1314 ];
1315 let cursor = Cursor::new(data);
1316 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1317
1318 assert_eq!(reader.num_quality_layers(), 1);
1320
1321 reader.coding_style = Some(CodingStyle {
1323 progression_order: crate::codestream::ProgressionOrder::Lrcp,
1324 num_layers: 10,
1325 use_mct: false,
1326 num_levels: 5,
1327 code_block_width: 64,
1328 code_block_height: 64,
1329 code_block_style: 0,
1330 wavelet: crate::codestream::WaveletTransform::Reversible53,
1331 });
1332
1333 assert_eq!(reader.num_quality_layers(), 10);
1334 assert_eq!(reader.num_decomposition_levels(), 5);
1335 assert!(!reader.uses_mct());
1336 }
1337
1338 #[test]
1339 fn test_progressive_decoder_iterator() {
1340 let data = vec![
1341 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
1342 ];
1343 let cursor = Cursor::new(data);
1344 let mut reader = Jpeg2000Reader::new(cursor).expect("reader creation failed");
1345
1346 reader.image_size = Some(ImageSize {
1348 width: 64,
1349 height: 64,
1350 x_offset: 0,
1351 y_offset: 0,
1352 tile_width: 64,
1353 tile_height: 64,
1354 tile_x_offset: 0,
1355 tile_y_offset: 0,
1356 num_components: 3,
1357 components: vec![],
1358 });
1359
1360 reader.coding_style = Some(CodingStyle {
1361 progression_order: crate::codestream::ProgressionOrder::Lrcp,
1362 num_layers: 3,
1363 use_mct: false,
1364 num_levels: 2,
1365 code_block_width: 32,
1366 code_block_height: 32,
1367 code_block_style: 0,
1368 wavelet: crate::codestream::WaveletTransform::Reversible53,
1369 });
1370
1371 let decoder = reader.decode_progressive().expect("decoder");
1372
1373 assert_eq!(decoder.total_layers(), 3);
1374 assert_eq!(decoder.current_layer(), 0);
1375 assert!(!decoder.is_complete());
1376 assert_eq!(decoder.progress(), 0.0);
1377 }
1378}