001/*
002 * $RCSfile: ForwCompTransfSpec.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:13 $
005 * $State: Exp $
006 *
007 * Class:                   ForwCompTransfSpec
008 *
009 * Description:             Component Transformation specification for encoder
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 java.util.StringTokenizer;
047
048import jj2000.j2k.image.CompTransfSpec;
049import jj2000.j2k.wavelet.FilterTypes;
050import jj2000.j2k.wavelet.analysis.AnWTFilter;
051import jj2000.j2k.wavelet.analysis.AnWTFilterSpec;
052
053import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava;
054/**
055 * This class extends CompTransfSpec class in order to hold encoder specific
056 * aspects of CompTransfSpec.
057 *
058 * @see CompTransfSpec
059 * */
060public class ForwCompTransfSpec extends CompTransfSpec implements FilterTypes {
061    private String defaultValue = null;
062
063    /**
064     * Constructs a new 'ForwCompTransfSpec' for the specified number of
065     * components and tiles and the arguments of <tt>optName</tt>
066     * option. This constructor is called by the encoder. It also
067     * checks that the arguments belongs to the recognized arguments
068     * list.
069     *
070     * <P>This constructor chose the component transformation type
071     * depending on the wavelet filters : RCT with w5x3 filter and ICT
072     * with w9x7 filter. Note: All filters must use the same data
073     * type.
074     *
075     * @param nt The number of tiles
076     *
077     * @param nc The number of components
078     *
079     * @param type the type of the specification module i.e. tile specific,
080     * component specific or both.
081     *
082     * @param wfs The wavelet filter specifications
083     * */
084    public ForwCompTransfSpec(int nt, int nc, byte type, AnWTFilterSpec wfs,
085                              J2KImageWriteParamJava wp, String values){
086        super(nt,nc,type);
087
088        String param = values;
089        specified = values;
090        if(values==null){
091            // If less than three component, do not use any component
092            // transformation
093            if(nc<3) {
094                setDefault("none");
095                return;
096            }
097            // If the compression is lossless, uses RCT
098            else if(wp.getLossless()) {
099                setDefault("rct");
100                return;
101            } else {
102                AnWTFilter[][] anfilt;
103                int[] filtType = new int[nComp];
104                for(int c=0; c<3; c++) {
105                    anfilt = (AnWTFilter[][])wfs.getCompDef(c);
106                    filtType[c] = anfilt[0][0].getFilterType();
107                }
108
109                // Check that the three first components use the same filters
110                boolean reject = false;
111                for(int c=1; c<3; c++){
112                    if(filtType[c]!=filtType[0]) reject = true;
113                }
114
115                if(reject) {
116                    setDefault("none");
117                } else {
118                    anfilt = (AnWTFilter[][])wfs.getCompDef(0);
119                    if(anfilt[0][0].getFilterType()==W9X7) {
120                        setDefault("ict");
121                    } else {
122                        setDefault("rct");
123                    }
124                }
125            }
126
127            // Each tile receives a component transform specification
128            // according the type of wavelet filters that are used by the
129            // three first components
130            for(int t=0; t<nt; t++) {
131                AnWTFilter[][] anfilt;
132                int[] filtType = new int[nComp];
133                for(int c=0; c<3; c++) {
134                    anfilt = (AnWTFilter[][])wfs.getTileCompVal(t,c);
135                    filtType[c] = anfilt[0][0].getFilterType();
136                }
137
138                // Check that the three components use the same filters
139                boolean reject = false;
140                for(int c=1; c<nComp;c++){
141                    if(filtType[c]!=filtType[0])
142                        reject = true;
143                }
144
145                if(reject) {
146                    setTileDef(t,"none");
147                } else {
148                    anfilt = (AnWTFilter[][])wfs.getTileCompVal(t,0);
149                    if(anfilt[0][0].getFilterType()==W9X7) {
150                        setTileDef(t,"ict");
151                    } else {
152                        setTileDef(t,"rct");
153                    }
154                }
155            }
156            return;
157        }
158
159        if (param.equalsIgnoreCase("true"))
160            param = "on";
161        // Parse argument
162        StringTokenizer stk = new StringTokenizer(param);
163        String word; // current word
164        byte curSpecType = SPEC_DEF; // Specification type of the
165        // current parameter
166        boolean[] tileSpec = null; // Tiles concerned by the
167        // specification
168        Boolean value;
169
170        while(stk.hasMoreTokens()){
171            word = stk.nextToken();
172
173            switch(word.charAt(0)){
174            case 't': // Tiles specification
175                tileSpec = parseIdx(word,nTiles);
176                if(curSpecType==SPEC_COMP_DEF) {
177                    curSpecType = SPEC_TILE_COMP;
178                } else {
179                    curSpecType = SPEC_TILE_DEF;
180                }
181                break;
182            case 'c': // Components specification
183                throw new IllegalArgumentException("Component specific "+
184                                                   " parameters"+
185                                                   " not allowed with "+
186                                                   "'-Mct' option");
187            default:
188                if(word.equals("off")) {
189                    if(curSpecType==SPEC_DEF) {
190                        setDefault("none");
191                    } else if(curSpecType==SPEC_TILE_DEF) {
192                        for(int i=tileSpec.length-1; i>=0; i--)
193                            if(tileSpec[i]) {
194                                setTileDef(i,"none");
195                            }
196                    }
197                } else if(word.equals("on")) {
198                    if(nc<3) {
199                        setDefault("none");
200                        break;
201                    }
202
203                    if(curSpecType==SPEC_DEF) { // Set arbitrarily the default
204                        // value to RCT (later will be found the suitable
205                        // component transform for each tile)
206                        setDefault("rct");
207                    } else if (curSpecType==SPEC_TILE_DEF) {
208                        for(int i=tileSpec.length-1; i>=0; i--) {
209                            if(tileSpec[i]) {
210                                if(getFilterType(i,wfs)==W5X3) {
211                                    setTileDef(i,"rct");
212                                } else {
213                                    setTileDef(i,"ict");
214                                }
215                            }
216                        }
217                    }
218                } else {
219                    throw new IllegalArgumentException("Default parameter of "+
220                                                       "option Mct not"+
221                                                       " recognized: "+param);
222                }
223
224                // Re-initialize
225                curSpecType = SPEC_DEF;
226                tileSpec = null;
227                break;
228            }
229        }
230
231        // Check that default value has been specified
232        if(getDefault()==null) {
233            // If not, set arbitrarily the default value to 'none' but
234            // specifies explicitely a default value for each tile depending
235            // on the wavelet transform that is used
236            setDefault("none");
237
238            for(int t=0; t<nt; t++) {
239                if(isTileSpecified(t)) {
240                    continue;
241                }
242
243                AnWTFilter[][] anfilt;
244                int[] filtType = new int[nComp];
245                for(int c=0; c<3; c++) {
246                    anfilt = (AnWTFilter[][])wfs.getTileCompVal(t,c);
247                    filtType[c] = anfilt[0][0].getFilterType();
248                }
249
250                // Check that the three components use the same filters
251                boolean reject = false;
252                for(int c=1; c<nComp;c++){
253                    if(filtType[c]!=filtType[0])
254                        reject = true;
255                }
256
257                if(reject) {
258                    setTileDef(t,"none");
259                } else {
260                    anfilt = (AnWTFilter[][])wfs.getTileCompVal(t,0);
261                    if(anfilt[0][0].getFilterType()==W9X7) {
262                        setTileDef(t,"ict");
263                    } else {
264                        setTileDef(t,"rct");
265                    }
266                }
267            }
268        }
269
270        // Check validity of component transformation of each tile compared to
271        // the filter used.
272        for(int t=nt-1; t>=0; t--) {
273
274            if(((String)getTileDef(t)).equals("none")) {
275                // No comp. transf is used. No check is needed
276                continue;
277            }
278            else if(((String)getTileDef(t)).equals("rct")) {
279                // Tile is using Reversible component transform
280                int filterType = getFilterType(t,wfs);
281                switch(filterType){
282                case FilterTypes.W5X3: // OK
283                    break;
284                case FilterTypes.W9X7: // Must use ICT
285                    if(isTileSpecified(t)){
286                        // User has requested RCT -> Error
287                        throw new IllegalArgumentException("Cannot use RCT "+
288                                                           "with 9x7 filter "+
289                                                           "in tile "+t);
290                    }
291                    else{ // Specify ICT for this tile
292                        setTileDef(t,"ict");
293                    }
294                    break;
295                default:
296                    throw new IllegalArgumentException("Default filter is "+
297                                                       "not JPEG 2000 part"+
298                                                       " I compliant");
299                }
300            } else { // ICT
301                int filterType = getFilterType(t,wfs);
302                switch(filterType) {
303                case FilterTypes.W5X3: // Must use RCT
304                    if(isTileSpecified(t)){
305                        // User has requested ICT -> Error
306                        throw new IllegalArgumentException("Cannot use ICT "+
307                                                           "with filter 5x3 "+
308                                                           "in tile "+t);
309                    }
310                    else{
311                        setTileDef(t,"rct");
312                    }
313                    break;
314                case FilterTypes.W9X7: // OK
315                    break;
316                default:
317                    throw new IllegalArgumentException("Default filter is "+
318                                                       "not JPEG 2000 part"+
319                                                       " I compliant");
320
321                }
322            }
323        }
324    }
325
326    /** Get the filter type common to all component of a given tile. If the
327     * tile index is -1, it searches common filter type of default
328     * specifications.
329     *
330     * @param t The tile index
331     *
332     * @param wfs The analysis filters specifications
333     *
334     * @return The filter type common to all the components
335     *
336     */
337    private int getFilterType(int t, AnWTFilterSpec wfs){
338        AnWTFilter[][] anfilt;
339        int[] filtType = new int[nComp];
340        for(int c=0;c<nComp; c++){
341            if(t==-1)
342                anfilt = (AnWTFilter[][])wfs.getCompDef(c);
343            else
344                anfilt = (AnWTFilter[][])wfs.getTileCompVal(t,c);
345            filtType[c] = anfilt[0][0].getFilterType();
346        }
347
348        // Check that all filters are the same one
349        boolean reject = false;
350        for(int c=1; c<nComp;c++){
351            if(filtType[c]!=filtType[0])
352                reject = true;
353        }
354        if(reject){
355            throw new IllegalArgumentException("Can not use component"+
356                                               " transformation when "+
357                                               "components do not use "+
358                                               "the same filters");
359        }
360        return filtType[0];
361    }
362}