001/*
002 * $RCSfile: ForwCompTransf.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:13 $
005 * $State: Exp $
006 *
007 * Class:               ForwCompTransf
008 *
009 * Description:         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.forwcomptransf;
045
046import jj2000.j2k.ModuleSpec;
047import jj2000.j2k.image.BlkImgDataSrc;
048import jj2000.j2k.image.CompTransfSpec;
049import jj2000.j2k.image.DataBlk;
050import jj2000.j2k.image.DataBlkFloat;
051import jj2000.j2k.image.DataBlkInt;
052import jj2000.j2k.image.ImgDataAdapter;
053import jj2000.j2k.util.MathUtil;
054import jj2000.j2k.wavelet.analysis.AnWTFilterSpec;
055
056import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava;
057/**
058 * This class apply component transformations to the tiles depending
059 * on user specifications. These transformations can be used to
060 * improve compression efficiency but are not related to colour
061 * transforms used to map colour values for display purposes. JPEG
062 * 2000 part I defines 2 component transformations: RCT (Reversible
063 * Component Transformation) and ICT (Irreversible Component
064 * Transformation).
065 *
066 * @see ModuleSpec
067 * */
068public class ForwCompTransf extends ImgDataAdapter
069    implements BlkImgDataSrc {
070
071    /** Identifier for no component transformation. Value is 0. */
072    public static final int NONE = 0;
073
074    /** Identifier for the Forward Reversible Component Transformation
075        (FORW_RCT). Value is 1. */
076    public static final int FORW_RCT = 1;
077
078    /** Identifier for the Forward Irreversible Component
079        Transformation (FORW_ICT). Value is 2 */
080    public static final int FORW_ICT = 2;
081
082    /** The source of image data */
083    private BlkImgDataSrc src;
084
085    /** The component transformations specifications */
086    private CompTransfSpec cts;
087
088    /** The wavelet filter specifications */
089    private AnWTFilterSpec wfs;
090
091    /** The type of the current component transformation JPEG 2000
092     * part I only support NONE, FORW_RCT and FORW_ICT types*/
093    private int transfType = NONE;
094
095    /** The bit-depths of transformed components */
096    private int tdepth[];
097
098    /** Output block used instead of the one provided as an argument
099        if the later is DataBlkFloat.*/
100    private DataBlk outBlk;
101
102    /** Block used to request component with index 0 */
103    private DataBlkInt block0;
104
105    /** Block used to request component with index 1*/
106    private DataBlkInt block1;
107
108    /** Block used to request component with index 2*/
109    private DataBlkInt block2;
110
111     /**
112     * Constructs a new ForwCompTransf object that operates on the
113     * specified source of image data.
114     *
115     * @param imgSrc The source from where to get the data to be
116     * transformed
117     *
118     * @param encSpec The encoder specifications
119     *
120     * @see BlkImgDataSrc
121     * */
122    public ForwCompTransf(BlkImgDataSrc imgSrc, J2KImageWriteParamJava wp) {
123        super(imgSrc);
124        this.cts = wp.getComponentTransformation();
125        this.wfs = wp.getFilters();
126        src = imgSrc;
127    }
128
129    /** The prefix for component transformation type: 'M' */
130    public final static char OPT_PREFIX = 'M';
131
132    /** The list of parameters that is accepted by the forward
133     * component transformation module. Options start with an 'M'. */
134    private final static String [][] pinfo = {
135        { "Mct", "[<tile index>] [true|false] ...",
136          "Specifies to use component transformation with some tiles. "+
137          " If the wavelet transform is reversible (w5x3 filter), the "+
138          "Reversible Component Transformation (RCT) is applied. If not "+
139          "(w9x7 filter), the Irreversible Component Transformation (ICT)"+
140          " is used.", null},
141    };
142
143    /**
144     * Returns the position of the fixed point in the specified
145     * component. This is the position of the least significant integral
146     * (i.e. non-fractional) bit, which is equivalent to the number of
147     * fractional bits. For instance, for fixed-point values with 2 fractional
148     * bits, 2 is returned. For floating-point data this value does not apply
149     * and 0 should be returned. Position 0 is the position of the least
150     * significant bit in the data.
151     *
152     * <P>This default implementation assumes that the number of
153     * fractional bits is not modified by the component mixer.
154     *
155     * @param c The index of the component.
156     *
157     * @return The value of the fixed point position of the source
158     * since the color transform does not affect it.
159     * */
160     public int getFixedPoint(int c){
161         return src.getFixedPoint(c);
162     }
163
164    /**
165     * Returns the parameters that are used in this class and implementing
166     * classes. It returns a 2D String array. Each of the 1D arrays is for a
167     * different option, and they have 4 elements. The first element is the
168     * option name, the second one is the synopsis, the third one is a long
169     * description of what the parameter is and the fourth is its default
170     * value. The synopsis or description may be 'null', in which case it is
171     * assumed that there is no synopsis or description of the option,
172     * respectively. Null may be returned if no options are supported.
173     *
174     * @return the options name, their synopsis and their explanation,
175     * or null if no options are supported.
176     * */
177    public static String[][] getParameterInfo(){
178        return pinfo;
179    }
180
181    /**
182     * Calculates the bitdepths of the transformed components, given the
183     * bitdepth of the un-transformed components and the component
184     * tranformation type.
185     *
186     * @param ntdepth The bitdepth of each non-transformed components.
187     *
188     * @param ttype The type ID of the component transformation.
189     *
190     * @param tdepth If not null the results are stored in this
191     * array, otherwise a new array is allocated and returned.
192     *
193     * @return The bitdepth of each transformed component.
194     * */
195    public static
196        int[] calcMixedBitDepths(int ntdepth[], int ttype, int tdepth[]) {
197
198        if (ntdepth.length < 3 && ttype != NONE) {
199            throw new IllegalArgumentException();
200        }
201
202        if (tdepth == null) {
203            tdepth = new int[ntdepth.length];
204        }
205
206        switch (ttype) {
207        case NONE:
208            System.arraycopy(ntdepth,0,tdepth,0,ntdepth.length);
209            break;
210        case FORW_RCT:
211            if (ntdepth.length >3) {
212                System.arraycopy(ntdepth,3,tdepth,3,ntdepth.length-3);
213            }
214            // The formulas are:
215            // tdepth[0] = ceil(log2(2^(ntdepth[0])+2^ntdepth[1]+
216            //                        2^(ntdepth[2])))-2+1
217            // tdepth[1] = ceil(log2(2^(ntdepth[1])+2^(ntdepth[2])-1))+1
218            // tdepth[2] = ceil(log2(2^(ntdepth[0])+2^(ntdepth[1])-1))+1
219            // The MathUtil.log2(x) function calculates floor(log2(x)), so we
220            // use 'MathUtil.log2(2*x-1)+1', which calculates ceil(log2(x))
221            // for any x>=1, x integer.
222            tdepth[0] = MathUtil.log2((1<<ntdepth[0])+(2<<ntdepth[1])+
223                                      (1<<ntdepth[2])-1)-2+1;
224            tdepth[1] = MathUtil.log2((1<<ntdepth[2])+(1<<ntdepth[1])-1)+1;
225            tdepth[2] = MathUtil.log2((1<<ntdepth[0])+(1<<ntdepth[1])-1)+1;
226            break;
227        case FORW_ICT:
228            if (ntdepth.length >3) {
229                System.arraycopy(ntdepth,3,tdepth,3,ntdepth.length-3);
230            }
231            // The MathUtil.log2(x) function calculates floor(log2(x)), so we
232            // use 'MathUtil.log2(2*x-1)+1', which calculates ceil(log2(x))
233            // for any x>=1, x integer.
234            tdepth[0] =
235                MathUtil.log2((int)Math.floor((1<<ntdepth[0])*0.299072+
236                                              (1<<ntdepth[1])*0.586914+
237                                              (1<<ntdepth[2])*0.114014)-1)+1;
238            tdepth[1] =
239                MathUtil.log2((int)Math.floor((1<<ntdepth[0])*0.168701+
240                                              (1<<ntdepth[1])*0.331299+
241                                              (1<<ntdepth[2])*0.5)-1)+1;
242            tdepth[2] =
243                MathUtil.log2((int)Math.floor((1<<ntdepth[0])*0.5+
244                                              (1<<ntdepth[1])*0.418701+
245                                              (1<<ntdepth[2])*0.081299)-1)+1;
246            break;
247        }
248
249        return tdepth;
250    }
251
252    /**
253     * Initialize some variables used with RCT. It must be called, at least,
254     * at the beginning of each new tile.
255     * */
256    private void initForwRCT(){
257        int i;
258        int tIdx = getTileIdx();
259
260        if (src.getNumComps() < 3) {
261            throw new IllegalArgumentException();
262        }
263        // Check that the 3 components have the same dimensions
264        if (src.getTileCompWidth(tIdx, 0) != src.getTileCompWidth(tIdx, 1) ||
265            src.getTileCompWidth(tIdx, 0) != src.getTileCompWidth(tIdx, 2) ||
266            src.getTileCompHeight(tIdx, 0) != src.getTileCompHeight(tIdx, 1) ||
267            src.getTileCompHeight(tIdx, 0) != src.getTileCompHeight(tIdx, 2)) {
268            throw new IllegalArgumentException("Can not use RCT "+
269                                               "on components with different "+
270                                               "dimensions");
271        }
272        // Initialize bitdepths
273        int utd[]; // Premix bitdepths
274        utd = new int[src.getNumComps()];
275        for (i=utd.length-1; i>=0; i--) {
276            utd[i] = src.getNomRangeBits(i);
277        }
278        tdepth = calcMixedBitDepths(utd,FORW_RCT,null);
279    }
280
281    /**
282     * Initialize some variables used with ICT. It must be called, at least,
283     * at the beginning of a new tile.
284     * */
285    private void initForwICT(){
286        int i;
287        int tIdx = getTileIdx();
288
289        if (src.getNumComps() < 3) {
290            throw new IllegalArgumentException();
291        }
292        // Check that the 3 components have the same dimensions
293        if (src.getTileCompWidth(tIdx, 0) != src.getTileCompWidth(tIdx, 1) ||
294            src.getTileCompWidth(tIdx, 0) != src.getTileCompWidth(tIdx, 2) ||
295            src.getTileCompHeight(tIdx, 0) != src.getTileCompHeight(tIdx, 1) ||
296            src.getTileCompHeight(tIdx, 0) != src.getTileCompHeight(tIdx, 2)) {
297            throw new IllegalArgumentException("Can not use ICT "+
298                                               "on components with different "+
299                                               "dimensions");
300        }
301        // Initialize bitdepths
302        int utd[]; // Premix bitdepths
303        utd = new int[src.getNumComps()];
304        for (i=utd.length-1; i>=0; i--) {
305            utd[i] = src.getNomRangeBits(i);
306        }
307        tdepth = calcMixedBitDepths(utd,FORW_ICT,null);
308    }
309
310    /**
311     * Returns a string with a descriptive text of which forward component
312     * transformation is used. This can be either "Forward RCT" or "Forward
313     * ICT" or "No component transformation" depending on the current tile.
314     *
315     * @return A descriptive string
316     * */
317    public String toString() {
318        switch(transfType){
319        case FORW_RCT:
320            return "Forward RCT";
321        case FORW_ICT:
322            return "Forward ICT";
323        case NONE:
324            return "No component transformation";
325        default:
326            throw new IllegalArgumentException("Non JPEG 2000 part I"+
327                                               " component transformation");
328        }
329    }
330
331    /**
332     * Returns the number of bits, referred to as the "range bits",
333     * corresponding to the nominal range of the data in the specified
334     * component and in the current tile. If this number is <i>b</i> then for
335     * unsigned data the nominal range is between 0 and 2^b-1, and for signed
336     * data it is between -2^(b-1) and 2^(b-1)-1. Note that this value can be
337     * affected by the multiple component transform.
338     *
339     * @param c The index of the component.
340     *
341     * @return The bitdepth of component 'c' after mixing.
342     * */
343    public int getNomRangeBits(int c) {
344        switch(transfType){
345        case FORW_RCT:
346        case FORW_ICT:
347            return tdepth[c];
348        case NONE:
349            return src.getNomRangeBits(c);
350        default:
351            throw new IllegalArgumentException("Non JPEG 2000 part I"+
352                                               " component transformation");
353        }
354    }
355
356    /**
357     * Returns true if this transform is reversible in current
358     * tile. Reversible component transformations are those which operation
359     * can be completely reversed without any loss of information (not even
360     * due to rounding).
361     *
362     * @return Reversibility of component transformation in current tile
363     * */
364    public boolean isReversible(){
365        switch(transfType){
366        case NONE:
367        case FORW_RCT:
368            return true;
369        case FORW_ICT:
370            return false;
371        default:
372            throw new IllegalArgumentException("Non JPEG 2000 part I"+
373                                               " component transformation");
374        }
375    }
376
377    /**
378     * Apply forward component transformation associated with the current
379     * tile. If no component transformation has been requested by the user,
380     * data are not modified.
381     *
382     * <P>This method calls the getInternCompData() method, but respects the
383     * definitions of the getCompData() method defined in the BlkImgDataSrc
384     * interface.
385     *
386     * @param blk Determines the rectangular area to return, and the
387     * data is returned in this object.
388     *
389     * @param c Index of the output component.
390     *
391     * @return The requested DataBlk
392     *
393     * @see BlkImgDataSrc#getCompData
394     * */
395    public DataBlk getCompData(DataBlk blk, int c){
396        // If requesting a component whose index is greater than 3 or there is
397        // no transform return a copy of data (getInternCompData returns the
398        // actual data in those cases)
399        if (c>=3 || transfType == NONE) {
400            return src.getCompData(blk,c);
401        }
402        else { // We can use getInternCompData (since data is a copy anyways)
403            return getInternCompData(blk,c);
404        }
405    }
406
407    /**
408     * Apply the component transformation associated with the current tile. If
409     * no component transformation has been requested by the user, data are
410     * not modified. Else, appropriate method is called (forwRCT or forwICT).
411     *
412     * @see #forwRCT
413     *
414     * @see #forwICT
415     *
416     * @param blk Determines the rectangular area to return.
417     *
418     * @param c Index of the output component.
419     *
420     * @return The requested DataBlk
421     * */
422    public DataBlk getInternCompData(DataBlk blk, int c){
423        switch(transfType){
424        case NONE:
425            return src.getInternCompData(blk,c);
426        case FORW_RCT:
427            return forwRCT(blk,c);
428        case FORW_ICT:
429            return forwICT(blk,c);
430        default:
431            throw new IllegalArgumentException("Non JPEG 2000 part I component"+
432                                               " transformation for tile: "+
433                                               tIdx);
434        }
435    }
436
437    /**
438     * Apply forward component transformation to obtain requested component
439     * from specified block of data. Whatever the type of requested DataBlk,
440     * it always returns a DataBlkInt.
441     *
442     * @param blk Determine the rectangular area to return
443     *
444     * @param c The index of the requested component
445     *
446     * @return Data of requested component
447     * */
448    private DataBlk forwRCT(DataBlk blk,int c){
449        int k,k0,k1,k2,mink,i;
450        int w = blk.w; //width of output block
451        int h = blk.h; //height of ouput block
452        int  outdata[]; //array of output data
453
454        //If asking for Yr, Ur or Vr do transform
455        if(c >= 0 && c <= 2) {
456            // Check that request data type is int
457            if(blk.getDataType()!=DataBlk.TYPE_INT){
458                if(outBlk==null || outBlk.getDataType() != DataBlk.TYPE_INT){
459                    outBlk = new DataBlkInt();
460                }
461                outBlk.w = w;
462                outBlk.h = h;
463                outBlk.ulx = blk.ulx;
464                outBlk.uly = blk.uly;
465                blk = outBlk;
466            }
467
468            //Reference to output block data array
469            outdata = (int[]) blk.getData();
470
471            //Create data array of blk if necessary
472            if(outdata == null || outdata.length<h*w) {
473                outdata = new int[h*w];
474                blk.setData(outdata);
475            }
476
477            // Block buffers for input RGB data
478            int data0[],data1[],bdata[]; // input data arrays
479
480            if(block0==null)
481                block0 = new DataBlkInt();
482            if(block1==null)
483                block1 = new DataBlkInt();
484            if(block2==null)
485                block2 = new DataBlkInt();
486            block0.w = block1.w = block2.w = blk.w;
487            block0.h = block1.h = block2.h = blk.h;
488            block0.ulx = block1.ulx = block2.ulx = blk.ulx;
489            block0.uly = block1.uly = block2.uly = blk.uly;
490
491            //Fill in buffer blocks (to be read only)
492            // Returned blocks may have different size and position
493            block0 = (DataBlkInt)src.getInternCompData(block0, 0);
494            data0 = (int[]) block0.getData();
495            block1 = (DataBlkInt)src.getInternCompData(block1, 1);
496            data1 = (int[]) block1.getData();
497            block2 = (DataBlkInt)src.getInternCompData(block2, 2);
498            bdata = (int[]) block2.getData();
499
500            // Set the progressiveness of the output data
501            blk.progressive = block0.progressive || block1.progressive ||
502                block2.progressive;
503            blk.offset = 0;
504            blk.scanw = w;
505
506            //Perform conversion
507
508            // Initialize general indexes
509            k = w*h-1;
510            k0 = block0.offset+(h-1)*block0.scanw+w-1;
511            k1 = block1.offset+(h-1)*block1.scanw+w-1;
512            k2 = block2.offset+(h-1)*block2.scanw+w-1;
513
514            switch(c) {
515            case 0: //RGB to Yr conversion
516                for (i = h-1; i >= 0; i--) {
517                    for (mink = k-w; k > mink; k--, k0--, k1--, k2--) {
518                        // Use int arithmetic with 12 fractional bits
519                        // and rounding
520                        outdata[k] =
521                            ( data0[k] + 2 * data1[k] + bdata[k]
522                              ) >> 2; // Same as / 4
523                    }
524                    // Jump to beggining of previous line in input
525                    k0 -= block0.scanw - w;
526                    k1 -= block1.scanw - w;
527                    k2 -= block2.scanw - w;
528                }
529                break;
530
531            case 1: //RGB to Ur conversion
532                for (i = h-1; i >= 0; i--) {
533                    for (mink = k-w; k > mink; k--, k1--, k2--) {
534                        // Use int arithmetic with 12 fractional bits
535                        // and rounding
536                        outdata[k] = bdata[k2] - data1[k1];
537                    }
538                    // Jump to beggining of previous line in input
539                    k1 -= block1.scanw - w;
540                    k2 -= block2.scanw - w;
541                }
542                break;
543
544            case 2:  //RGB to Vr conversion
545                for (i = h-1; i >= 0; i--) {
546                    for (mink = k-w; k > mink; k--, k0--, k1--) {
547                        // Use int arithmetic with 12 fractional bits
548                        // and rounding
549                        outdata[k] = data0[k0] - data1[k1];
550                    }
551                    // Jump to beggining of previous line in input
552                    k0 -= block0.scanw - w;
553                    k1 -= block1.scanw - w;
554                }
555                break;
556
557            }
558        }
559        else if (c >= 3) {
560            // Requesting a component which is not Y, Ur or Vr =>
561            // just pass the data
562            return src.getInternCompData(blk,c);
563        }
564        else {
565            // Requesting a non valid component index
566            throw new IllegalArgumentException();
567        }
568        return blk;
569
570    }
571
572    /**
573     * Apply forward irreversible component transformation to obtain requested
574     * component from specified block of data. Whatever the type of requested
575     * DataBlk, it always returns a DataBlkFloat.
576     *
577     * @param blk Determine the rectangular area to return
578     *
579     * @param c The index of the requested component
580     *
581     * @return Data of requested component
582     * */
583    private DataBlk forwICT(DataBlk blk,int c){
584        int k,k0,k1,k2,mink,i;
585        int w = blk.w; //width of output block
586        int h = blk.h; //height of ouput block
587        float  outdata[]; //array of output data
588
589        if(blk.getDataType()!=DataBlk.TYPE_FLOAT){
590            if(outBlk==null || outBlk.getDataType() != DataBlk.TYPE_FLOAT){
591                outBlk = new DataBlkFloat();
592            }
593            outBlk.w = w;
594            outBlk.h = h;
595            outBlk.ulx = blk.ulx;
596            outBlk.uly = blk.uly;
597            blk = outBlk;
598        }
599
600        //Reference to output block data array
601        outdata = (float[]) blk.getData();
602
603        //Create data array of blk if necessary
604        if(outdata == null || outdata.length<w*h) {
605            outdata = new float[h * w];
606            blk.setData(outdata);
607        }
608
609        //If asking for Y, Cb or Cr do transform
610        if(c>=0 && c<=2) {
611
612            int data0[],data1[],data2[]; // input data arrays
613
614            if(block0==null)
615                block0 = new DataBlkInt();
616            if(block1==null)
617                block1 = new DataBlkInt();
618            if(block2==null)
619                block2 = new DataBlkInt();
620            block0.w = block1.w = block2.w = blk.w;
621            block0.h = block1.h = block2.h = blk.h;
622            block0.ulx = block1.ulx = block2.ulx = blk.ulx;
623            block0.uly = block1.uly = block2.uly = blk.uly;
624
625            // Returned blocks may have different size and position
626            block0 = (DataBlkInt)src.getInternCompData(block0, 0);
627            data0 = (int[]) block0.getData();
628            block1 = (DataBlkInt)src.getInternCompData(block1, 1);
629            data1 = (int[]) block1.getData();
630            block2 = (DataBlkInt)src.getInternCompData(block2, 2);
631            data2 = (int[]) block2.getData();
632
633            // Set the progressiveness of the output data
634            blk.progressive = block0.progressive || block1.progressive ||
635                block2.progressive;
636            blk.offset = 0;
637            blk.scanw = w;
638
639            //Perform conversion
640
641            // Initialize general indexes
642            k = w*h-1;
643            k0 = block0.offset+(h-1)*block0.scanw+w-1;
644            k1 = block1.offset+(h-1)*block1.scanw+w-1;
645            k2 = block2.offset+(h-1)*block2.scanw+w-1;
646
647            switch(c) {
648            case 0:
649            //RGB to Y conversion
650                for (i = h-1; i >= 0; i--) {
651                    for (mink = k-w; k > mink; k--, k0--, k1--, k2--) {
652                        outdata[k] =
653                            0.299f * data0[k0]
654                            + 0.587f * data1[k1]
655                            + 0.114f * data2[k2];
656                    }
657                    // Jump to beggining of previous line in input
658                    k0 -= block0.scanw - w;
659                    k1 -= block1.scanw - w;
660                    k2 -= block2.scanw - w;
661                }
662                break;
663
664            case 1:
665            //RGB to Cb conversion
666                for (i = h-1; i >= 0; i--) {
667                    for (mink = k-w; k > mink; k--, k0--, k1--, k2--) {
668                        outdata[k] =
669                            - 0.16875f * data0[k0]
670                            - 0.33126f * data1[k1]
671                            + 0.5f * data2[k2];
672                    }
673                    // Jump to beggining of previous line in input
674                    k0 -= block0.scanw - w;
675                    k1 -= block1.scanw - w;
676                    k2 -= block2.scanw - w;
677                }
678                break;
679
680            case 2:
681            //RGB to Cr conversion
682                for (i = h-1; i >= 0; i--) {
683                    for (mink = k-w; k > mink; k--, k0--, k1--, k2--) {
684                        outdata[k] =
685                            0.5f * data0[k0]
686                            - 0.41869f * data1[k1]
687                            - 0.08131f * data2[k2];
688                    }
689                    // Jump to beggining of previous line in input
690                    k0 -= block0.scanw - w;
691                    k1 -= block1.scanw - w;
692                    k2 -= block2.scanw - w;
693                }
694                break;
695            }
696        }
697        else if(c>=3) {
698            // Requesting a component which is not Y, Cb or Cr =>
699            // just pass the data
700
701            // Variables
702            DataBlkInt indb = new DataBlkInt(blk.ulx,blk.uly,w,h);
703            int indata[]; // input data array
704
705            // Get the input data
706            // (returned block may be larger than requested one)
707            src.getInternCompData(indb,c);
708            indata = (int[]) indb.getData();
709
710            // Copy the data converting from int to float
711            k = w*h-1;
712            k0 = indb.offset+(h-1)*indb.scanw+w-1;
713            for (i=h-1; i>=0; i--) {
714                for (mink = k-w; k > mink; k--, k0--) {
715                    outdata[k] = (float) indata[k0];
716                }
717                // Jump to beggining of next line in input
718                k0 += indb.w - w;
719            }
720
721            // Set the progressivity
722            blk.progressive = indb.progressive;
723            blk.offset = 0;
724            blk.scanw = w;
725            return blk;
726        }
727        else {
728            // Requesting a non valid component index
729            throw new IllegalArgumentException();
730        }
731        return blk;
732
733    }
734
735    /**
736     * Changes the current tile, given the new indexes. An
737     * IllegalArgumentException is thrown if the indexes do not correspond to
738     * a valid tile.
739     *
740     * <P>This default implementation changes the tile in the source and
741     * re-initializes properly component transformation variables..
742     *
743     * @param x The horizontal index of the tile.
744     *
745     * @param y The vertical index of the new tile.
746     * */
747    public void setTile(int x, int y) {
748        src.setTile(x,y);
749        tIdx = getTileIdx(); // index of the current tile
750
751        // initializations
752        String str = (String)cts.getTileDef(tIdx);
753        if(str.equals("none")){
754            transfType = NONE;
755        }
756        else if(str.equals("rct")){
757            transfType = FORW_RCT;
758            initForwRCT();
759        }
760        else if(str.equals("ict")){
761            transfType = FORW_ICT;
762            initForwICT();
763        }
764        else{
765            throw new IllegalArgumentException("Component transformation"+
766                                               " not recognized");
767        }
768    }
769
770    /**
771     * Advances to the next tile, in standard scan-line order (by rows then
772     * columns). An NoNextElementException is thrown if the current tile is
773     * the last one (i.e. there is no next tile).
774     *
775     * <P>This default implementation just advances to the next tile in the
776     * source and re-initializes properly component transformation variables.
777     * */
778    public void nextTile() {
779        src.nextTile();
780        tIdx = getTileIdx(); // index of the current tile
781
782        // initializations
783        String str = (String)cts.getTileDef(tIdx);
784        if(str.equals("none")){
785            transfType = NONE;
786        }
787        else if(str.equals("rct")){
788            transfType = FORW_RCT;
789            initForwRCT();
790        }
791        else if(str.equals("ict")){
792            transfType = FORW_ICT;
793            initForwICT();
794        }
795        else{
796            throw new IllegalArgumentException("Component transformation"+
797                                               " not recognized");
798        }
799    }
800
801}