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