001/*
002 * $RCSfile: ProgressionSpec.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:05 $
005 * $State: Exp $
006 *
007 * Class:                   ProgressionSpec
008 *
009 * Description:             Specification of the progression(s) type(s) and
010 *                          changes of progression.
011 *
012 * COPYRIGHT:
013 *
014 * This software module was originally developed by Raphaël Grosbois and
015 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
016 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
017 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
018 * Centre France S.A) in the course of development of the JPEG2000
019 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
020 * software module is an implementation of a part of the JPEG 2000
021 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
022 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
023 * Partners) agree not to assert against ISO/IEC and users of the JPEG
024 * 2000 Standard (Users) any of their rights under the copyright, not
025 * including other intellectual property rights, for this software module
026 * with respect to the usage by ISO/IEC and Users of this software module
027 * or modifications thereof for use in hardware or software products
028 * claiming conformance to the JPEG 2000 Standard. Those intending to use
029 * this software module in hardware or software products are advised that
030 * their use may infringe existing patents. The original developers of
031 * this software module, JJ2000 Partners and ISO/IEC assume no liability
032 * for use of this software module or modifications thereof. No license
033 * or right to this software module is granted for non JPEG 2000 Standard
034 * conforming products. JJ2000 Partners have full right to use this
035 * software module for his/her own purpose, assign or donate this
036 * software module to any third party and to inhibit third parties from
037 * using this software module for non JPEG 2000 Standard conforming
038 * products. This copyright notice must be included in all copies or
039 * derivative works of this software module.
040 *
041 * Copyright (c) 1999/2000 JJ2000 Partners.
042 *  */
043package jj2000.j2k.entropy;
044
045import java.util.StringTokenizer;
046import java.util.Vector;
047
048import jj2000.j2k.IntegerSpec;
049import jj2000.j2k.ModuleSpec;
050import jj2000.j2k.codestream.ProgressionType;
051
052import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava;
053
054/**
055 * This class extends ModuleSpec class for progression type(s) and progression
056 * order changes holding purposes.
057 *
058 * <P>It stores the progression type(s) used in the codestream. There can be
059 * only one progression type or several ones if progression order changes are
060 * used (POC markers).
061 * */
062public class ProgressionSpec extends ModuleSpec {
063
064    /**
065     * Creates a new ProgressionSpec object for the specified number of tiles
066     * and components.
067     *
068     * @param nt The number of tiles
069     *
070     * @param nc The number of components
071     *
072     * @param type the type of the specification module i.e. tile specific,
073     * component specific or both. The ProgressionSpec class should only be
074     * used only with the type ModuleSpec.SPEC_TYPE_TILE.
075     * */
076    public ProgressionSpec(int nt, int nc, byte type) {
077        super(nt, nc, type);
078        if ( type !=  ModuleSpec.SPEC_TYPE_TILE ) {
079            throw new Error("Illegal use of class ProgressionSpec !");
080        }
081    }
082
083    /**
084     * Creates a new ProgressionSpec object for the specified number of
085     * tiles, components and the J2KImageWriteParamJava instance.
086     *
087     * @param nt The number of tiles
088     *
089     * @param nc The number of components
090     *
091     * @param nl The number of layer
092     *
093     * @param dls The number of decomposition levels specifications
094     *
095     * @param type the type of the specification module. The ProgressionSpec
096     * class should only be used only with the type ModuleSpec.SPEC_TYPE_TILE.
097     *
098     * @param wp The J2KImageWriteParamJava instance
099     * */
100    public ProgressionSpec(int nt,int nc,int nl,IntegerSpec dls,byte type,
101                           J2KImageWriteParamJava wp, String values){
102        super(nt,nc,type);
103
104        specified = values;
105
106        String param  = values;
107        Progression[] prog;
108        int mode=-1;
109
110        if(values == null){ // No parameter specified
111            if(wp.getROIs() == null) {
112                mode = checkProgMode("res");
113            }
114            else {
115                mode = checkProgMode("layer");
116            }
117
118            if(mode==-1){
119                String errMsg = "Unknown progression type : '"+param+"'";
120                throw new IllegalArgumentException(errMsg);
121            }
122            prog = new Progression[1];
123            prog[0] = new Progression(mode,0,nc,0,dls.getMax()+1,nl);
124            setDefault(prog);
125            return;
126        }
127
128        StringTokenizer stk = new StringTokenizer(param);
129        byte curSpecType = SPEC_DEF; // Specification type of the
130                                     // current parameter
131        boolean[] tileSpec = null; // Tiles concerned by the specification
132        String word   = null; // current word
133        String errMsg = null; // Error message
134        boolean needInteger = false; // True if an integer value is expected
135        int intType = 0; // Type of read integer value (0=index of first
136        // component, 1= index of first resolution level, 2=index of last
137        // layer, 3= index of last component, 4= index of last resolution
138        // level)
139        Vector progression = new Vector();
140        int tmp = 0;
141        Progression curProg = null;
142
143        while(stk.hasMoreTokens()){
144            word = stk.nextToken();
145
146            switch(word.charAt(0)){
147            case 't':
148                // If progression were previously found, store them
149                if(progression.size()>0){
150                    // Ensure that all information has been taken
151                    curProg.ce = nc;
152                    curProg.lye = nl;
153                    curProg.re = dls.getMax()+1;
154                    prog = new Progression[progression.size()];
155                    progression.copyInto(prog);
156                    if(curSpecType==SPEC_DEF){
157                        setDefault(prog);
158                    }
159                    else if(curSpecType==SPEC_TILE_DEF){
160                        for(int i=tileSpec.length-1; i>=0; i--)
161                            if(tileSpec[i]){
162                                setTileDef(i,prog);
163                            }
164                    }
165                }
166                progression.removeAllElements();
167                intType=-1;
168                needInteger = false;
169
170                // Tiles specification
171                tileSpec = parseIdx(word,nTiles);
172                curSpecType = SPEC_TILE_DEF;
173                break;
174            default:
175                // Here, words is either a Integer (progression bound
176                // index) or a String (progression order type). This
177                // is determined by the value of needInteger.
178                if(needInteger){ // Progression bound info
179                    try{
180                        tmp = (new Integer(word)).intValue();
181                    }
182                    catch(NumberFormatException e){
183                        // Progression has missing parameters
184                        throw new IllegalArgumentException("Progression "+
185                                                           "order"+
186                                                           " specification "+
187                                                           "has missing "+
188                                                           "parameters: "+
189                                                           param);
190                    }
191
192                    switch(intType){
193                    case 0: // cs
194                        if(tmp<0 || tmp>dls.getMax()+1)
195                            throw new
196                                IllegalArgumentException("Invalid comp_start "+
197                                                         "in '-Aptype' option");
198                        curProg.cs = tmp; break;
199                    case 1: // rs
200                        if(tmp<0 || tmp>nc)
201                            throw new
202                                IllegalArgumentException("Invalid res_start "+
203                                                         "in '-Aptype' option");
204
205                        curProg.rs = tmp; break;
206                    case 2: // lye
207                        if(tmp<0)
208                            throw new
209                                IllegalArgumentException("Invalid layer_end "+
210                                                         "in '-Aptype' option");
211                        if (tmp>nl) {
212                            tmp = nl;
213                        }
214                        curProg.lye = tmp; break;
215                    case 3: // ce
216                        if(tmp<0)
217                            throw new
218                                IllegalArgumentException("Invalid comp_end "+
219                                                         "in '-Aptype' option");
220                        if( tmp>(dls.getMax()+1)) {
221                            tmp = dls.getMax()+1;
222                        }
223                        curProg.ce = tmp; break;
224                    case 4: // re
225                        if(tmp<0)
226                            throw new
227                                IllegalArgumentException("Invalid res_end "+
228                                                         "in '-Aptype' option");
229                        if (tmp>nc) {
230                            tmp = nc;
231                        }
232                        curProg.re = tmp; break;
233                    }
234
235                    if(intType<4){
236                        intType++;
237                        needInteger = true;
238                        break;
239                    }
240                    else if(intType==4){
241                        intType = 0;
242                        needInteger = false;
243                        break;
244                    }
245                    else{
246                        throw new Error("Error in usage of 'Aptype' "+
247                                        "option: "+param);
248                    }
249                }
250
251                if(!needInteger){ // Progression type info
252                    mode = checkProgMode(word);
253                    if(mode==-1 ){
254                        errMsg = "Unknown progression type : '"+word+"'";
255                        throw new IllegalArgumentException(errMsg);
256                    }
257                    needInteger = true;
258                    intType = 0;
259                    if(progression.size()==0)
260                        curProg = new Progression(mode,0,nc,0,dls.getMax()+1,
261                                                  nl);
262                    else{
263                        curProg = new Progression(mode,0,nc,0,dls.getMax()+1,
264                                                  nl);
265                    }
266                    progression.addElement(curProg);
267                }
268            } // switch
269        } // while
270
271        if(progression.size()==0){ // No progression defined
272            // Set it arbitrarily to layer progressive
273            if(wp.getROIs() == null) {
274                mode = checkProgMode("res");
275            }
276            else {
277                mode = checkProgMode("layer");
278            }
279
280            if(mode==-1){
281                errMsg = "Unknown progression type : '"+param+"'";
282                throw new IllegalArgumentException(errMsg);
283            }
284            prog = new Progression[1];
285            prog[0] = new Progression(mode,0,nc,0,dls.getMax()+1,nl);
286            setDefault(prog);
287            return;
288        }
289
290        // Ensure that all information has been taken
291        curProg.ce = nc;
292        curProg.lye = nl;
293        curProg.re = dls.getMax()+1;
294
295        // Store found progression
296        prog = new Progression[progression.size()];
297        progression.copyInto(prog);
298
299        if(curSpecType==SPEC_DEF){
300            setDefault(prog);
301        }
302        else if(curSpecType==SPEC_TILE_DEF){
303            for(int i=tileSpec.length-1; i>=0; i--)
304                if(tileSpec[i]){
305                    setTileDef(i,prog);
306                }
307        }
308
309        // Check that default value has been specified
310        if(getDefault()==null){
311            int ndefspec = 0;
312            for(int t=nt-1; t>=0; t--){
313                for(int c=nc-1; c>=0 ; c--){
314                    if(specValType[t][c] == SPEC_DEF){
315                        ndefspec++;
316                    }
317                }
318            }
319
320            // If some tile-component have received no specification, they are
321            // arbitrarily set to 'layer' progressive.
322            if(ndefspec!=0){
323                if(wp.getROIs() == null) {
324                    mode = checkProgMode("res");
325                } else {
326                    mode = checkProgMode("layer");
327                }
328                if(mode==-1){
329                    errMsg = "Unknown progression type : '"+param+"'";
330                    throw new IllegalArgumentException(errMsg);
331                }
332                prog = new Progression[1];
333                prog[0] = new Progression(mode,0,nc,0,dls.getMax()+1,nl);
334                setDefault(prog);
335            }
336            else{
337                // All tile-component have been specified, takes the first
338                // tile-component value as default.
339                setDefault(getTileCompVal(0,0));
340                switch(specValType[0][0]){
341                case SPEC_TILE_DEF:
342                    for(int c=nc-1; c>=0; c--){
343                        if(specValType[0][c]==SPEC_TILE_DEF)
344                            specValType[0][c] = SPEC_DEF;
345                    }
346                    tileDef[0] = null;
347                    break;
348                case SPEC_COMP_DEF:
349                    for(int t=nt-1; t>=0; t--){
350                        if(specValType[t][0]==SPEC_COMP_DEF)
351                            specValType[t][0] = SPEC_DEF;
352                    }
353                    compDef[0] = null;
354                    break;
355                case SPEC_TILE_COMP:
356                    specValType[0][0] = SPEC_DEF;
357                    tileCompVal.put("t0c0",null);
358                    break;
359                }
360            }
361        }
362   }
363
364    /**
365     * Check if the progression mode exists and if so, return its integer
366     * value. It returns -1 otherwise.
367     *
368     * @param mode The progression mode stored in a string
369     *
370     * @return The integer value of the progression mode or -1 if the
371     * progression mode does not exist.
372     *
373     * @see ProgressionType
374     * */
375    private int checkProgMode(String mode) {
376        if(mode.equals("res")){
377            return ProgressionType.RES_LY_COMP_POS_PROG;
378        }
379        else if( mode.equals("layer") ) {
380            return ProgressionType.LY_RES_COMP_POS_PROG;
381        }
382        else if( mode.equals("pos-comp") ) {
383            return ProgressionType.POS_COMP_RES_LY_PROG;
384        }
385        else if ( mode.equals("comp-pos") ) {
386            return ProgressionType.COMP_POS_RES_LY_PROG;
387        }
388        else if ( mode.equals("res-pos") ) {
389            return ProgressionType.RES_POS_COMP_LY_PROG;
390        }
391        else {
392            // No corresponding progression mode, we return -1.
393            return -1;
394        }
395    }
396}