001/* 002 * $RCSfile: PrecinctSizeSpec.java,v $ 003 * $Revision: 1.1 $ 004 * $Date: 2005/02/11 05:02:04 $ 005 * $State: Exp $ 006 * 007 * Class: PrecinctSizeSpec 008 * 009 * Description: Specification of the precinct sizes 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; 048import java.util.Vector; 049 050import jj2000.j2k.IntegerSpec; 051import jj2000.j2k.ModuleSpec; 052import jj2000.j2k.codestream.Markers; 053import jj2000.j2k.image.BlkImgDataSrc; 054import jj2000.j2k.util.MathUtil; 055 056import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava; 057 058/** 059 * This class extends ModuleSpec class for precinct partition sizes holding 060 * purposes. 061 * 062 * <p>It stores the size a of precinct when precinct partition is used or not. 063 * If precinct partition is used, we can have several packets for a given 064 * resolution level whereas there is only one packet per resolution level if 065 * no precinct partition is used. 066 * */ 067public class PrecinctSizeSpec extends ModuleSpec { 068 069 /** Name of the option */ 070 private static final String optName = "Cpp"; 071 072 /** Reference to wavelet number of decomposition levels for each 073 * tile-component. */ 074 private IntegerSpec dls; 075 076 /** 077 * Creates a new PrecinctSizeSpec object for the specified number of tiles 078 * and components. 079 * 080 * @param nt The number of tiles 081 * 082 * @param nc The number of components 083 * 084 * @param type the type of the specification module i.e. tile specific, 085 * component specific or both. 086 * 087 * @param dls Reference to the number of decomposition levels 088 * specification 089 * */ 090 public PrecinctSizeSpec(int nt, int nc, byte type, IntegerSpec dls) { 091 super(nt, nc, type); 092 this.dls = dls; 093 } 094 095 /** 096 * Creates a new PrecinctSizeSpec object for the specified number of tiles 097 * and components and the J2KImageWriteParamJava instance. 098 * 099 * @param nt The number of tiles 100 * 101 * @param nc The number of components 102 * 103 * @param type the type of the specification module i.e. tile specific, 104 * component specific or both. 105 * 106 * @param imgsrc The image source (used to get the image size) 107 * 108 * @param wp The J2KImageWriteParamJava instance 109 * */ 110 public PrecinctSizeSpec(int nt, int nc, byte type, BlkImgDataSrc imgsrc, 111 IntegerSpec dls, J2KImageWriteParamJava wp, String values) { 112 super(nt, nc, type); 113 114 this.dls = dls; 115 116 // The precinct sizes are stored in a 2 elements vector array, the 117 // first element containing a vector for the precincts width for each 118 // resolution level and the second element containing a vector for the 119 // precincts height for each resolution level. The precincts sizes are 120 // specified from the highest resolution level to the lowest one 121 // (i.e. 0). If there are less elements than the number of 122 // decomposition levels, the last element is used for all remaining 123 // resolution levels (i.e. if the precincts sizes are specified only 124 // for resolutions levels 5, 4 and 3, then the precincts size for 125 // resolution levels 2, 1 and 0 will be the same as the size used for 126 // resolution level 3). 127 128 // Boolean used to know if we were previously reading a precinct's 129 // size or if we were reading something else. 130 boolean wasReadingPrecinctSize = false; 131 132 String param = values; 133/* 134 if (values == null) 135 param = defaultValue; // the default is null 136*/ 137 // Set precinct sizes to default i.e. 2^15 = 138 // Markers.PRECINCT_PARTITION_DEF_SIZE 139 Vector tmpv[] = new Vector[2]; 140 tmpv[0] = new Vector(); // ppx 141 tmpv[0].addElement(new Integer(Markers.PRECINCT_PARTITION_DEF_SIZE)); 142 tmpv[1] = new Vector(); // ppy 143 tmpv[1].addElement(new Integer(Markers.PRECINCT_PARTITION_DEF_SIZE)); 144 setDefault(tmpv); 145 146 if ( param==null ) { 147 // No precinct size specified in the command line so we do not try 148 // to parse it. 149 return; 150 } 151 152 // Precinct partition is used : parse arguments 153 StringTokenizer stk = new StringTokenizer(param); 154 byte curSpecType = SPEC_DEF; // Specification type of the 155 // current parameter 156 boolean[] tileSpec = null; // Tiles concerned by the specification 157 boolean[] compSpec = null; // Components concerned by the specification 158 int i, xIdx, ci, ti; 159 160 boolean endOfParamList = false; 161 String word = null; // current word 162 Integer w, h; 163 String errMsg = null; 164 165 while((stk.hasMoreTokens() || wasReadingPrecinctSize) && 166 !endOfParamList){ 167 168 Vector v[] = new Vector[2]; // v[0] : ppx, v[1] : ppy 169 170 // We do not read the next token if we were reading a precinct's 171 // size argument as we have already read the next token into word. 172 if ( !wasReadingPrecinctSize ) { 173 word = stk.nextToken(); 174 } 175 176 wasReadingPrecinctSize = false; 177 178 switch(word.charAt(0)){ 179 180 case 't': // Tiles specification 181 tileSpec = parseIdx(word,nTiles); 182 if(curSpecType==SPEC_COMP_DEF) { 183 curSpecType = SPEC_TILE_COMP; 184 } 185 else { 186 curSpecType = SPEC_TILE_DEF; 187 } 188 break; 189 190 case 'c': // Components specification 191 compSpec = parseIdx(word,nComp); 192 if(curSpecType==SPEC_TILE_DEF) { 193 curSpecType = SPEC_TILE_COMP; 194 } 195 else { 196 curSpecType = SPEC_COMP_DEF; 197 } 198 break; 199 200 default: 201 if ( !Character.isDigit(word.charAt(0)) ) { 202 errMsg = "Bad construction for parameter: "+word; 203 throw new IllegalArgumentException(errMsg); 204 } 205 206 // Initialises Vector objects 207 v[0] = new Vector(); // ppx 208 v[1] = new Vector(); // ppy 209 210 while ( true ) { 211 212 // Now get the precinct dimensions 213 try { 214 // Get precinct width 215 w = new Integer(word); 216 217 // Get next word in argument list 218 try { 219 word = stk.nextToken(); 220 } 221 catch (NoSuchElementException e) { 222 errMsg = "'"+optName+"' option : could not "+ 223 "parse the precinct's width"; 224 throw new IllegalArgumentException(errMsg); 225 226 } 227 // Get precinct height 228 h = new Integer(word); 229 if (w.intValue() != (1<<MathUtil.log2(w.intValue())) 230 || h.intValue() != 231 (1<<MathUtil.log2(h.intValue())) ) { 232 errMsg = "Precinct dimensions must be powers of 2"; 233 throw new IllegalArgumentException(errMsg); 234 } 235 } 236 catch( NumberFormatException e) { 237 errMsg = "'"+optName+"' option : the argument '"+word+ 238 "' could not be parsed."; 239 throw new IllegalArgumentException(errMsg); 240 } 241 // Store packet's dimensions in Vector arrays 242 v[0].addElement(w); 243 v[1].addElement(h); 244 245 // Try to get the next token 246 if ( stk.hasMoreTokens() ) { 247 word = stk.nextToken(); 248 if ( !Character.isDigit(word.charAt(0)) ) { 249 // The next token does not start with a digit so 250 // it is not a precinct's size argument. We set 251 // the wasReadingPrecinctSize booleen such that we 252 // know that we don't have to read another token 253 // and check for the end of the parameters list. 254 wasReadingPrecinctSize = true; 255 256 if(curSpecType==SPEC_DEF){ 257 setDefault(v); 258 } 259 else if(curSpecType==SPEC_TILE_DEF){ 260 for(ti=tileSpec.length-1; ti>=0; ti--) { 261 if( tileSpec[ti] ){ 262 setTileDef(ti,v); 263 } 264 } 265 } 266 else if(curSpecType==SPEC_COMP_DEF){ 267 for(ci=compSpec.length-1; ci>=0; ci--) { 268 if( compSpec[ci] ){ 269 setCompDef(ci,v); 270 } 271 } 272 } 273 else{ 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,v); 278 } 279 } 280 } 281 } 282 // Re-initialize 283 curSpecType = SPEC_DEF; 284 tileSpec = null; 285 compSpec = null; 286 287 // Go back to 'normal' parsing 288 break; 289 } 290 else { 291 // Next token starts with a digit so read it 292 } 293 } 294 else { 295 // We have reached the end of the parameters list so 296 // we store the last precinct's sizes and we stop 297 if(curSpecType==SPEC_DEF){ 298 setDefault(v); 299 } 300 else if(curSpecType==SPEC_TILE_DEF){ 301 for(ti=tileSpec.length-1; ti>=0; ti--) { 302 if( tileSpec[ti] ){ 303 setTileDef(ti,v); 304 } 305 } 306 } 307 else if(curSpecType==SPEC_COMP_DEF){ 308 for(ci=compSpec.length-1; ci>=0; ci--) { 309 if( compSpec[ci] ){ 310 setCompDef(ci,v); 311 } 312 } 313 } 314 else{ 315 for(ti=tileSpec.length-1; ti>=0; ti--){ 316 for(ci=compSpec.length-1; ci>=0 ; ci--){ 317 if( tileSpec[ti] && compSpec[ci] ){ 318 setTileCompVal(ti,ci,v); 319 } 320 } 321 } 322 } 323 endOfParamList = true; 324 break; 325 } 326 } // while (true) 327 break; 328 } // switch 329 } // while 330 } 331 332 /** 333 * Returns the precinct partition width in component 'n' and tile 't' at 334 * resolution level 'rl'. If the tile index is equal to -1 or if the 335 * component index is equal to -1 it means that those should not be taken 336 * into account. 337 * 338 * @param t The tile index, in raster scan order. Specify -1 if it is not 339 * a specific tile. 340 * 341 * @param c The component index. Specify -1 if it is not a specific 342 * component. 343 * 344 * @param rl The resolution level 345 * 346 * @return The precinct partition width in component 'c' and tile 't' at 347 * resolution level 'rl'. 348 * */ 349 public int getPPX(int t, int c, int rl) { 350 int mrl, idx; 351 Vector[] v=null; 352 boolean tileSpecified = (t!=-1 ? true : false); 353 boolean compSpecified = (c!=-1 ? true : false); 354 355 // Get the maximum number of decomposition levels and the object 356 // (Vector array) containing the precinct dimensions (width and 357 // height) for the specified (or not) tile/component 358 if ( tileSpecified && compSpecified ) { 359 mrl = ((Integer)dls.getTileCompVal(t, c)).intValue(); 360 v = (Vector[])getTileCompVal(t, c); 361 } 362 else if ( tileSpecified && !compSpecified ) { 363 mrl = ((Integer)dls.getTileDef(t)).intValue(); 364 v = (Vector[])getTileDef(t); 365 } 366 else if ( !tileSpecified && compSpecified ) { 367 mrl = ((Integer)dls.getCompDef(c)).intValue(); 368 v = (Vector[])getCompDef(c); 369 } 370 else { 371 mrl = ((Integer)dls.getDefault()).intValue(); 372 v = (Vector[])getDefault(); 373 } 374 idx = mrl - rl; 375 if ( v[0].size() > idx ) { 376 return ((Integer)v[0].elementAt(idx)).intValue(); 377 } 378 else { 379 return ((Integer)v[0].elementAt(v[0].size()-1)).intValue(); 380 } 381 } 382 383 /** 384 * Returns the precinct partition height in component 'n' and tile 't' at 385 * resolution level 'rl'. If the tile index is equal to -1 or if the 386 * component index is equal to -1 it means that those should not be taken 387 * into account. 388 * 389 * @param t The tile index, in raster scan order. Specify -1 if it is not 390 * a specific tile. 391 * 392 * @param c The component index. Specify -1 if it is not a specific 393 * component. 394 * 395 * @param rl The resolution level. 396 * 397 * @return The precinct partition width in component 'n' and tile 't' at 398 * resolution level 'rl'. 399 * */ 400 public int getPPY(int t, int c, int rl) { 401 int mrl, idx; 402 Vector[] v=null; 403 boolean tileSpecified = (t!=-1 ? true : false); 404 boolean compSpecified = (c!=-1 ? true : false); 405 406 // Get the maximum number of decomposition levels and the object 407 // (Vector array) containing the precinct dimensions (width and 408 // height) for the specified (or not) tile/component 409 if ( tileSpecified && compSpecified ) { 410 mrl = ((Integer)dls.getTileCompVal(t, c)).intValue(); 411 v = (Vector[])getTileCompVal(t, c); 412 } 413 else if ( tileSpecified && !compSpecified ) { 414 mrl = ((Integer)dls.getTileDef(t)).intValue(); 415 v = (Vector[])getTileDef(t); 416 } 417 else if ( !tileSpecified && compSpecified ) { 418 mrl = ((Integer)dls.getCompDef(c)).intValue(); 419 v = (Vector[])getCompDef(c); 420 } 421 else { 422 mrl = ((Integer)dls.getDefault()).intValue(); 423 v = (Vector[])getDefault(); 424 } 425 idx = mrl - rl; 426 if ( v[1].size() > idx ) { 427 return ((Integer)v[1].elementAt(idx)).intValue(); 428 } 429 else { 430 return ((Integer)v[1].elementAt(v[1].size()-1)).intValue(); 431 } 432 } 433}