1use alloc::vec::Vec;
4
5use super::{
6 J2kDirectColorPlan, J2kDirectGrayscalePlan, J2kDirectRgbaPlan, J2kRect, J2kWaveletTransform,
7};
8use crate::{HtCodeBlockPayloadRanges, J2kClassicCodeBlockPayload, J2kCodestreamRange};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct J2kReferencedPayloadRecordSpan {
13 pub first_record: usize,
15 pub record_count: usize,
17}
18
19impl J2kReferencedPayloadRecordSpan {
20 #[must_use]
22 pub const fn end_record(self) -> Option<usize> {
23 self.first_record.checked_add(self.record_count)
24 }
25}
26
27#[derive(Debug)]
29pub enum J2kReferencedTileGeometry {
30 Grayscale(J2kDirectGrayscalePlan),
32 Color(J2kDirectColorPlan),
34 Rgba(J2kDirectRgbaPlan),
36}
37
38#[derive(Debug)]
40pub struct J2kReferencedTilePlan {
41 tile_index: usize,
42 decoded_rect: J2kRect,
43 destination_rect: J2kRect,
44 payload_records: J2kReferencedPayloadRecordSpan,
45 pub(super) classic_payloads: Vec<J2kClassicCodeBlockPayload>,
46 pub(super) classic_ranges: Vec<J2kCodestreamRange>,
47 wavelet_transform: J2kWaveletTransform,
48 geometry: J2kReferencedTileGeometry,
49}
50
51impl J2kReferencedTilePlan {
52 #[expect(
54 clippy::too_many_arguments,
55 reason = "tile geometry, payload ownership, and transform facts remain explicit"
56 )]
57 #[must_use]
58 pub fn new(
59 tile_index: usize,
60 decoded_rect: J2kRect,
61 destination_rect: J2kRect,
62 payload_records: J2kReferencedPayloadRecordSpan,
63 classic_payloads: Vec<J2kClassicCodeBlockPayload>,
64 classic_ranges: Vec<J2kCodestreamRange>,
65 wavelet_transform: J2kWaveletTransform,
66 geometry: J2kReferencedTileGeometry,
67 ) -> Self {
68 Self {
69 tile_index,
70 decoded_rect,
71 destination_rect,
72 payload_records,
73 classic_payloads,
74 classic_ranges,
75 wavelet_transform,
76 geometry,
77 }
78 }
79
80 #[must_use]
82 pub const fn tile_index(&self) -> usize {
83 self.tile_index
84 }
85
86 #[must_use]
88 pub const fn decoded_rect(&self) -> J2kRect {
89 self.decoded_rect
90 }
91
92 #[must_use]
94 pub const fn destination_rect(&self) -> J2kRect {
95 self.destination_rect
96 }
97
98 #[must_use]
100 pub const fn payload_records(&self) -> J2kReferencedPayloadRecordSpan {
101 self.payload_records
102 }
103
104 #[must_use]
106 pub fn classic_payloads(&self) -> &[J2kClassicCodeBlockPayload] {
107 &self.classic_payloads
108 }
109
110 #[must_use]
112 pub fn classic_ranges(&self) -> &[J2kCodestreamRange] {
113 &self.classic_ranges
114 }
115
116 #[must_use]
118 pub const fn grayscale_geometry(&self) -> Option<&J2kDirectGrayscalePlan> {
119 match &self.geometry {
120 J2kReferencedTileGeometry::Grayscale(value) => Some(value),
121 J2kReferencedTileGeometry::Color(_) | J2kReferencedTileGeometry::Rgba(_) => None,
122 }
123 }
124
125 #[must_use]
127 pub const fn color_geometry(&self) -> Option<&J2kDirectColorPlan> {
128 match &self.geometry {
129 J2kReferencedTileGeometry::Color(value) => Some(value),
130 J2kReferencedTileGeometry::Grayscale(_) | J2kReferencedTileGeometry::Rgba(_) => None,
131 }
132 }
133
134 #[must_use]
136 pub const fn rgba_geometry(&self) -> Option<&J2kDirectRgbaPlan> {
137 match &self.geometry {
138 J2kReferencedTileGeometry::Rgba(value) => Some(value),
139 J2kReferencedTileGeometry::Grayscale(_) | J2kReferencedTileGeometry::Color(_) => None,
140 }
141 }
142
143 #[must_use]
145 pub const fn wavelet_transform(&self) -> J2kWaveletTransform {
146 self.wavelet_transform
147 }
148}
149
150#[derive(Debug, Clone, Copy)]
152pub struct J2kReferencedImageGeometry<'a> {
153 tiles: &'a [J2kReferencedTilePlan],
154 full_dimensions: (u32, u32),
155 output_rect: J2kRect,
156}
157
158impl<'a> J2kReferencedImageGeometry<'a> {
159 const fn new(
160 tiles: &'a [J2kReferencedTilePlan],
161 full_dimensions: (u32, u32),
162 output_rect: J2kRect,
163 ) -> Self {
164 Self {
165 tiles,
166 full_dimensions,
167 output_rect,
168 }
169 }
170
171 #[must_use]
173 pub const fn tiles(self) -> &'a [J2kReferencedTilePlan] {
174 self.tiles
175 }
176
177 #[must_use]
179 pub const fn is_empty(self) -> bool {
180 self.tiles.is_empty()
181 }
182
183 #[must_use]
185 pub const fn full_dimensions(self) -> (u32, u32) {
186 self.full_dimensions
187 }
188
189 #[must_use]
191 pub const fn output_rect(self) -> J2kRect {
192 self.output_rect
193 }
194
195 #[must_use]
197 pub fn is_grayscale(self) -> bool {
198 !self.is_empty()
199 && self
200 .tiles
201 .iter()
202 .all(|tile| tile.grayscale_geometry().is_some())
203 }
204
205 #[must_use]
207 pub fn is_color(self) -> bool {
208 !self.is_empty()
209 && self
210 .tiles
211 .iter()
212 .all(|tile| tile.color_geometry().is_some())
213 }
214
215 #[must_use]
217 pub fn is_rgba(self) -> bool {
218 !self.is_empty() && self.tiles.iter().all(|tile| tile.rgba_geometry().is_some())
219 }
220
221 #[must_use]
223 pub fn grayscale_geometry(self) -> Option<&'a J2kDirectGrayscalePlan> {
224 (self.tiles.len() == 1)
225 .then(|| self.tiles[0].grayscale_geometry())
226 .flatten()
227 }
228
229 #[must_use]
231 pub fn color_geometry(self) -> Option<&'a J2kDirectColorPlan> {
232 (self.tiles.len() == 1)
233 .then(|| self.tiles[0].color_geometry())
234 .flatten()
235 }
236
237 #[must_use]
239 pub fn rgba_geometry(self) -> Option<&'a J2kDirectRgbaPlan> {
240 (self.tiles.len() == 1)
241 .then(|| self.tiles[0].rgba_geometry())
242 .flatten()
243 }
244
245 #[must_use]
247 pub fn uniform_wavelet_transform(self) -> Option<J2kWaveletTransform> {
248 let first = self.tiles.first()?.wavelet_transform();
249 self.tiles
250 .iter()
251 .all(|tile| tile.wavelet_transform() == first)
252 .then_some(first)
253 }
254}
255
256#[derive(Debug)]
258pub enum J2kReferencedClassicPlan {
259 Grayscale {
261 tiles: Vec<J2kReferencedTilePlan>,
263 full_dimensions: (u32, u32),
265 output_rect: J2kRect,
267 payloads: Vec<J2kClassicCodeBlockPayload>,
269 ranges: Vec<J2kCodestreamRange>,
271 },
272 Color {
274 tiles: Vec<J2kReferencedTilePlan>,
276 full_dimensions: (u32, u32),
278 output_rect: J2kRect,
280 payloads: Vec<J2kClassicCodeBlockPayload>,
282 ranges: Vec<J2kCodestreamRange>,
284 },
285 Rgba {
287 tiles: Vec<J2kReferencedTilePlan>,
289 full_dimensions: (u32, u32),
291 output_rect: J2kRect,
293 payloads: Vec<J2kClassicCodeBlockPayload>,
295 ranges: Vec<J2kCodestreamRange>,
297 },
298}
299
300#[derive(Debug)]
302pub enum J2kReferencedHtj2kPlan {
303 Grayscale {
305 tiles: Vec<J2kReferencedTilePlan>,
307 full_dimensions: (u32, u32),
309 output_rect: J2kRect,
311 payloads: Vec<HtCodeBlockPayloadRanges>,
313 },
314 Color {
316 tiles: Vec<J2kReferencedTilePlan>,
318 full_dimensions: (u32, u32),
320 output_rect: J2kRect,
322 payloads: Vec<HtCodeBlockPayloadRanges>,
324 },
325 Rgba {
327 tiles: Vec<J2kReferencedTilePlan>,
329 full_dimensions: (u32, u32),
331 output_rect: J2kRect,
333 payloads: Vec<HtCodeBlockPayloadRanges>,
335 },
336}
337
338macro_rules! shared_plan_methods {
339 ($name:ident) => {
340 impl $name {
341 #[must_use]
343 pub fn grayscale_geometry(&self) -> Option<&J2kDirectGrayscalePlan> {
344 self.image_geometry().grayscale_geometry()
345 }
346
347 #[must_use]
349 pub fn color_geometry(&self) -> Option<&J2kDirectColorPlan> {
350 self.image_geometry().color_geometry()
351 }
352
353 #[must_use]
355 pub fn rgba_geometry(&self) -> Option<&J2kDirectRgbaPlan> {
356 self.image_geometry().rgba_geometry()
357 }
358
359 #[must_use]
361 pub const fn image_geometry(&self) -> J2kReferencedImageGeometry<'_> {
362 match self {
363 Self::Grayscale {
364 tiles,
365 full_dimensions,
366 output_rect,
367 ..
368 }
369 | Self::Color {
370 tiles,
371 full_dimensions,
372 output_rect,
373 ..
374 }
375 | Self::Rgba {
376 tiles,
377 full_dimensions,
378 output_rect,
379 ..
380 } => J2kReferencedImageGeometry::new(
381 tiles.as_slice(),
382 *full_dimensions,
383 *output_rect,
384 ),
385 }
386 }
387
388 #[must_use]
390 pub fn tiles(&self) -> &[J2kReferencedTilePlan] {
391 self.image_geometry().tiles()
392 }
393
394 #[must_use]
396 pub const fn full_dimensions(&self) -> (u32, u32) {
397 self.image_geometry().full_dimensions()
398 }
399
400 #[must_use]
402 pub const fn output_rect(&self) -> J2kRect {
403 self.image_geometry().output_rect()
404 }
405 }
406 };
407}
408
409shared_plan_methods!(J2kReferencedClassicPlan);
410shared_plan_methods!(J2kReferencedHtj2kPlan);
411
412impl J2kReferencedClassicPlan {
413 #[must_use]
415 pub fn payloads(&self) -> &[J2kClassicCodeBlockPayload] {
416 match self {
417 Self::Grayscale { payloads, .. }
418 | Self::Color { payloads, .. }
419 | Self::Rgba { payloads, .. } => payloads,
420 }
421 }
422
423 #[must_use]
425 pub fn ranges(&self) -> &[J2kCodestreamRange] {
426 match self {
427 Self::Grayscale { ranges, .. }
428 | Self::Color { ranges, .. }
429 | Self::Rgba { ranges, .. } => ranges,
430 }
431 }
432
433 #[must_use]
435 pub fn grayscale(
436 tiles: Vec<J2kReferencedTilePlan>,
437 full_dimensions: (u32, u32),
438 output_rect: J2kRect,
439 payloads: Vec<J2kClassicCodeBlockPayload>,
440 ranges: Vec<J2kCodestreamRange>,
441 ) -> Self {
442 Self::Grayscale {
443 tiles,
444 full_dimensions,
445 output_rect,
446 payloads,
447 ranges,
448 }
449 }
450
451 #[must_use]
453 pub fn color(
454 tiles: Vec<J2kReferencedTilePlan>,
455 full_dimensions: (u32, u32),
456 output_rect: J2kRect,
457 payloads: Vec<J2kClassicCodeBlockPayload>,
458 ranges: Vec<J2kCodestreamRange>,
459 ) -> Self {
460 Self::Color {
461 tiles,
462 full_dimensions,
463 output_rect,
464 payloads,
465 ranges,
466 }
467 }
468
469 #[must_use]
471 pub fn rgba(
472 tiles: Vec<J2kReferencedTilePlan>,
473 full_dimensions: (u32, u32),
474 output_rect: J2kRect,
475 payloads: Vec<J2kClassicCodeBlockPayload>,
476 ranges: Vec<J2kCodestreamRange>,
477 ) -> Self {
478 Self::Rgba {
479 tiles,
480 full_dimensions,
481 output_rect,
482 payloads,
483 ranges,
484 }
485 }
486}
487
488impl J2kReferencedHtj2kPlan {
489 #[must_use]
491 pub fn payloads(&self) -> &[HtCodeBlockPayloadRanges] {
492 match self {
493 Self::Grayscale { payloads, .. }
494 | Self::Color { payloads, .. }
495 | Self::Rgba { payloads, .. } => payloads,
496 }
497 }
498
499 #[must_use]
501 pub fn grayscale(
502 tiles: Vec<J2kReferencedTilePlan>,
503 full_dimensions: (u32, u32),
504 output_rect: J2kRect,
505 payloads: Vec<HtCodeBlockPayloadRanges>,
506 ) -> Self {
507 Self::Grayscale {
508 tiles,
509 full_dimensions,
510 output_rect,
511 payloads,
512 }
513 }
514
515 #[must_use]
517 pub fn color(
518 tiles: Vec<J2kReferencedTilePlan>,
519 full_dimensions: (u32, u32),
520 output_rect: J2kRect,
521 payloads: Vec<HtCodeBlockPayloadRanges>,
522 ) -> Self {
523 Self::Color {
524 tiles,
525 full_dimensions,
526 output_rect,
527 payloads,
528 }
529 }
530
531 #[must_use]
533 pub fn rgba(
534 tiles: Vec<J2kReferencedTilePlan>,
535 full_dimensions: (u32, u32),
536 output_rect: J2kRect,
537 payloads: Vec<HtCodeBlockPayloadRanges>,
538 ) -> Self {
539 Self::Rgba {
540 tiles,
541 full_dimensions,
542 output_rect,
543 payloads,
544 }
545 }
546}