corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * CVS identifier:
3 *
4 * $Id: InvWTFull.java,v 1.20 2002/05/22 15:01:32 grosbois Exp $
5 *
6 * Class: InvWTFull
7 *
8 * Description: This class implements a full page inverse DWT for
9 * int and float data.
10 *
11 * the InvWTFullInt and InvWTFullFloat
12 * classes by Bertrand Berthelot, Apr-19-1999
13 *
14 *
15 * COPYRIGHT:
16 *
17 * This software module was originally developed by Raphaël Grosbois and
18 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
19 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
20 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
21 * Centre France S.A) in the course of development of the JPEG2000
22 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
23 * software module is an implementation of a part of the JPEG 2000
24 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
25 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
26 * Partners) agree not to assert against ISO/IEC and users of the JPEG
27 * 2000 Standard (Users) any of their rights under the copyright, not
28 * including other intellectual property rights, for this software module
29 * with respect to the usage by ISO/IEC and Users of this software module
30 * or modifications thereof for use in hardware or software products
31 * claiming conformance to the JPEG 2000 Standard. Those intending to use
32 * this software module in hardware or software products are advised that
33 * their use may infringe existing patents. The original developers of
34 * this software module, JJ2000 Partners and ISO/IEC assume no liability
35 * for use of this software module or modifications thereof. No license
36 * or right to this software module is granted for non JPEG 2000 Standard
37 * conforming products. JJ2000 Partners have full right to use this
38 * software module for his/her own purpose, assign or donate this
39 * software module to any third party and to inhibit third parties from
40 * using this software module for non JPEG 2000 Standard conforming
41 * products. This copyright notice must be included in all copies or
42 * derivative works of this software module.
43 *
44 * Copyright (c) 1999/2000 JJ2000 Partners.
45 * */
46 using System;
47 using System.Collections.Generic;
48 using CSJ2K.j2k.wavelet;
49 using CSJ2K.j2k.decoder;
50 using CSJ2K.j2k.image;
51 using CSJ2K.j2k.util;
52 namespace CSJ2K.j2k.wavelet.synthesis
53 {
54  
55 /// <summary> This class implements the InverseWT with the full-page approach for int and
56 /// float data.
57 ///
58 /// <p>The image can be reconstructed at different (image) resolution levels
59 /// indexed from the lowest resolution available for each tile-component. This
60 /// is controlled by the setImgResLevel() method.</p>
61 ///
62 /// <p>Note: Image resolution level indexes may differ from tile-component
63 /// resolution index. They are indeed indexed starting from the lowest number
64 /// of decomposition levels of each component of each tile.</p>
65 ///
66 /// <p>Example: For an image (1 tile) with 2 components (component 0 having 2
67 /// decomposition levels and component 1 having 3 decomposition levels), the
68 /// first (tile-) component has 3 resolution levels and the second one has 4
69 /// resolution levels, whereas the image has only 3 resolution levels
70 /// available.</p>
71 ///
72 /// <p>This implementation does not support progressive data: Data is
73 /// considered to be non-progressive (i.e. "final" data) and the 'progressive'
74 /// attribute of the 'DataBlk' class is always set to false, see the 'DataBlk'
75 /// class.</p>
76 ///
77 /// </summary>
78 /// <seealso cref="DataBlk">
79 ///
80 /// </seealso>
81 public class InvWTFull:InverseWT
82 {
83  
84 /// <summary>Reference to the ProgressWatch instance if any </summary>
85 private ProgressWatch pw = null;
86  
87 /// <summary>The total number of code-blocks to decode </summary>
88 private int cblkToDecode = 0;
89  
90 /// <summary>The number of already decoded code-blocks </summary>
91 private int nDecCblk = 0;
92  
93 /// <summary>the code-block buffer's source i.e. the quantizer </summary>
94 private CBlkWTDataSrcDec src;
95  
96 /// <summary>Current data type </summary>
97 private int dtype;
98  
99 /// <summary>Block storing the reconstructed image for each component </summary>
100 private DataBlk[] reconstructedComps;
101  
102 /// <summary>Number of decomposition levels in each component </summary>
103 private int[] ndl;
104  
105 /// <summary> The reversible flag for each component in each tile. The first index is
106 /// the tile index, the second one is the component index. The
107 /// reversibility of the components for each tile are calculated on a as
108 /// needed basis.
109 ///
110 /// </summary>
111 private Dictionary<int, bool[]> reversible = new Dictionary<int, bool[]>();
112 //private bool[][] reversible;
113  
114 /// <summary> Initializes this object with the given source of wavelet
115 /// coefficients. It initializes the resolution level for full resolutioin
116 /// reconstruction.
117 ///
118 /// </summary>
119 /// <param name="src">from where the wavelet coefficinets should be obtained.
120 ///
121 /// </param>
122 /// <param name="decSpec">The decoder specifications
123 ///
124 /// </param>
125 public InvWTFull(CBlkWTDataSrcDec src, DecoderSpecs decSpec):base(src, decSpec)
126 {
127 this.src = src;
128 int nc = src.NumComps;
129 reconstructedComps = new DataBlk[nc];
130 ndl = new int[nc];
131 pw = FacilityManager.ProgressWatch;
132 }
133  
134 /// <summary> Returns the reversibility of the current subband. It computes
135 /// iteratively the reversibility of the child subbands. For each subband
136 /// it tests the reversibility of the horizontal and vertical synthesis
137 /// filters used to reconstruct this subband.
138 ///
139 /// </summary>
140 /// <param name="subband">The current subband.
141 ///
142 /// </param>
143 /// <returns> true if all the filters used to reconstruct the current
144 /// subband are reversible
145 ///
146 /// </returns>
147 private bool isSubbandReversible(Subband subband)
148 {
149 if (subband.isNode)
150 {
151 // It's reversible if the filters to obtain the 4 subbands are
152 // reversible and the ones for this one are reversible too.
153 return isSubbandReversible(subband.LL) && isSubbandReversible(subband.HL) && isSubbandReversible(subband.LH) && isSubbandReversible(subband.HH) && ((SubbandSyn) subband).hFilter.Reversible && ((SubbandSyn) subband).vFilter.Reversible;
154 }
155 else
156 {
157 // Leaf subband. Reversibility of data depends on source, so say
158 // it's true
159 return true;
160 }
161 }
162  
163 /// <summary> Returns the reversibility of the wavelet transform for the specified
164 /// component, in the current tile. A wavelet transform is reversible when
165 /// it is suitable for lossless and lossy-to-lossless compression.
166 ///
167 /// </summary>
168 /// <param name="t">The index of the tile.
169 ///
170 /// </param>
171 /// <param name="c">The index of the component.
172 ///
173 /// </param>
174 /// <returns> true is the wavelet transform is reversible, false if not.
175 ///
176 /// </returns>
177 public override bool isReversible(int t, int c)
178 {
179 if (reversible[t] == null)
180 {
181 // Reversibility not yet calculated for this tile
182 reversible[t] = new bool[NumComps];
183 for (int i = reversible[t].Length - 1; i >= 0; i--)
184 {
185 reversible[t][i] = isSubbandReversible(src.getSynSubbandTree(t, i));
186 }
187 }
188 return reversible[t][c];
189 }
190  
191 /// <summary> Returns the number of bits, referred to as the "range bits",
192 /// corresponding to the nominal range of the data in the specified
193 /// component.
194 ///
195 /// <p>The returned value corresponds to the nominal dynamic range of the
196 /// reconstructed image data, as long as the getNomRangeBits() method of
197 /// the source returns a value corresponding to the nominal dynamic range
198 /// of the image data and not not of the wavelet coefficients.</p>
199 ///
200 /// <p>If this number is <i>b</b> then for unsigned data the nominal range
201 /// is between 0 and 2^b-1, and for signed data it is between -2^(b-1) and
202 /// 2^(b-1)-1.</p>
203 ///
204 /// </summary>
205 /// <param name="c">The index of the component.
206 ///
207 /// </param>
208 /// <returns> The number of bits corresponding to the nominal range of the
209 /// data.
210 ///
211 /// </returns>
212 public override int getNomRangeBits(int c)
213 {
214 return src.getNomRangeBits(c);
215 }
216  
217 /// <summary> Returns the position of the fixed point in the specified
218 /// component. This is the position of the least significant integral
219 /// (i.e. non-fractional) bit, which is equivalent to the number of
220 /// fractional bits. For instance, for fixed-point values with 2 fractional
221 /// bits, 2 is returned. For floating-point data this value does not apply
222 /// and 0 should be returned. Position 0 is the position of the least
223 /// significant bit in the data.
224 ///
225 /// <p>This default implementation assumes that the wavelet transform does
226 /// not modify the fixed point. If that were the case this method should be
227 /// overriden.</p>
228 ///
229 /// </summary>
230 /// <param name="c">The index of the component.
231 ///
232 /// </param>
233 /// <returns> The position of the fixed-point, which is the same as the
234 /// number of fractional bits. For floating-point data 0 is returned.
235 ///
236 /// </returns>
237 public override int getFixedPoint(int c)
238 {
239 return src.getFixedPoint(c);
240 }
241  
242 /// <summary> Returns a block of image data containing the specifed rectangular area,
243 /// in the specified component, as a reference to the internal buffer (see
244 /// below). The rectangular area is specified by the coordinates and
245 /// dimensions of the 'blk' object.
246 ///
247 /// <p>The area to return is specified by the 'ulx', 'uly', 'w' and 'h'
248 /// members of the 'blk' argument. These members are not modified by this
249 /// method.</p>
250 ///
251 /// <p>The data returned by this method can be the data in the internal
252 /// buffer of this object, if any, and thus can not be modified by the
253 /// caller. The 'offset' and 'scanw' of the returned data can be
254 /// arbitrary. See the 'DataBlk' class.</p>
255 ///
256 /// <p>The returned data has its 'progressive' attribute unset
257 /// (i.e. false).</p>
258 ///
259 /// </summary>
260 /// <param name="blk">Its coordinates and dimensions specify the area to return.
261 ///
262 /// </param>
263 /// <param name="c">The index of the component from which to get the data.
264 ///
265 /// </param>
266 /// <returns> The requested DataBlk
267 ///
268 /// </returns>
269 /// <seealso cref="getInternCompData">
270 ///
271 /// </seealso>
272 public override DataBlk getInternCompData(DataBlk blk, int c)
273 {
274 int tIdx = TileIdx;
275 if (src.getSynSubbandTree(tIdx, c).HorWFilter == null)
276 {
277 dtype = DataBlk.TYPE_INT;
278 }
279 else
280 {
281 dtype = src.getSynSubbandTree(tIdx, c).HorWFilter.DataType;
282 }
283  
284 //If the source image has not been decomposed
285 if (reconstructedComps[c] == null)
286 {
287 //Allocate component data buffer
288 switch (dtype)
289 {
290  
291 case DataBlk.TYPE_FLOAT:
292 reconstructedComps[c] = new DataBlkFloat(0, 0, getTileCompWidth(tIdx, c), getTileCompHeight(tIdx, c));
293 break;
294  
295 case DataBlk.TYPE_INT:
296 reconstructedComps[c] = new DataBlkInt(0, 0, getTileCompWidth(tIdx, c), getTileCompHeight(tIdx, c));
297 break;
298 }
299 //Reconstruct source image
300 waveletTreeReconstruction(reconstructedComps[c], src.getSynSubbandTree(tIdx, c), c);
301 if (pw != null && c == src.NumComps - 1)
302 {
303 pw.terminateProgressWatch();
304 }
305 }
306  
307 if (blk.DataType != dtype)
308 {
309 if (dtype == DataBlk.TYPE_INT)
310 {
311 blk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h);
312 }
313 else
314 {
315 blk = new DataBlkFloat(blk.ulx, blk.uly, blk.w, blk.h);
316 }
317 }
318 // Set the reference to the internal buffer
319 blk.Data = reconstructedComps[c].Data;
320 blk.offset = reconstructedComps[c].w * blk.uly + blk.ulx;
321 blk.scanw = reconstructedComps[c].w;
322 blk.progressive = false;
323 return blk;
324 }
325  
326 /// <summary> Returns a block of image data containing the specifed rectangular area,
327 /// in the specified component, as a copy (see below). The rectangular area
328 /// is specified by the coordinates and dimensions of the 'blk' object.
329 ///
330 /// <p>The area to return is specified by the 'ulx', 'uly', 'w' and 'h'
331 /// members of the 'blk' argument. These members are not modified by this
332 /// method.</p>
333 ///
334 /// <p>The data returned by this method is always a copy of the internal
335 /// data of this object, if any, and it can be modified "in place" without
336 /// any problems after being returned. The 'offset' of the returned data is
337 /// 0, and the 'scanw' is the same as the block's width. See the 'DataBlk'
338 /// class.</p>
339 ///
340 /// <p>If the data array in 'blk' is <tt>null</tt>, then a new one is
341 /// created. If the data array is not <tt>null</tt> then it must be big
342 /// enough to contain the requested area.</p>
343 ///
344 /// <p>The returned data always has its 'progressive' attribute unset (i.e
345 /// false)</p>
346 ///
347 /// </summary>
348 /// <param name="blk">Its coordinates and dimensions specify the area to
349 /// return. If it contains a non-null data array, then it must be large
350 /// enough. If it contains a null data array a new one is created. The
351 /// fields in this object are modified to return the data.
352 ///
353 /// </param>
354 /// <param name="c">The index of the component from which to get the data.
355 ///
356 /// </param>
357 /// <returns> The requested DataBlk
358 ///
359 /// </returns>
360 /// <seealso cref="getCompData">
361 ///
362 /// </seealso>
363 public override DataBlk getCompData(DataBlk blk, int c)
364 {
365 //int j;
366 System.Object dst_data; // src_data removed
367 int[] dst_data_int; // src_data_int removed
368 float[] dst_data_float; // src_data_float removed
369  
370 // To keep compiler happy
371 dst_data = null;
372  
373 // Ensure output buffer
374 switch (blk.DataType)
375 {
376  
377 case DataBlk.TYPE_INT:
378 dst_data_int = (int[]) blk.Data;
379 if (dst_data_int == null || dst_data_int.Length < blk.w * blk.h)
380 {
381 dst_data_int = new int[blk.w * blk.h];
382 }
383 dst_data = dst_data_int;
384 break;
385  
386 case DataBlk.TYPE_FLOAT:
387 dst_data_float = (float[]) blk.Data;
388 if (dst_data_float == null || dst_data_float.Length < blk.w * blk.h)
389 {
390 dst_data_float = new float[blk.w * blk.h];
391 }
392 dst_data = dst_data_float;
393 break;
394 }
395  
396 // Use getInternCompData() to get the data, since getInternCompData()
397 // returns reference to internal buffer, we must copy it.
398 blk = getInternCompData(blk, c);
399  
400 // Copy the data
401 blk.Data = dst_data;
402 blk.offset = 0;
403 blk.scanw = blk.w;
404 return blk;
405 }
406  
407 /// <summary> Performs the 2D inverse wavelet transform on a subband of the image, on
408 /// the specified component. This method will successively perform 1D
409 /// filtering steps on all columns and then all lines of the subband.
410 ///
411 /// </summary>
412 /// <param name="db">the buffer for the image/wavelet data.
413 ///
414 /// </param>
415 /// <param name="sb">The subband to reconstruct.
416 ///
417 /// </param>
418 /// <param name="c">The index of the component to reconstruct
419 ///
420 /// </param>
421 private void wavelet2DReconstruction(DataBlk db, SubbandSyn sb, int c)
422 {
423 System.Object data;
424 System.Object buf;
425 int ulx, uly, w, h;
426 int i, j, k;
427 int offset;
428  
429 // If subband is empty (i.e. zero size) nothing to do
430 if (sb.w == 0 || sb.h == 0)
431 {
432 return ;
433 }
434  
435 data = db.Data;
436  
437 ulx = sb.ulx;
438 uly = sb.uly;
439 w = sb.w;
440 h = sb.h;
441  
442 buf = null; // To keep compiler happy
443  
444 switch (sb.HorWFilter.DataType)
445 {
446  
447 case DataBlk.TYPE_INT:
448 buf = new int[(w >= h)?w:h];
449 break;
450  
451 case DataBlk.TYPE_FLOAT:
452 buf = new float[(w >= h)?w:h];
453 break;
454 }
455  
456 //Perform the horizontal reconstruction
457 offset = (uly - db.uly) * db.w + ulx - db.ulx;
458 if (sb.ulcx % 2 == 0)
459 {
460 // start index is even => use LPF
461 for (i = 0; i < h; i++, offset += db.w)
462 {
463 // CONVERSION PROBLEM?
464 Array.Copy((System.Array)data, offset, (System.Array)buf, 0, w);
465 sb.hFilter.synthetize_lpf(buf, 0, (w + 1) / 2, 1, buf, (w + 1) / 2, w / 2, 1, data, offset, 1);
466 }
467 }
468 else
469 {
470 // start index is odd => use HPF
471 for (i = 0; i < h; i++, offset += db.w)
472 {
473 // CONVERSION PROBLEM?
474 Array.Copy((System.Array)data, offset, (System.Array)buf, 0, w);
475 sb.hFilter.synthetize_hpf(buf, 0, w / 2, 1, buf, w / 2, (w + 1) / 2, 1, data, offset, 1);
476 }
477 }
478  
479 //Perform the vertical reconstruction
480 offset = (uly - db.uly) * db.w + ulx - db.ulx;
481 switch (sb.VerWFilter.DataType)
482 {
483  
484 case DataBlk.TYPE_INT:
485 int[] data_int, buf_int;
486 data_int = (int[]) data;
487 buf_int = (int[]) buf;
488 if (sb.ulcy % 2 == 0)
489 {
490 // start index is even => use LPF
491 for (j = 0; j < w; j++, offset++)
492 {
493 for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
494 buf_int[i] = data_int[k];
495 sb.vFilter.synthetize_lpf(buf, 0, (h + 1) / 2, 1, buf, (h + 1) / 2, h / 2, 1, data, offset, db.w);
496 }
497 }
498 else
499 {
500 // start index is odd => use HPF
501 for (j = 0; j < w; j++, offset++)
502 {
503 for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
504 buf_int[i] = data_int[k];
505 sb.vFilter.synthetize_hpf(buf, 0, h / 2, 1, buf, h / 2, (h + 1) / 2, 1, data, offset, db.w);
506 }
507 }
508 break;
509  
510 case DataBlk.TYPE_FLOAT:
511 float[] data_float, buf_float;
512 data_float = (float[]) data;
513 buf_float = (float[]) buf;
514 if (sb.ulcy % 2 == 0)
515 {
516 // start index is even => use LPF
517 for (j = 0; j < w; j++, offset++)
518 {
519 for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
520 buf_float[i] = data_float[k];
521 sb.vFilter.synthetize_lpf(buf, 0, (h + 1) / 2, 1, buf, (h + 1) / 2, h / 2, 1, data, offset, db.w);
522 }
523 }
524 else
525 {
526 // start index is odd => use HPF
527 for (j = 0; j < w; j++, offset++)
528 {
529 for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
530 buf_float[i] = data_float[k];
531 sb.vFilter.synthetize_hpf(buf, 0, h / 2, 1, buf, h / 2, (h + 1) / 2, 1, data, offset, db.w);
532 }
533 }
534 break;
535 }
536 }
537  
538 /// <summary> Performs the inverse wavelet transform on the whole component. It
539 /// iteratively reconstructs the subbands from leaves up to the root
540 /// node. This method is recursive, the first call to it the 'sb' must be
541 /// the root of the subband tree. The method will then process the entire
542 /// subband tree by calling itslef recursively.
543 ///
544 /// </summary>
545 /// <param name="img">The buffer for the image/wavelet data.
546 ///
547 /// </param>
548 /// <param name="sb">The subband to reconstruct.
549 ///
550 /// </param>
551 /// <param name="c">The index of the component to reconstruct
552 ///
553 /// </param>
554 private void waveletTreeReconstruction(DataBlk img, SubbandSyn sb, int c)
555 {
556  
557 DataBlk subbData;
558  
559 // If the current subband is a leaf then get the data from the source
560 if (!sb.isNode)
561 {
562 int i, m, n;
563 System.Object src_data, dst_data;
564 Coord ncblks;
565  
566 if (sb.w == 0 || sb.h == 0)
567 {
568 return ; // If empty subband do nothing
569 }
570  
571 // Get all code-blocks in subband
572 if (dtype == DataBlk.TYPE_INT)
573 {
574 subbData = new DataBlkInt();
575 }
576 else
577 {
578 subbData = new DataBlkFloat();
579 }
580 ncblks = sb.numCb;
581 dst_data = img.Data;
582 for (m = 0; m < ncblks.y; m++)
583 {
584 for (n = 0; n < ncblks.x; n++)
585 {
586 subbData = src.getInternCodeBlock(c, m, n, sb, subbData);
587 src_data = subbData.Data;
588 if (pw != null)
589 {
590 nDecCblk++;
591 pw.updateProgressWatch(nDecCblk, null);
592 }
593 // Copy the data line by line
594 for (i = subbData.h - 1; i >= 0; i--)
595 {
596 // CONVERSION PROBLEM
597 Array.Copy((System.Array)src_data, subbData.offset + i * subbData.scanw, (System.Array)dst_data, (subbData.uly + i) * img.w + subbData.ulx, subbData.w);
598 }
599 }
600 }
601 }
602 else if (sb.isNode)
603 {
604 // Reconstruct the lower resolution levels if the current subbands
605 // is a node
606  
607 //Perform the reconstruction of the LL subband
608 waveletTreeReconstruction(img, (SubbandSyn) sb.LL, c);
609  
610 if (sb.resLvl <= reslvl - maxImgRes + ndl[c])
611 {
612 //Reconstruct the other subbands
613 waveletTreeReconstruction(img, (SubbandSyn) sb.HL, c);
614 waveletTreeReconstruction(img, (SubbandSyn) sb.LH, c);
615 waveletTreeReconstruction(img, (SubbandSyn) sb.HH, c);
616  
617 //Perform the 2D wavelet decomposition of the current subband
618 wavelet2DReconstruction(img, (SubbandSyn) sb, c);
619 }
620 }
621 }
622  
623 /// <summary> Returns the implementation type of this wavelet transform, WT_IMPL_FULL
624 /// (full-page based transform). All components return the same.
625 ///
626 /// </summary>
627 /// <param name="c">The index of the component.
628 ///
629 /// </param>
630 /// <returns> WT_IMPL_FULL
631 ///
632 /// </returns>
633 /// <seealso cref="WaveletTransform.WT_IMPL_FULL">
634 ///
635 /// </seealso>
636 public override int getImplementationType(int c)
637 {
638 return CSJ2K.j2k.wavelet.WaveletTransform_Fields.WT_IMPL_FULL;
639 }
640  
641 /// <summary> Changes the current tile, given the new indexes. An
642 /// IllegalArgumentException is thrown if the indexes do not correspond to
643 /// a valid tile.
644 ///
645 /// </summary>
646 /// <param name="x">The horizontal index of the tile.
647 ///
648 /// </param>
649 /// <param name="y">The vertical index of the new tile.
650 ///
651 /// </param>
652 public override void setTile(int x, int y)
653 {
654 int i;
655  
656 // Change tile
657 base.setTile(x, y);
658  
659 int nc = src.NumComps;
660 int tIdx = src.TileIdx;
661 for (int c = 0; c < nc; c++)
662 {
663 ndl[c] = src.getSynSubbandTree(tIdx, c).resLvl;
664 }
665  
666 // Reset the decomposed component buffers.
667 if (reconstructedComps != null)
668 {
669 for (i = reconstructedComps.Length - 1; i >= 0; i--)
670 {
671 reconstructedComps[i] = null;
672 }
673 }
674  
675 cblkToDecode = 0;
676 SubbandSyn root, sb;
677 for (int c = 0; c < nc; c++)
678 {
679 root = src.getSynSubbandTree(tIdx, c);
680 for (int r = 0; r <= reslvl - maxImgRes + root.resLvl; r++)
681 {
682 if (r == 0)
683 {
684 sb = (SubbandSyn) root.getSubbandByIdx(0, 0);
685 if (sb != null)
686 cblkToDecode += sb.numCb.x * sb.numCb.y;
687 }
688 else
689 {
690 sb = (SubbandSyn) root.getSubbandByIdx(r, 1);
691 if (sb != null)
692 cblkToDecode += sb.numCb.x * sb.numCb.y;
693 sb = (SubbandSyn) root.getSubbandByIdx(r, 2);
694 if (sb != null)
695 cblkToDecode += sb.numCb.x * sb.numCb.y;
696 sb = (SubbandSyn) root.getSubbandByIdx(r, 3);
697 if (sb != null)
698 cblkToDecode += sb.numCb.x * sb.numCb.y;
699 }
700 } // Loop on resolution levels
701 } // Loop on components
702 nDecCblk = 0;
703  
704 if (pw != null)
705 {
706 pw.initProgressWatch(0, cblkToDecode, "Decoding tile " + tIdx + "...");
707 }
708 }
709  
710 /// <summary> Advances to the next tile, in standard scan-line order (by rows then
711 /// columns). An 'NoNextElementException' is thrown if the current tile is
712 /// the last one (i.e. there is no next tile).
713 ///
714 /// </summary>
715 public override void nextTile()
716 {
717 int i;
718  
719 // Change tile
720 base.nextTile();
721  
722 int nc = src.NumComps;
723 int tIdx = src.TileIdx;
724 for (int c = 0; c < nc; c++)
725 {
726 ndl[c] = src.getSynSubbandTree(tIdx, c).resLvl;
727 }
728  
729 // Reset the decomposed component buffers.
730 if (reconstructedComps != null)
731 {
732 for (i = reconstructedComps.Length - 1; i >= 0; i--)
733 {
734 reconstructedComps[i] = null;
735 }
736 }
737 }
738 }
739 }