001/*
002 * $RCSfile: CBlkSizeSpec.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:04 $
005 * $State: Exp $
006 *
007 * Class:                   CBlkSizeSpec
008 *
009 * Description:             Specification of the code-blocks size
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.entropy;
045
046import jj2000.j2k.codestream.*;
047import jj2000.j2k.wavelet.*;
048import jj2000.j2k.image.*;
049import jj2000.j2k.util.*;
050import jj2000.j2k.*;
051
052import java.util.*;
053
054import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
055/**
056 * This class extends ModuleSpec class for code-blocks sizes holding purposes.
057 *
058 * <P>It stores the size a of code-block.
059 * */
060public class CBlkSizeSpec extends ModuleSpec {
061
062    private String defaultValue = "64 64";
063
064    /** Name of the option */
065    private static final String optName = "Cblksiz";
066
067    /** The maximum code-block width */
068    private int maxCBlkWidth = 0;
069
070    /** The maximum code-block height */
071    private int maxCBlkHeight = 0;
072
073    /**
074     * Creates a new CBlkSizeSpec object for the specified number of tiles and
075     * components.
076     *
077     * @param nt The number of tiles
078     *
079     * @param nc The number of components
080     *
081     * @param type the type of the specification module i.e. tile specific,
082     * component specific or both.
083     * */
084    public CBlkSizeSpec(int nt, int nc, byte type) {
085        super(nt, nc, type);
086    }
087
088    /**
089     * Creates a new CBlkSizeSpec object for the specified number of tiles and
090     * components and the ParameterList instance.
091     *
092     * @param nt The number of tiles
093     *
094     * @param nc The number of components
095     *
096     * @param type the type of the specification module i.e. tile specific,
097     * component specific or both.
098     *
099     * @param imgsrc The image source (used to get the image size)
100     *
101     * @param pl The ParameterList instance
102     * */
103    public CBlkSizeSpec(int nt, int nc, byte type, J2KImageWriteParamJava wp, String values) {
104        super(nt, nc, type);
105
106        boolean firstVal = true;
107        specified = values;
108
109        String param = values; //"64 64";
110        if (param == null)
111            param = defaultValue;    // the default
112        //pl.getParameter(optName);
113
114        // Precinct partition is used : parse arguments
115        StringTokenizer stk = new StringTokenizer(param);
116        byte curSpecType = SPEC_DEF; // Specification type of the
117                                     // current parameter
118        boolean[] tileSpec = null; // Tiles concerned by the specification
119        boolean[] compSpec = null; // Components concerned by the specification
120        int i, xIdx, ci, ti;
121        String word = null; // current word
122        String errMsg = null;
123
124        while( stk.hasMoreTokens() ) {
125            word = stk.nextToken();
126
127            switch(word.charAt(0)){
128
129            case 't': // Tiles specification
130                tileSpec = parseIdx(word, nTiles);
131                if(curSpecType==SPEC_COMP_DEF) {
132                    curSpecType = SPEC_TILE_COMP;
133                }
134                else {
135                    curSpecType = SPEC_TILE_DEF;
136                }
137                break;
138
139            case 'c': // Components specification
140                compSpec = parseIdx(word, nComp);
141                if(curSpecType==SPEC_TILE_DEF) {
142                    curSpecType = SPEC_TILE_COMP;
143                }
144                else {
145                    curSpecType = SPEC_COMP_DEF;
146                }
147                break;
148
149            default:
150                if ( !Character.isDigit(word.charAt(0)) ) {
151                    errMsg = "Bad construction for parameter: "+word;
152                    throw new IllegalArgumentException(errMsg);
153                }
154                Integer dim[] = new Integer[2];
155                // Get code-block's width
156                try {
157                    dim[0] = new Integer(word);
158                    // Check that width is not >
159                    // StdEntropyCoderOptions.MAX_CB_DIM
160                    if( dim[0].intValue()>StdEntropyCoderOptions.MAX_CB_DIM ){
161                        errMsg = "'"+optName+"' option : the code-block's "+
162                            "width cannot be greater than "+
163                            StdEntropyCoderOptions.MAX_CB_DIM;
164                        throw new IllegalArgumentException(errMsg);
165                    }
166                    // Check that width is not <
167                    // StdEntropyCoderOptions.MIN_CB_DIM
168                    if( dim[0].intValue()<StdEntropyCoderOptions.MIN_CB_DIM ){
169                        errMsg = "'"+optName+"' option : the code-block's "+
170                            "width cannot be less than "+
171                            StdEntropyCoderOptions.MIN_CB_DIM;
172                        throw new IllegalArgumentException(errMsg);
173                    }
174                    // Check that width is a power of 2
175                    if ( dim[0].intValue() !=
176                         (1<<MathUtil.log2(dim[0].intValue())) ) {
177                        errMsg = "'"+optName+"' option : the code-block's "+
178                            "width must be a power of 2";
179                        throw new IllegalArgumentException(errMsg);
180                    }
181                }
182                catch( NumberFormatException e) {
183                     errMsg = "'"+optName+"' option : the code-block's "+
184                         "width could not be parsed.";
185                    throw new IllegalArgumentException(errMsg);
186                }
187                // Get the next word in option
188                try {
189                    word = stk.nextToken();
190                }
191                catch (NoSuchElementException e) {
192                    errMsg = "'"+optName+"' option : could not parse the "+
193                        "code-block's height";
194                    throw new IllegalArgumentException(errMsg);
195
196                }
197                // Get the code-block's height
198                try {
199                    dim[1] = new Integer(word);
200                    // Check that height is not >
201                    // StdEntropyCoderOptions.MAX_CB_DIM
202                    if ( dim[1].intValue()>StdEntropyCoderOptions.MAX_CB_DIM ){
203                        errMsg = "'"+optName+"' option : the code-block's "+
204                            "height cannot be greater than "+
205                            StdEntropyCoderOptions.MAX_CB_DIM;
206                        throw new IllegalArgumentException(errMsg);
207                    }
208                    // Check that height is not <
209                    // StdEntropyCoderOptions.MIN_CB_DIM
210                    if ( dim[1].intValue()<StdEntropyCoderOptions.MIN_CB_DIM ){
211                        errMsg = "'"+optName+"' option : the code-block's "+
212                            "height cannot be less than "+
213                            StdEntropyCoderOptions.MIN_CB_DIM;
214                        throw new IllegalArgumentException(errMsg);
215                    }
216                    // Check that height is a power of 2
217                    if ( dim[1].intValue() !=
218                         (1<<MathUtil.log2(dim[1].intValue())) ) {
219                        errMsg = "'"+optName+"' option : the code-block's "+
220                            "height must be a power of 2";
221                        throw new IllegalArgumentException(errMsg);
222                    }
223                    // Check that the code-block 'area' (i.e. width*height) is
224                    // not greater than StdEntropyCoderOptions.MAX_CB_AREA
225                    if ( dim[0].intValue()*dim[1].intValue() >
226                         StdEntropyCoderOptions.MAX_CB_AREA )
227                        {
228                            errMsg = "'"+optName+"' option : The "+
229                                "code-block's area (i.e. width*height) "+
230                                "cannot be greater than "+
231                                StdEntropyCoderOptions.MAX_CB_AREA;
232                            throw new IllegalArgumentException(errMsg);
233                        }
234                }
235                catch( NumberFormatException e) {
236                    errMsg = "'"+optName+"' option : the code-block's height "+
237                        "could not be parsed.";
238                    throw new IllegalArgumentException(errMsg);
239                }
240
241                // Store the maximum dimensions if necessary
242                if ( dim[0].intValue() > maxCBlkWidth ) {
243                    maxCBlkWidth = dim[0].intValue();
244                }
245
246                if ( dim[1].intValue() > maxCBlkHeight ) {
247                    maxCBlkHeight = dim[1].intValue();
248                }
249
250                if ( firstVal ) {
251                    // This is the first time a value is given so we set it as
252                    // the default one
253                    setDefault(dim);
254                    firstVal = false;
255                }
256
257                switch (curSpecType) {
258                case  SPEC_DEF:
259                    setDefault(dim);
260                    break;
261                case SPEC_TILE_DEF:
262                    for(ti=tileSpec.length-1; ti>=0; ti--) {
263                        if( tileSpec[ti] ){
264                            setTileDef(ti,dim);
265                        }
266                    }
267                    break;
268                case SPEC_COMP_DEF:
269                    for(ci=compSpec.length-1; ci>=0; ci--) {
270                        if( compSpec[ci] ){
271                            setCompDef(ci,dim);
272                        }
273                    }
274                    break;
275                default:
276                    for(ti=tileSpec.length-1; ti>=0; ti--){
277                        for(ci=compSpec.length-1; ci>=0 ; ci--){
278                            if(tileSpec[ti] && compSpec[ci]){
279                                setTileCompVal(ti,ci,dim);
280                            }
281                        }
282                    }
283                    break;
284                }
285            } // end switch
286        }
287    }
288
289    /**
290     * Returns the maximum code-block's width
291     *
292     */
293    public int getMaxCBlkWidth() {
294        return maxCBlkWidth;
295    }
296
297    /**
298     * Returns the maximum code-block's height
299     *
300     */
301    public int getMaxCBlkHeight() {
302        return maxCBlkHeight;
303    }
304
305    /**
306     * Returns the code-block width :
307     *
308     * <ul>
309     * <li>for the specified tile/component</li>
310     * <li>for the specified tile</li>
311     * <li>for the specified component</li>
312     * <li>default value</li>
313     * </ul>
314     *
315     * The value returned depends on the value of the variable 'type' which
316     * can take the following values :<br>
317     *
318     * <ul>
319     * <li>SPEC_DEF -> Default value is returned. t and c values are
320     * ignored</li>
321     * <li>SPEC_COMP_DEF -> Component default value is returned. t value is
322     * ignored</li>
323     * <li>SPEC_TILE_DEF -> Tile default value is returned. c value is
324     * ignored</li>
325     * <li>SPEC_TILE_COMP -> Tile/Component value is returned.</li>
326     * </ul>
327     *
328     * @param type The type of the value we want to be returned
329     *
330     * @param t The tile index
331     *
332     * @param c the component index
333     *
334     * @return The code-block width for the specified tile and component
335     * */
336    public int getCBlkWidth(byte type, int t, int c) {
337        Integer dim[] = null;
338        switch (type) {
339        case SPEC_DEF:
340            dim = (Integer[])getDefault();
341            break;
342        case SPEC_COMP_DEF:
343            dim = (Integer[])getCompDef(c);
344            break;
345        case SPEC_TILE_DEF:
346            dim = (Integer[])getTileDef(t);
347            break;
348        case SPEC_TILE_COMP:
349            dim = (Integer[])getTileCompVal(t, c);
350        }
351        return dim[0].intValue();
352    }
353
354    /**
355     * Returns the code-block height:
356     *
357     * <ul>
358     * <li>for the specified tile/component</li>
359     * <li>for the specified tile</li>
360     * <li>for the specified component</li>
361     * <li>default value</li>
362     * </ul>
363     *
364     * The value returned depends on the value of the variable 'type' which
365     * can take the following values :
366     *
367     * <ul>
368     * <li>SPEC_DEF -> Default value is returned. t and c values are
369     * ignored</li>
370     * <li>SPEC_COMP_DEF -> Component default value is returned. t value is
371     * ignored</li>
372     * <li>SPEC_TILE_DEF -> Tile default value is returned. c value is
373     * ignored</li>
374     * <li>SPEC_TILE_COMP -> Tile/Component value is returned.</li>
375     * </ul>
376     *
377     * @param type The type of the value we want to be returned
378     *
379     * @param t The tile index
380     *
381     * @param c the component index
382     *
383     * @return The code-block height for the specified tile and component
384     * */
385    public int getCBlkHeight(byte type, int t, int c) {
386        Integer dim[] = null;
387        switch (type) {
388        case SPEC_DEF:
389            dim = (Integer[])getDefault();
390            break;
391        case SPEC_COMP_DEF:
392            dim = (Integer[])getCompDef(c);
393            break;
394        case SPEC_TILE_DEF:
395            dim = (Integer[])getTileDef(t);
396            break;
397        case SPEC_TILE_COMP:
398            dim = (Integer[])getTileCompVal(t, c);
399        }
400        return dim[1].intValue();
401    }
402
403    /**
404     * Sets default value for this module
405     *
406     * @param value Default value
407     * */
408    public void setDefault(Object value){
409        super.setDefault(value);
410
411        // Store the biggest code-block dimensions
412        storeHighestDims((Integer[])value);
413    }
414
415    /**
416     * Sets default value for specified tile and specValType tag if allowed by
417     * its priority.
418     *
419     * @param c Tile index.
420     *
421     * @param value Tile's default value
422     *  */
423    public void setTileDef(int t, Object value){
424        super.setTileDef(t, value);
425
426        // Store the biggest code-block dimensions
427        storeHighestDims((Integer[])value);
428    }
429
430    /**
431     * Sets default value for specified component and specValType tag if
432     * allowed by its priority.
433     *
434     * @param c Component index
435     *
436     * @param value Component's default value
437     *  */
438    public void setCompDef(int c, Object value){
439        super.setCompDef(c, value);
440
441        // Store the biggest code-block dimensions
442        storeHighestDims((Integer[])value);
443    }
444
445    /**
446     * Sets value for specified tile-component.
447     *
448     * @param t Tie index
449     *
450     * @param c Component index
451     *
452     * @param value Tile-component's value
453     *  */
454    public void setTileCompVal(int t,int c, Object value){
455        super.setTileCompVal(t, c, value);
456
457        // Store the biggest code-block dimensions
458        storeHighestDims((Integer[])value);
459    }
460
461    /**
462     * Stores the highest code-block width and height
463     *
464     * @param dim The 2 elements array that contains the code-block width and
465     * height.
466     *  */
467    private void storeHighestDims(Integer[] dim){
468        // Store the biggest code-block dimensions
469        if ( dim[0].intValue() > maxCBlkWidth ) {
470            maxCBlkWidth = dim[0].intValue();
471        }
472        if ( dim[1].intValue() > maxCBlkHeight ) {
473            maxCBlkHeight = dim[1].intValue();
474        }
475    }
476}