001/*
002 * $RCSfile: InvCompTransf.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:14 $
005 * $State: Exp $
006 *
007 * Class:               InvCompTransf
008 *
009 * Description:         Inverse Component transformations applied to tiles
010 *
011 *
012 *
013 * COPYRIGHT:
014 *
015 * This software module was originally developed by Raphaël Grosbois and
016 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019 * Centre France S.A) in the course of development of the JPEG2000
020 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021 * software module is an implementation of a part of the JPEG 2000
022 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024 * Partners) agree not to assert against ISO/IEC and users of the JPEG
025 * 2000 Standard (Users) any of their rights under the copyright, not
026 * including other intellectual property rights, for this software module
027 * with respect to the usage by ISO/IEC and Users of this software module
028 * or modifications thereof for use in hardware or software products
029 * claiming conformance to the JPEG 2000 Standard. Those intending to use
030 * this software module in hardware or software products are advised that
031 * their use may infringe existing patents. The original developers of
032 * this software module, JJ2000 Partners and ISO/IEC assume no liability
033 * for use of this software module or modifications thereof. No license
034 * or right to this software module is granted for non JPEG 2000 Standard
035 * conforming products. JJ2000 Partners have full right to use this
036 * software module for his/her own purpose, assign or donate this
037 * software module to any third party and to inhibit third parties from
038 * using this software module for non JPEG 2000 Standard conforming
039 * products. This copyright notice must be included in all copies or
040 * derivative works of this software module.
041 *
042 * Copyright (c) 1999/2000 JJ2000 Partners.
043 *  */
044package jj2000.j2k.image.invcomptransf;
045
046import jj2000.j2k.ModuleSpec;
047import jj2000.j2k.decoder.DecoderSpecs;
048import jj2000.j2k.image.BlkImgDataSrc;
049import jj2000.j2k.image.CompTransfSpec;
050import jj2000.j2k.image.DataBlk;
051import jj2000.j2k.image.DataBlkFloat;
052import jj2000.j2k.image.DataBlkInt;
053import jj2000.j2k.image.ImgDataAdapter;
054import jj2000.j2k.util.MathUtil;
055import jj2000.j2k.wavelet.synthesis.SynWTFilterSpec;
056
057/**
058 * This class apply inverse component transformations to the tiles depending
059 * on specification read from the codestream header. These transformations can
060 * be used to improve compression efficiency but are not related to colour
061 * transforms used to map colour values for display purposes. JPEG 2000 part I
062 * defines 2 component transformations: RCT (Reversible Component
063 * Transformation) and ICT (Irreversible Component Transformation).
064 *
065 * @see ModuleSpec
066 * */
067public class InvCompTransf extends ImgDataAdapter
068    implements BlkImgDataSrc{
069
070    /** Identifier for no component transformation. Value is 0. */
071    public static final int NONE = 0;
072
073    /** The prefix for inverse component transformation options: 'M' */
074    public final static char OPT_PREFIX = 'M';
075
076    /** The list of parameters that is accepted by the inverse
077     * component transformation module. They start with 'M'. */
078    private final static String [][] pinfo = null;
079
080    /** Identifier for the Inverse Reversible Component Transformation
081        (INV_RCT). Value is 1. */
082    public static final int INV_RCT = 1;
083
084    /** Identifier for the Inverse Irreversible Component
085        Transformation (INV_ICT). Value is 2 */
086    public static final int INV_ICT = 2;
087
088    /** The source of image data */
089    private BlkImgDataSrc src;
090
091    /** The component transformations specifications */
092    private CompTransfSpec cts;
093
094    /** The wavelet filter specifications */
095    private SynWTFilterSpec wfs;
096
097    /** The type of the current component transformation JPEG 2000
098     * part I only support NONE, FORW_RCT and FORW_ICT types*/
099    private int transfType = NONE;
100
101    /** Buffer for each component of output data */
102    private int[][] outdata = new int[3][];
103
104    /** Block used to request component 0 */
105    private DataBlk block0;
106
107    /** Block used to request component 1 */
108    private DataBlk block1;
109
110    /** Block used to request component 2 */
111    private DataBlk block2;
112
113    /** Data block used only to store coordinates and progressiveness
114        of the buffered blocks */
115    private DataBlkInt dbi = new DataBlkInt();
116
117    /** The bit-depths of un-transformed components */
118    private int utdepth[];
119
120    /** Flag indicating whether the decoder should skip the component 
121     * transform*/
122    private boolean noCompTransf = false;
123
124    /**
125     * Constructs a new ForwCompTransf object that operates on the
126     * specified source of image data.
127     *
128     * @param imgSrc The source from where to get the data to be
129     * transformed
130     *
131     * @param decSpec The decoder specifications
132     *
133     * @see BlkImgDataSrc
134     * */
135    public InvCompTransf(BlkImgDataSrc imgSrc, DecoderSpecs decSpec,
136                         int[] utdepth) {
137        super(imgSrc);
138        this.cts = decSpec.cts;
139        this.wfs = decSpec.wfs;
140        src = imgSrc;
141        this.utdepth = utdepth;
142    }
143
144    /**
145     * Returns the parameters that are used in this class and implementing
146     * classes. It returns a 2D String array. Each of the 1D arrays is for a
147     * different option, and they have 4 elements. The first element is the
148     * option name, the second one is the synopsis, the third one is a long
149     * description of what the parameter is and the fourth is its default
150     * value. The synopsis or description may be 'null', in which case it is
151     * assumed that there is no synopsis or description of the option,
152     * respectively. Null may be returned if no options are supported.
153     *
154     * @return the options name, their synopsis and their explanation,
155     * or null if no options are supported.
156     * */
157    public static String[][] getParameterInfo() {
158        return pinfo;
159    }
160
161    /**
162     * Returns a string with a descriptive text of which inverse component
163     * transformation is used. This can be either "Inverse RCT" or "Inverse
164     * ICT" or "No component transformation" depending on the current tile.
165     *
166     * @return A descriptive string
167     * */
168    public String toString() {
169        switch(transfType){
170        case INV_RCT:
171            return "Inverse RCT";
172        case INV_ICT:
173            return "Inverse ICT";
174        case NONE:
175            return "No component transformation";
176        default:
177            throw new IllegalArgumentException("Non JPEG 2000 part I"+
178                                               " component transformation");
179        }
180    }
181
182    /**
183     * Returns true if this transform is reversible in current
184     * tile. Reversible component transformations are those which operation
185     * can be completely reversed without any loss of information (not even
186     * due to rounding).
187     *
188     * @return Reversibility of component transformation in current
189     * tile
190     * */
191    public boolean isReversible(){
192        switch(transfType){
193        case NONE:
194        case INV_RCT:
195            return true;
196        case INV_ICT:
197            return false;
198        default:
199            throw new IllegalArgumentException("Non JPEG 2000 part I"+
200                                               " component transformation");
201        }
202    }
203
204    /**
205     * Returns the position of the fixed point in the specified
206     * component. This is the position of the least significant integral
207     * (i.e. non-fractional) bit, which is equivalent to the number of
208     * fractional bits. For instance, for fixed-point values with 2 fractional
209     * bits, 2 is returned. For floating-point data this value does not apply
210     * and 0 should be returned. Position 0 is the position of the least
211     * significant bit in the data.
212     *
213     * <P>This default implementation assumes that the number of fractional
214     * bits is not modified by the component mixer.
215     *
216     * @param c The index of the component.
217     *
218     * @return The value of the fixed point position of the source since the
219     * color transform does not affect it.
220     * */
221     public int getFixedPoint(int c) {
222         return src.getFixedPoint(c);
223     }
224
225    /**
226     * Calculates the bitdepths of the transformed components, given the
227     * bitdepth of the un-transformed components and the component
228     * tranformation type.
229     *
230     * @param utdepth The bitdepth of each un-transformed component
231     *
232     * @param ttype The type ID of the inverse component tranformation
233     *
234     * @param tdepth If not null the results are stored in this
235     * array, otherwise a new array is allocated and returned.
236     *
237     * @return The bitdepth of each transformed component.
238     * */
239    public static
240        int[] calcMixedBitDepths(int utdepth[], int ttype, int tdepth[]) {
241
242        if (utdepth.length < 3 && ttype != NONE) {
243            throw new IllegalArgumentException();
244        }
245
246        if (tdepth == null) {
247            tdepth = new int[utdepth.length];
248        }
249
250        switch (ttype) {
251        case NONE:
252            System.arraycopy(utdepth,0,tdepth,0,utdepth.length);
253            break;
254        case INV_RCT:
255            if (utdepth.length >3) {
256                System.arraycopy(utdepth,3,tdepth,3,utdepth.length-3);
257            }
258            // The formulas are:
259            // tdepth[0] = ceil(log2(2^(utdepth[0])+2^utdepth[1]+
260            //                        2^(utdepth[2])))-2+1
261            // tdepth[1] = ceil(log2(2^(utdepth[0])+2^(utdepth[1])-1))+1
262            // tdepth[2] = ceil(log2(2^(utdepth[1])+2^(utdepth[2])-1))+1
263            // The MathUtil.log2(x) function calculates floor(log2(x)), so we
264            // use 'MathUtil.log2(2*x-1)+1', which calculates ceil(log2(x))
265            // for any x>=1, x integer.
266            tdepth[0] = MathUtil.log2((1<<utdepth[0])+(2<<utdepth[1])+
267                                      (1<<utdepth[2])-1)-2+1;
268            tdepth[1] = MathUtil.log2((1<<utdepth[2])+(1<<utdepth[1])-1)+1;
269            tdepth[2] = MathUtil.log2((1<<utdepth[0])+(1<<utdepth[1])-1)+1;
270            break;
271        case INV_ICT:
272            if (utdepth.length >3) {
273                System.arraycopy(utdepth,3,tdepth,3,utdepth.length-3);
274            }
275            // The MathUtil.log2(x) function calculates floor(log2(x)), so we
276            // use 'MathUtil.log2(2*x-1)+1', which calculates ceil(log2(x))
277            // for any x>=1, x integer.
278            tdepth[0] =
279                MathUtil.log2((int)Math.floor((1<<utdepth[0])*0.299072+
280                                              (1<<utdepth[1])*0.586914+
281                                              (1<<utdepth[2])*0.114014)-1)+1;
282            tdepth[1] =
283                MathUtil.log2((int)Math.floor((1<<utdepth[0])*0.168701+
284                                              (1<<utdepth[1])*0.331299+
285                                              (1<<utdepth[2])*0.5)-1)+1;
286            tdepth[2] =
287                MathUtil.log2((int)Math.floor((1<<utdepth[0])*0.5+
288                                              (1<<utdepth[1])*0.418701+
289                                              (1<<utdepth[2])*0.081299)-1)+1;
290            break;
291        }
292
293        return tdepth;
294    }
295
296    /**
297     * Returns the number of bits, referred to as the "range bits",
298     * corresponding to the nominal range of the data in the specified
299     * component. If this number is <i>b</b> then for unsigned data the
300     * nominal range is between 0 and 2^b-1, and for signed data it is between
301     * -2^(b-1) and 2^(b-1)-1.
302     *
303     * @param c The index of the component.
304     *
305     * @return The bitdepth of un-transformed component 'c'.
306     * */
307    public int getNomRangeBits(int c) {
308        return utdepth[c];
309    }
310
311    /**
312     * Apply inverse component transformation associated with the current
313     * tile. If no component transformation has been requested by the user,
314     * data are not modified.
315     *
316     * <P>This method calls the getInternCompData() method, but respects the
317     * definitions of the getCompData() method defined in the BlkImgDataSrc
318     * interface.
319     *
320     * @param blk Determines the rectangular area to return, and the
321     * data is returned in this object.
322     *
323     * @param c Index of the output component.
324     *
325     * @return The requested DataBlk
326     *
327     * @see BlkImgDataSrc#getCompData
328     * */
329    public DataBlk getCompData(DataBlk blk, int c){
330        // If requesting a component whose index is greater than 3 or there is
331        // no transform return a copy of data (getInternCompData returns the
332        // actual data in those cases)
333        if (c>=3 || transfType == NONE) {
334            return src.getCompData(blk,c);
335        }
336        else { // We can use getInternCompData (since data is a copy anyways)
337            return getInternCompData(blk,c);
338        }
339    }
340
341    /**
342     * Apply the inverse component transformation associated with the current
343     * tile. If no component transformation has been requested by the user,
344     * data are not modified. Else, appropriate method is called (invRCT or
345     * invICT).
346     *
347     * @see #invRCT
348     *
349     * @see #invICT
350     *
351     * @param blk Determines the rectangular area to return.
352     *
353     * @param c Index of the output component.
354     *
355     * @return The requested DataBlk
356     * */
357    public DataBlk getInternCompData(DataBlk blk, int c){
358        // if specified in the command line that no component transform should
359        // be made, return original data
360        if(noCompTransf)
361            return src.getInternCompData(blk,c);
362
363        switch(transfType){
364        case NONE:
365            return src.getInternCompData(blk,c);
366        case INV_RCT:
367            return invRCT(blk,c);
368        case INV_ICT:
369            return invICT(blk,c);
370        default:
371            throw new IllegalArgumentException("Non JPEG 2000 part I"+
372                                               " component transformation");
373        }
374    }
375
376    /**
377     * Apply inverse component transformation to obtain requested component
378     * from specified block of data. Whatever the type of requested DataBlk,
379     * it always returns a DataBlkInt.
380     *
381     * @param blk Determine the rectangular area to return
382     *
383     * @param c The index of the requested component
384     *
385     * @return Data of requested component
386     * */
387    private DataBlk invRCT(DataBlk blk,int c){
388        // If the component number is three or greater, return original data
389        if (c>=3 && c < getNumComps()) {
390            // Requesting a component whose index is greater than 3
391            return src.getInternCompData(blk,c);
392        }
393
394        // If asking a component for the first time for this block,
395        // do transform for the 3 components
396        if ((outdata[c] == null)||
397            (dbi.ulx > blk.ulx) || (dbi.uly > blk.uly) ||
398            (dbi.ulx+dbi.w < blk.ulx+blk.w) ||
399            (dbi.uly+dbi.h < blk.uly+blk.h)) {
400            int k,k0,k1,k2,mink,i;
401            int w = blk.w; //width of output block
402            int h = blk.h; //height of ouput block
403
404            //Reference to output block data array
405            outdata[c] = (int[]) blk.getData();
406
407            //Create data array of blk if necessary
408            if(outdata[c] == null || outdata[c].length!=h*w){
409                outdata[c] = new int[h * w];
410                blk.setData(outdata[c]);
411            }
412
413            outdata[(c+1)%3] = new int[outdata[c].length];
414            outdata[(c+2)%3] = new int[outdata[c].length];
415
416            if(block0==null || block0.getDataType()!=DataBlk.TYPE_INT)
417                block0 = new DataBlkInt();
418            if(block1==null || block1.getDataType()!=DataBlk.TYPE_INT)
419                block1 = new DataBlkInt();
420            if(block2==null || block2.getDataType()!=DataBlk.TYPE_INT)
421                block2 = new DataBlkInt();
422            block0.w = block1.w = block2.w = blk.w;
423            block0.h = block1.h = block2.h = blk.h;
424            block0.ulx = block1.ulx = block2.ulx = blk.ulx;
425            block0.uly = block1.uly = block2.uly = blk.uly;
426
427            int data0[],data1[],data2[]; // input data arrays
428
429            // Fill in buffer blocks (to be read only)
430            // Returned blocks may have different size and position
431            block0 = (DataBlkInt)src.getInternCompData(block0, 0);
432            data0 = (int[]) block0.getData();
433            block1 = (DataBlkInt)src.getInternCompData(block1, 1);
434            data1 = (int[]) block1.getData();
435            block2 = (DataBlkInt)src.getInternCompData(block2, 2);
436            data2 = (int[]) block2.getData();
437
438            // Set the progressiveness of the output data
439            blk.progressive = block0.progressive || block1.progressive ||
440                block2.progressive;
441            blk.offset = 0;
442            blk.scanw = w;
443
444            // set attributes of the DataBlk used for buffering
445            dbi.progressive = blk.progressive;
446            dbi.ulx = blk.ulx;
447            dbi.uly = blk.uly;
448            dbi.w = blk.w;
449            dbi.h = blk.h;
450
451            // Perform conversion
452
453            // Initialize general indexes
454            k = w*h-1;
455            k0 = block0.offset+(h-1)*block0.scanw+w-1;
456            k1 = block1.offset+(h-1)*block1.scanw+w-1;
457            k2 = block2.offset+(h-1)*block2.scanw+w-1;
458
459            for( i = h-1; i >=0; i--){
460                for(mink = k-w; k > mink; k--, k0--, k1--, k2--){
461                    outdata[1][k] = (data0[k0] - ((data1[k1]+data2[k2])>>2) );
462                    outdata[0][k] = data2[k2] + outdata[1][k];
463                    outdata[2][k] = data1[k1] + outdata[1][k];
464                }
465                // Jump to beggining of previous line in input
466                k0 -= block0.scanw - w;
467                k1 -= block1.scanw - w;
468                k2 -= block2.scanw - w;
469            }
470            outdata[c] = null;
471        }
472        else if((c>=0)&&(c<=3)){ //Asking for the 2nd or 3rd block component
473            blk.setData(outdata[c]);
474            blk.progressive = dbi.progressive;
475            blk.offset = (blk.uly-dbi.uly)*dbi.w+blk.ulx-dbi.ulx;
476            blk.scanw = dbi.w;
477            outdata[c] = null;
478        }
479        else {
480            // Requesting a non valid component index
481            throw new IllegalArgumentException();
482        }
483        return blk;
484    }
485
486    /**
487     * Apply inverse irreversible component transformation to obtain requested
488     * component from specified block of data. Whatever the type of requested
489     * DataBlk, it always returns a DataBlkFloat.
490     *
491     * @param blk Determine the rectangular area to return
492     *
493     * @param c The index of the requested component
494     *
495     * @return Data of requested component
496     * */
497    private DataBlk invICT(DataBlk blk,int c){
498        if(c>=3 && c<getNumComps()) {
499            // Requesting a component whose index is greater than 3            
500            int k,k0,k1,k2,mink,i;
501            int w = blk.w; //width of output block
502            int h = blk.h; //height of ouput block
503
504            int outdata[]; // array of output data
505
506            //Reference to output block data array
507            outdata = (int[]) blk.getData();
508
509            //Create data array of blk if necessary
510            if( outdata == null ) {
511                outdata = new int[h * w];
512                blk.setData(outdata);
513            }
514
515            // Variables
516            DataBlkFloat indb = new DataBlkFloat(blk.ulx,blk.uly,w,h);
517            float indata[]; // input data array
518
519            // Get the input data
520            // (returned block may be larger than requested one)
521            src.getInternCompData(indb,c);
522            indata = (float[]) indb.getData();
523
524            // Copy the data converting from int to int
525            k = w*h-1;
526            k0 = indb.offset+(h-1)*indb.scanw+w-1;
527            for (i=h-1; i >=0; i--) {
528                for (mink = k-w; k > mink; k--, k0--) {
529                    outdata[k] = (int) (indata[k0]);
530                }
531                // Jump to beggining of previous line in input
532                k0 -= indb.scanw - w;
533            }
534
535            // Set the progressivity and offset
536            blk.progressive = indb.progressive;
537            blk.offset = 0;
538            blk.scanw = w;
539        }
540
541        // If asking a component for the first time for this block,
542        // do transform for the 3 components
543        else if((outdata[c] == null)||
544            (dbi.ulx > blk.ulx) || (dbi.uly > blk.uly) ||
545            (dbi.ulx+dbi.w < blk.ulx+blk.w) ||
546            (dbi.uly+dbi.h < blk.uly+blk.h)) {
547            int k,k0,k1,k2,mink,i;
548            int w = blk.w; //width of output block
549            int h = blk.h; //height of ouput block
550
551            //Reference to output block data array
552            outdata[c] = (int[]) blk.getData();
553
554            //Create data array of blk if necessary
555            if(outdata[c] == null || outdata[c].length!=w*h){
556                outdata[c] = new int[h * w];
557                blk.setData(outdata[c]);
558            }
559
560            outdata[(c+1)%3] = new int[outdata[c].length];
561            outdata[(c+2)%3] = new int[outdata[c].length];
562
563            if(block0==null || block0.getDataType()!=DataBlk.TYPE_FLOAT)
564                block0 = new DataBlkFloat();
565            if(block2==null || block2.getDataType()!=DataBlk.TYPE_FLOAT)
566                block2 = new DataBlkFloat();
567            if(block1==null || block1.getDataType()!=DataBlk.TYPE_FLOAT)
568                block1 = new DataBlkFloat();
569            block0.w = block2.w = block1.w = blk.w;
570            block0.h = block2.h = block1.h = blk.h;
571            block0.ulx = block2.ulx = block1.ulx = blk.ulx;
572            block0.uly = block2.uly = block1.uly = blk.uly;
573
574            float data0[],data1[],data2[]; // input data arrays
575
576            // Fill in buffer blocks (to be read only)
577            // Returned blocks may have different size and position
578            block0 = (DataBlkFloat)src.getInternCompData(block0, 0);
579            data0  = (float[]) block0.getData();
580            block2 = (DataBlkFloat)src.getInternCompData(block2, 1);
581            data2 = (float[]) block2.getData();
582            block1 = (DataBlkFloat)src.getInternCompData(block1, 2);
583            data1 = (float[]) block1.getData();
584
585            // Set the progressiveness of the output data
586            blk.progressive = block0.progressive || block1.progressive ||
587                block2.progressive;
588            blk.offset = 0;
589            blk.scanw = w;
590
591            // set attributes of the DataBlk used for buffering
592            dbi.progressive = blk.progressive;
593            dbi.ulx = blk.ulx;
594            dbi.uly = blk.uly;
595            dbi.w = blk.w;
596            dbi.h = blk.h;
597
598            //Perform conversion
599
600            // Initialize general indexes
601            k = w*h-1;
602            k0 = block0.offset+(h-1)*block0.scanw+w-1;
603            k2 = block2.offset+(h-1)*block2.scanw+w-1;
604            k1 = block1.offset+(h-1)*block1.scanw+w-1;
605
606            for( i = h-1; i >=0; i--){
607                for(mink = k-w; k > mink; k--, k0--, k2--, k1--){
608                    outdata[0][k] = (int)(data0[k0]+1.402f*data1[k1]+0.5f);
609                    outdata[1][k] =
610                        (int) (data0[k0]-0.34413f*data2[k2]-0.71414f*data1[k1]
611                               + 0.5f);
612                    outdata[2][k] = (int)(data0[k0]+1.772f*data2[k2]+0.5f);
613                }
614                // Jump to beggining of previous line in input
615                k0 -= block0.scanw - w;
616                k2 -= block2.scanw - w;
617                k1 -= block1.scanw - w;
618            }
619            outdata[c] = null;
620        }
621        else if((c>=0)&&(c<=3)){//Asking for the 2nd or 3rd block component
622            blk.setData(outdata[c]);
623            blk.progressive = dbi.progressive;
624            blk.offset = (blk.uly-dbi.uly)*dbi.w+blk.ulx-dbi.ulx;
625            blk.scanw = dbi.w;
626            outdata[c] = null;
627        } else {
628            // Requesting a non valid component index
629            throw new IllegalArgumentException();
630        }
631        return blk;
632    }
633
634        /**
635     * Changes the current tile, given the new indexes. An
636     * IllegalArgumentException is thrown if the indexes do not
637     * correspond to a valid tile.
638     *
639     * <P>This default implementation changes the tile in the source
640     * and re-initializes properly component transformation variables..
641     *
642     * @param x The horizontal index of the tile.
643     *
644     * @param y The vertical index of the new tile.
645     *
646     * */
647    public void setTile(int x, int y) {
648        src.setTile(x,y);
649        tIdx = getTileIdx(); // index of the current tile
650
651        // initializations
652        if( ((Integer)cts.getTileDef(tIdx)).intValue()==NONE )
653            transfType = NONE;
654        else {
655            int nc = src.getNumComps()> 3 ? 3 : src.getNumComps();
656            int rev = 0;
657            for(int c=0; c<nc; c++)
658                rev += (wfs.isReversible(tIdx,c)?1:0);
659            if(rev==3){
660                // All WT are reversible
661                transfType = INV_RCT;
662            }
663            else if(rev==0){
664                // All WT irreversible
665                transfType = INV_ICT;
666            }
667            else{
668                // Error
669                throw new IllegalArgumentException("Wavelet transformation and "+
670                                                   "component transformation"+
671                                                   " not coherent in tile"+tIdx);
672            }
673        }
674    }
675
676    /**
677     * Advances to the next tile, in standard scan-line order (by rows
678     * then columns). An NoNextElementException is thrown if the
679     * current tile is the last one (i.e. there is no next tile).
680     *
681     * <P>This default implementation just advances to the next tile
682     * in the source and re-initializes properly component
683     * transformation variables.
684     *
685     * */
686    public void nextTile() {
687        src.nextTile();
688        tIdx = getTileIdx(); // index of the current tile
689
690        // initializations
691        if( ((Integer)cts.getTileDef(tIdx)).intValue()==NONE )
692            transfType = NONE;
693        else {
694            int nc = src.getNumComps() > 3 ? 3 : src.getNumComps();
695            int rev = 0;
696            for(int c=0; c<nc; c++)
697                rev += (wfs.isReversible(tIdx,c)?1:0);
698            if(rev==3){
699                // All WT are reversible
700                transfType = INV_RCT;
701            }
702            else if(rev==0){
703                // All WT irreversible
704                transfType = INV_ICT;
705            }
706            else{
707                // Error
708                throw new IllegalArgumentException("Wavelet transformation and "+
709                                                   "component transformation"+
710                                                   " not coherent in tile"+tIdx);
711            }
712        }
713    }
714
715}
716