Skip to main content

oxigdal_jpeg2000/tier2/
progression.rs

1//! JPEG2000 progression order iterators (ISO 15444-1 Table A.16)
2//!
3//! JPEG2000 defines five packet progression orders that determine the order
4//! in which packets (layer/resolution/component/precinct tuples) appear in
5//! the codestream.
6
7use crate::codestream::ProgressionOrder;
8
9/// Address of a code block within the codestream, identified by the
10/// four progression dimensions: layer, resolution, component, precinct.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct CodeBlockAddress {
13    /// Quality layer index (0-based)
14    pub layer: u16,
15    /// Resolution level index (0-based)
16    pub resolution: u8,
17    /// Component index (0-based)
18    pub component: u16,
19    /// Precinct index within this resolution level (0-based)
20    pub precinct: u32,
21}
22
23// ---------------------------------------------------------------------------
24// Internal state machine for each of the 5 progression orders
25// ---------------------------------------------------------------------------
26
27#[derive(Debug, Clone)]
28enum ProgressionState {
29    Lrcp {
30        layer: u16,
31        resolution: u8,
32        component: u16,
33        precinct: u32,
34    },
35    Rlcp {
36        resolution: u8,
37        layer: u16,
38        component: u16,
39        precinct: u32,
40    },
41    Rpcl {
42        resolution: u8,
43        precinct: u32,
44        component: u16,
45        layer: u16,
46    },
47    Pcrl {
48        precinct: u32,
49        component: u16,
50        resolution: u8,
51        layer: u16,
52    },
53    Cprl {
54        component: u16,
55        precinct: u32,
56        resolution: u8,
57        layer: u16,
58    },
59    Exhausted,
60}
61
62/// Iterator that yields [`CodeBlockAddress`] tuples in the order specified by
63/// the selected [`ProgressionOrder`].
64///
65/// The iterator visits every valid (layer, resolution, component, precinct)
66/// combination exactly once in the JPEG2000-specified order.
67#[derive(Debug, Clone)]
68pub struct ProgressionIterator {
69    num_layers: u16,
70    num_resolutions: u8,
71    num_components: u16,
72    /// Number of precincts per resolution level (index = resolution level)
73    num_precincts: Vec<u32>,
74    state: ProgressionState,
75}
76
77impl ProgressionIterator {
78    /// Create a new [`ProgressionIterator`].
79    ///
80    /// # Parameters
81    /// - `order`: Progression order as parsed from the COD marker.
82    /// - `num_layers`: Number of quality layers.
83    /// - `num_resolutions`: Number of resolution levels (including full resolution).
84    /// - `num_components`: Number of image components.
85    /// - `num_precincts`: Slice of precinct counts, one per resolution level.
86    ///   If shorter than `num_resolutions`, the last entry is repeated.
87    ///   Defaults to 1 precinct per level when empty.
88    pub fn new(
89        order: ProgressionOrder,
90        num_layers: u16,
91        num_resolutions: u8,
92        num_components: u16,
93        num_precincts: &[u32],
94    ) -> Self {
95        // Normalise precinct counts vector: length == num_resolutions
96        let resolved_precincts: Vec<u32> = if num_precincts.is_empty() {
97            vec![1; num_resolutions as usize]
98        } else {
99            let last = *num_precincts.last().unwrap_or(&1);
100            let mut v: Vec<u32> = num_precincts
101                .iter()
102                .take(num_resolutions as usize)
103                .copied()
104                .collect();
105            while v.len() < num_resolutions as usize {
106                v.push(last);
107            }
108            v
109        };
110
111        let state = if num_layers == 0 || num_resolutions == 0 || num_components == 0 {
112            ProgressionState::Exhausted
113        } else {
114            match order {
115                ProgressionOrder::Lrcp => ProgressionState::Lrcp {
116                    layer: 0,
117                    resolution: 0,
118                    component: 0,
119                    precinct: 0,
120                },
121                ProgressionOrder::Rlcp => ProgressionState::Rlcp {
122                    resolution: 0,
123                    layer: 0,
124                    component: 0,
125                    precinct: 0,
126                },
127                ProgressionOrder::Rpcl => ProgressionState::Rpcl {
128                    resolution: 0,
129                    precinct: 0,
130                    component: 0,
131                    layer: 0,
132                },
133                ProgressionOrder::Pcrl => ProgressionState::Pcrl {
134                    precinct: 0,
135                    component: 0,
136                    resolution: 0,
137                    layer: 0,
138                },
139                ProgressionOrder::Cprl => ProgressionState::Cprl {
140                    component: 0,
141                    precinct: 0,
142                    resolution: 0,
143                    layer: 0,
144                },
145            }
146        };
147
148        Self {
149            num_layers,
150            num_resolutions,
151            num_components,
152            num_precincts: resolved_precincts,
153            state,
154        }
155    }
156
157    /// Return the total number of packets this iterator will yield.
158    pub fn total_packets(&self) -> u64 {
159        let precincts_total: u64 = self.num_precincts.iter().map(|&p| p as u64).sum();
160        precincts_total * self.num_layers as u64 * self.num_components as u64
161    }
162
163    // -----------------------------------------------------------------------
164    // Internal helpers that advance each dimension for each order
165    // -----------------------------------------------------------------------
166
167    fn precincts_for(&self, res: u8) -> u32 {
168        self.num_precincts
169            .get(res as usize)
170            .copied()
171            .unwrap_or(1)
172            .max(1)
173    }
174}
175
176impl Iterator for ProgressionIterator {
177    type Item = CodeBlockAddress;
178
179    fn next(&mut self) -> Option<Self::Item> {
180        match &self.state {
181            ProgressionState::Exhausted => None,
182
183            // ----------------------------------------------------------
184            // LRCP: Layer → Resolution → Component → Precinct (innermost)
185            // ----------------------------------------------------------
186            ProgressionState::Lrcp {
187                layer,
188                resolution,
189                component,
190                precinct,
191            } => {
192                let (l, r, c, p) = (*layer, *resolution, *component, *precinct);
193                let item = CodeBlockAddress {
194                    layer: l,
195                    resolution: r,
196                    component: c,
197                    precinct: p,
198                };
199
200                // Advance innermost (precinct) first
201                let max_p = self.precincts_for(r);
202                let next_p = p + 1;
203                let (nl, nr, nc, np) = if next_p < max_p {
204                    (l, r, c, next_p)
205                } else {
206                    let next_c = c + 1;
207                    if next_c < self.num_components {
208                        (l, r, next_c, 0)
209                    } else {
210                        let next_r = r + 1;
211                        if next_r < self.num_resolutions {
212                            (l, next_r, 0, 0)
213                        } else {
214                            let next_l = l + 1;
215                            if next_l < self.num_layers {
216                                (next_l, 0, 0, 0)
217                            } else {
218                                self.state = ProgressionState::Exhausted;
219                                return Some(item);
220                            }
221                        }
222                    }
223                };
224
225                self.state = ProgressionState::Lrcp {
226                    layer: nl,
227                    resolution: nr,
228                    component: nc,
229                    precinct: np,
230                };
231                Some(item)
232            }
233
234            // ----------------------------------------------------------
235            // RLCP: Resolution → Layer → Component → Precinct
236            // ----------------------------------------------------------
237            ProgressionState::Rlcp {
238                resolution,
239                layer,
240                component,
241                precinct,
242            } => {
243                let (r, l, c, p) = (*resolution, *layer, *component, *precinct);
244                let item = CodeBlockAddress {
245                    layer: l,
246                    resolution: r,
247                    component: c,
248                    precinct: p,
249                };
250
251                let max_p = self.precincts_for(r);
252                let (nr, nl, nc, np) = if p + 1 < max_p {
253                    (r, l, c, p + 1)
254                } else if c + 1 < self.num_components {
255                    (r, l, c + 1, 0)
256                } else if l + 1 < self.num_layers {
257                    (r, l + 1, 0, 0)
258                } else {
259                    let next_r = r + 1;
260                    if next_r < self.num_resolutions {
261                        (next_r, 0, 0, 0)
262                    } else {
263                        self.state = ProgressionState::Exhausted;
264                        return Some(item);
265                    }
266                };
267
268                self.state = ProgressionState::Rlcp {
269                    resolution: nr,
270                    layer: nl,
271                    component: nc,
272                    precinct: np,
273                };
274                Some(item)
275            }
276
277            // ----------------------------------------------------------
278            // RPCL: Resolution → Precinct → Component → Layer
279            // ----------------------------------------------------------
280            ProgressionState::Rpcl {
281                resolution,
282                precinct,
283                component,
284                layer,
285            } => {
286                let (r, p, c, l) = (*resolution, *precinct, *component, *layer);
287                let item = CodeBlockAddress {
288                    layer: l,
289                    resolution: r,
290                    component: c,
291                    precinct: p,
292                };
293
294                let max_p = self.precincts_for(r);
295                let (nr, np, nc, nl) = if l + 1 < self.num_layers {
296                    (r, p, c, l + 1)
297                } else if c + 1 < self.num_components {
298                    (r, p, c + 1, 0)
299                } else if p + 1 < max_p {
300                    (r, p + 1, 0, 0)
301                } else {
302                    let next_r = r + 1;
303                    if next_r < self.num_resolutions {
304                        (next_r, 0, 0, 0)
305                    } else {
306                        self.state = ProgressionState::Exhausted;
307                        return Some(item);
308                    }
309                };
310
311                self.state = ProgressionState::Rpcl {
312                    resolution: nr,
313                    precinct: np,
314                    component: nc,
315                    layer: nl,
316                };
317                Some(item)
318            }
319
320            // ----------------------------------------------------------
321            // PCRL: Precinct → Component → Resolution → Layer
322            // ----------------------------------------------------------
323            ProgressionState::Pcrl {
324                precinct,
325                component,
326                resolution,
327                layer,
328            } => {
329                let (p, c, r, l) = (*precinct, *component, *resolution, *layer);
330                let item = CodeBlockAddress {
331                    layer: l,
332                    resolution: r,
333                    component: c,
334                    precinct: p,
335                };
336
337                let max_p = self.precincts_for(r);
338                let (np, nc, nr, nl) = if l + 1 < self.num_layers {
339                    (p, c, r, l + 1)
340                } else if r + 1 < self.num_resolutions {
341                    (p, c, r + 1, 0)
342                } else if c + 1 < self.num_components {
343                    (p, c + 1, 0, 0)
344                } else if p + 1 < max_p {
345                    (p + 1, 0, 0, 0)
346                } else {
347                    self.state = ProgressionState::Exhausted;
348                    return Some(item);
349                };
350
351                self.state = ProgressionState::Pcrl {
352                    precinct: np,
353                    component: nc,
354                    resolution: nr,
355                    layer: nl,
356                };
357                Some(item)
358            }
359
360            // ----------------------------------------------------------
361            // CPRL: Component → Precinct → Resolution → Layer
362            // ----------------------------------------------------------
363            ProgressionState::Cprl {
364                component,
365                precinct,
366                resolution,
367                layer,
368            } => {
369                let (c, p, r, l) = (*component, *precinct, *resolution, *layer);
370                let item = CodeBlockAddress {
371                    layer: l,
372                    resolution: r,
373                    component: c,
374                    precinct: p,
375                };
376
377                let max_p = self.precincts_for(r);
378                let (nc, np, nr, nl) = if l + 1 < self.num_layers {
379                    (c, p, r, l + 1)
380                } else if r + 1 < self.num_resolutions {
381                    (c, p, r + 1, 0)
382                } else if p + 1 < max_p {
383                    (c, p + 1, 0, 0)
384                } else {
385                    let next_c = c + 1;
386                    if next_c < self.num_components {
387                        (next_c, 0, 0, 0)
388                    } else {
389                        self.state = ProgressionState::Exhausted;
390                        return Some(item);
391                    }
392                };
393
394                self.state = ProgressionState::Cprl {
395                    component: nc,
396                    precinct: np,
397                    resolution: nr,
398                    layer: nl,
399                };
400                Some(item)
401            }
402        }
403    }
404}
405
406#[cfg(test)]
407mod tests {
408    use super::*;
409    use crate::codestream::ProgressionOrder;
410
411    fn collect_all(iter: ProgressionIterator) -> Vec<CodeBlockAddress> {
412        iter.collect()
413    }
414
415    #[test]
416    fn test_lrcp_basic_order() {
417        // 2 layers, 2 resolutions, 1 component, 1 precinct/level
418        let iter = ProgressionIterator::new(ProgressionOrder::Lrcp, 2, 2, 1, &[1, 1]);
419        let items = collect_all(iter);
420        // Expected: (l=0,r=0), (l=0,r=1), (l=1,r=0), (l=1,r=1)
421        assert_eq!(items.len(), 4);
422        assert_eq!(items[0].layer, 0);
423        assert_eq!(items[0].resolution, 0);
424        assert_eq!(items[1].layer, 0);
425        assert_eq!(items[1].resolution, 1);
426        assert_eq!(items[2].layer, 1);
427        assert_eq!(items[2].resolution, 0);
428        assert_eq!(items[3].layer, 1);
429        assert_eq!(items[3].resolution, 1);
430    }
431
432    #[test]
433    fn test_rlcp_basic_order() {
434        let iter = ProgressionIterator::new(ProgressionOrder::Rlcp, 2, 2, 1, &[1, 1]);
435        let items = collect_all(iter);
436        // Expected: (r=0,l=0), (r=0,l=1), (r=1,l=0), (r=1,l=1)
437        assert_eq!(items.len(), 4);
438        assert_eq!(items[0].resolution, 0);
439        assert_eq!(items[0].layer, 0);
440        assert_eq!(items[1].resolution, 0);
441        assert_eq!(items[1].layer, 1);
442        assert_eq!(items[2].resolution, 1);
443        assert_eq!(items[2].layer, 0);
444    }
445
446    #[test]
447    fn test_rpcl_basic_order() {
448        // 1 layer, 2 resolutions, 2 components, 1 precinct/level
449        let iter = ProgressionIterator::new(ProgressionOrder::Rpcl, 1, 2, 2, &[1, 1]);
450        let items = collect_all(iter);
451        // RPCL: r → p → c → l
452        // (r=0,p=0,c=0,l=0), (r=0,p=0,c=1,l=0), (r=1,p=0,c=0,l=0), (r=1,p=0,c=1,l=0)
453        assert_eq!(items.len(), 4);
454        assert_eq!(items[0].resolution, 0);
455        assert_eq!(items[0].component, 0);
456        assert_eq!(items[1].resolution, 0);
457        assert_eq!(items[1].component, 1);
458        assert_eq!(items[2].resolution, 1);
459        assert_eq!(items[2].component, 0);
460    }
461
462    #[test]
463    fn test_pcrl_basic_order() {
464        // 1 layer, 1 resolution, 2 components, 2 precincts at res 0
465        let iter = ProgressionIterator::new(ProgressionOrder::Pcrl, 1, 1, 2, &[2]);
466        let items = collect_all(iter);
467        // PCRL outermost = precinct, then component, then resolution, then layer
468        // (p=0,c=0,r=0,l=0), (p=0,c=1,r=0,l=0), (p=1,c=0,r=0,l=0), (p=1,c=1,r=0,l=0)
469        assert_eq!(items.len(), 4);
470        assert_eq!(items[0].precinct, 0);
471        assert_eq!(items[0].component, 0);
472        assert_eq!(items[1].precinct, 0);
473        assert_eq!(items[1].component, 1);
474        assert_eq!(items[2].precinct, 1);
475        assert_eq!(items[2].component, 0);
476    }
477
478    #[test]
479    fn test_cprl_basic_order() {
480        // 1 layer, 2 resolutions, 2 components, 1 precinct
481        let iter = ProgressionIterator::new(ProgressionOrder::Cprl, 1, 2, 2, &[1, 1]);
482        let items = collect_all(iter);
483        // CPRL: c → p → r → l
484        // (c=0,p=0,r=0,l=0), (c=0,p=0,r=1,l=0), (c=1,p=0,r=0,l=0), (c=1,p=0,r=1,l=0)
485        assert_eq!(items.len(), 4);
486        assert_eq!(items[0].component, 0);
487        assert_eq!(items[0].resolution, 0);
488        assert_eq!(items[1].component, 0);
489        assert_eq!(items[1].resolution, 1);
490        assert_eq!(items[2].component, 1);
491        assert_eq!(items[2].resolution, 0);
492    }
493
494    #[test]
495    fn test_empty_iterator_zero_layers() {
496        let iter = ProgressionIterator::new(ProgressionOrder::Lrcp, 0, 3, 3, &[1, 1, 1]);
497        let items: Vec<_> = iter.collect();
498        assert!(items.is_empty());
499    }
500
501    #[test]
502    fn test_single_item_iterator() {
503        let iter = ProgressionIterator::new(ProgressionOrder::Lrcp, 1, 1, 1, &[1]);
504        let items: Vec<_> = iter.collect();
505        assert_eq!(items.len(), 1);
506        assert_eq!(items[0].layer, 0);
507        assert_eq!(items[0].resolution, 0);
508        assert_eq!(items[0].component, 0);
509        assert_eq!(items[0].precinct, 0);
510    }
511
512    #[test]
513    fn test_multiple_precincts_per_resolution() {
514        // 1 layer, 1 resolution, 1 component, 3 precincts
515        let iter = ProgressionIterator::new(ProgressionOrder::Lrcp, 1, 1, 1, &[3]);
516        let items: Vec<_> = iter.collect();
517        assert_eq!(items.len(), 3);
518        assert_eq!(items[0].precinct, 0);
519        assert_eq!(items[1].precinct, 1);
520        assert_eq!(items[2].precinct, 2);
521    }
522
523    #[test]
524    fn test_total_packets_count() {
525        // 3 layers, 2 resolutions (1 precinct each), 4 components
526        // total = (1+1) * 3 * 4 = 24
527        let iter = ProgressionIterator::new(ProgressionOrder::Lrcp, 3, 2, 4, &[1, 1]);
528        assert_eq!(iter.total_packets(), 24);
529    }
530
531    #[test]
532    fn test_default_precincts_when_empty_slice() {
533        let iter = ProgressionIterator::new(ProgressionOrder::Lrcp, 1, 2, 1, &[]);
534        let items: Vec<_> = iter.collect();
535        // Should produce 2 items (1 precinct per resolution by default)
536        assert_eq!(items.len(), 2);
537    }
538}