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