001/* 002 * $RCSfile: AnWTFilterSpec.java,v $ 003 * $Revision: 1.1 $ 004 * $Date: 2005/02/11 05:02:29 $ 005 * $State: Exp $ 006 * 007 * Class: AnWTFilterSpec 008 * 009 * Description: Analysis filters specification 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.wavelet.analysis; 045 046import java.util.StringTokenizer; 047 048import jj2000.j2k.ModuleSpec; 049import jj2000.j2k.quantization.QuantTypeSpec; 050 051import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava; 052 053/** 054 * This class extends ModuleSpec class for analysis filters specification 055 * holding purpose. 056 * 057 * @see ModuleSpec 058 * */ 059public class AnWTFilterSpec extends ModuleSpec { 060 061 /** The reversible default filter */ 062 private final static String REV_FILTER_STR = "w5x3"; 063 064 /** The non-reversible default filter */ 065 private final static String NON_REV_FILTER_STR = "w9x7"; 066 067 /** 068 * Constructs a new 'AnWTFilterSpec' for the specified number of 069 * components and tiles. 070 * 071 * @param nt The number of tiles 072 * 073 * @param nc The number of components 074 * 075 * @param type the type of the specification module i.e. tile specific, 076 * component specific or both. 077 * 078 * @param qts Quantization specifications 079 * */ 080 public AnWTFilterSpec(int nt, int nc, byte type, 081 QuantTypeSpec qts, J2KImageWriteParamJava wp, String values){ 082 super(nt, nc, type); 083/* 084 // Check parameters 085 pl.checkList(AnWTFilter.OPT_PREFIX, 086 pl.toNameArray(AnWTFilter.getParameterInfo())); 087*/ 088 specified = values; 089 String param = specified; 090 boolean isFilterSpecified = true; 091 092 // No parameter specified 093 if(values==null){ 094 isFilterSpecified = false; 095 096 if(wp.getLossless()) { 097 setDefault(parseFilters(REV_FILTER_STR)); 098 return; 099 } 100 101 // If no filter is specified through the command-line, use 102 // REV_FILTER_STR or NON_REV_FILTER_STR according to the 103 // quantization type 104 for(int t=nt-1;t>=0;t--){ 105 for(int c=nc-1;c>=0;c--){ 106 switch(qts.getSpecValType(t,c)){ 107 case SPEC_DEF: 108 if(getDefault()==null){ 109 if( wp.getLossless() ) 110 setDefault(parseFilters(REV_FILTER_STR)); 111 if( ((String)qts.getDefault()). 112 equals("reversible") ){ 113 setDefault(parseFilters(REV_FILTER_STR)); 114 } 115 else{ 116 setDefault(parseFilters(NON_REV_FILTER_STR)); 117 } 118 } 119 specValType[t][c] = SPEC_DEF; 120 break; 121 case SPEC_COMP_DEF: 122 if(!isCompSpecified(c)){ 123 if( ((String)qts.getCompDef(c)). 124 equals("reversible") ){ 125 setCompDef(c,parseFilters(REV_FILTER_STR)); 126 } 127 else{ 128 setCompDef(c,parseFilters(NON_REV_FILTER_STR)); 129 } 130 } 131 specValType[t][c] = SPEC_COMP_DEF; 132 break; 133 case SPEC_TILE_DEF: 134 if(!isTileSpecified(t)){ 135 if( ((String)qts.getTileDef(t)). 136 equals("reversible") ){ 137 setTileDef(t,parseFilters(REV_FILTER_STR)); 138 } 139 else{ 140 setTileDef(t,parseFilters(NON_REV_FILTER_STR)); 141 } 142 } 143 specValType[t][c] = SPEC_TILE_DEF; 144 break; 145 case SPEC_TILE_COMP: 146 if(!isTileCompSpecified(t,c)){ 147 if(((String)qts.getTileCompVal(t,c)). 148 equals("reversible")){ 149 setTileCompVal(t,c,parseFilters(REV_FILTER_STR)); 150 } 151 else{ 152 setTileCompVal(t,c, 153 parseFilters(NON_REV_FILTER_STR)); 154 } 155 } 156 specValType[t][c] = SPEC_TILE_COMP; 157 break; 158 default: 159 throw new IllegalArgumentException("Unsupported "+ 160 "specification type"); 161 } 162 } 163 } 164 165 return; 166 } 167 168 // Parse argument 169 StringTokenizer stk = new StringTokenizer(param); 170 String word; // current word 171 byte curSpecType = SPEC_DEF; // Specification type of the 172 // current parameter 173 boolean[] tileSpec = null; // Tiles concerned by the specification 174 boolean[] compSpec = null; // Components concerned by the specification 175 AnWTFilter[][] filter; 176 177 while(stk.hasMoreTokens()){ 178 word = stk.nextToken(); 179 180 switch(word.charAt(0)){ 181 case 't': // Tiles specification 182 case 'T': // Tiles specification 183 tileSpec = parseIdx(word,nTiles); 184 if(curSpecType==SPEC_COMP_DEF) 185 curSpecType = SPEC_TILE_COMP; 186 else 187 curSpecType = SPEC_TILE_DEF; 188 break; 189 case 'c': // Components specification 190 case 'C': // Components specification 191 compSpec = parseIdx(word,nComp); 192 if(curSpecType==SPEC_TILE_DEF) 193 curSpecType = SPEC_TILE_COMP; 194 else 195 curSpecType = SPEC_COMP_DEF; 196 break; 197 case 'w': // WT filters specification 198 case 'W': // WT filters specification 199 if(wp.getLossless() && 200 word.equalsIgnoreCase("w9x7") ) { 201 throw new IllegalArgumentException("Cannot use non "+ 202 "reversible "+ 203 "wavelet transform with"+ 204 " '-lossless' option"); 205 206 } 207 208 filter = parseFilters(word); 209 if(curSpecType==SPEC_DEF){ 210 setDefault(filter); 211 } 212 else if(curSpecType==SPEC_TILE_DEF){ 213 for(int i=tileSpec.length-1; i>=0; i--) 214 if(tileSpec[i]){ 215 setTileDef(i,filter); 216 } 217 } 218 else if(curSpecType==SPEC_COMP_DEF){ 219 for(int i=compSpec.length-1; i>=0; i--) 220 if(compSpec[i]){ 221 setCompDef(i,filter); 222 } 223 } 224 else{ 225 for(int i=tileSpec.length-1; i>=0; i--){ 226 for(int j=compSpec.length-1; j>=0 ; j--){ 227 if(tileSpec[i] && compSpec[j]){ 228 setTileCompVal(i,j,filter); 229 } 230 } 231 } 232 } 233 234 // Re-initialize 235 curSpecType = SPEC_DEF; 236 tileSpec = null; 237 compSpec = null; 238 break; 239 240 default: 241 throw new IllegalArgumentException("Bad construction for "+ 242 "parameter: "+word); 243 } 244 } 245 246 // Check that default value has been specified 247 if(getDefault()==null){ 248 int ndefspec = 0; 249 for(int t=nt-1; t>=0; t--){ 250 for(int c=nc-1; c>=0 ; c--){ 251 if(specValType[t][c] == SPEC_DEF){ 252 ndefspec++; 253 } 254 } 255 } 256 257 // If some tile-component have received no specification, it takes 258 // the default value 259 if(ndefspec!=0){ 260 if( ((String)qts.getDefault()).equals("reversible") ) 261 setDefault(parseFilters(REV_FILTER_STR)); 262 else 263 setDefault(parseFilters(NON_REV_FILTER_STR)); 264 } 265 else{ 266 // All tile-component have been specified, takes the first 267 // tile-component value as default. 268 setDefault(getTileCompVal(0,0)); 269 switch(specValType[0][0]){ 270 case SPEC_TILE_DEF: 271 for(int c=nc-1; c>=0; c--){ 272 if(specValType[0][c]==SPEC_TILE_DEF) 273 specValType[0][c] = SPEC_DEF; 274 } 275 tileDef[0] = null; 276 break; 277 case SPEC_COMP_DEF: 278 for(int t=nt-1; t>=0; t--){ 279 if(specValType[t][0]==SPEC_COMP_DEF) 280 specValType[t][0] = SPEC_DEF; 281 } 282 compDef[0] = null; 283 break; 284 case SPEC_TILE_COMP: 285 specValType[0][0] = SPEC_DEF; 286 tileCompVal.put("t0c0",null); 287 break; 288 } 289 } 290 } 291 292 // Check consistency between filter and quantization type 293 // specification 294 for(int t=nt-1;t>=0;t--){ 295 for(int c=nc-1;c>=0;c--){ 296 // Reversible quantization 297 if( ((String)qts.getTileCompVal(t,c)).equals("reversible")){ 298 // If filter is reversible, it is OK 299 if(isReversible(t,c)) continue; 300 301 // If no filter has been defined, use reversible filter 302 if(!isFilterSpecified){ 303 setTileCompVal(t,c,parseFilters(REV_FILTER_STR)); 304 } 305 else{ 306 // Non reversible filter specified -> Error 307 throw new IllegalArgumentException("Filter of "+ 308 "tile-component"+ 309 " ("+t+","+c+") does"+ 310 " not allow "+ 311 "reversible "+ 312 "quantization. "+ 313 "Specify '-Qtype "+ 314 "expounded' or "+ 315 "'-Qtype derived'"+ 316 "in "+ 317 "the command line."); 318 } 319 } 320 else{ // No reversible quantization 321 // No reversible filter -> OK 322 if(!isReversible(t,c)) continue; 323 324 // If no filter has been specified, use non-reversible 325 // filter 326 if(!isFilterSpecified){ 327 setTileCompVal(t,c,parseFilters(NON_REV_FILTER_STR)); 328 } 329 else{ 330 // Reversible filter specified -> Error 331 throw new IllegalArgumentException("Filter of "+ 332 "tile-component"+ 333 " ("+t+","+c+") does"+ 334 " not allow "+ 335 "non-reversible "+ 336 "quantization. "+ 337 "Specify '-Qtype "+ 338 "reversible' in "+ 339 "the command line"); 340 } 341 } 342 } 343 } 344 } 345 346 /** 347 * Parse filters from the given word 348 * 349 * @param word String to parse 350 * 351 * @return Analysis wavelet filter (first dimension: by direction, 352 * second dimension: by decomposition levels) 353 */ 354 private AnWTFilter[][] parseFilters(String word){ 355 AnWTFilter[][] filt=new AnWTFilter[2][1]; 356 if(word.equalsIgnoreCase("w5x3")){ 357 filt[0][0]=new AnWTFilterIntLift5x3(); 358 filt[1][0]=new AnWTFilterIntLift5x3(); 359 return filt; 360 } 361 else if(word.equalsIgnoreCase("w9x7")){ 362 filt[0][0]=new AnWTFilterFloatLift9x7(); 363 filt[1][0]=new AnWTFilterFloatLift9x7(); 364 return filt; 365 } 366 else{ 367 throw new 368 IllegalArgumentException("Non JPEG 2000 part I filter: " 369 +word); 370 } 371 } 372 373 /** 374 * Returns the data type used by the filters in this object, as defined in 375 * the 'DataBlk' interface for specified tile-component. 376 * 377 * @param t Tile index 378 * 379 * @param c Component index 380 * 381 * @return The data type of the filters in this object 382 * 383 * @see jj2000.j2k.image.DataBlk 384 * */ 385 public int getWTDataType(int t,int c){ 386 AnWTFilter[][] an = (AnWTFilter[][])getSpec(t,c); 387 return an[0][0].getDataType(); 388 } 389 390 /** 391 * Returns the horizontal analysis filters to be used in component 'n' and 392 * tile 't'. 393 * 394 * <P>The horizontal analysis filters are returned in an array of 395 * AnWTFilter. Each element contains the horizontal filter for each 396 * resolution level starting with resolution level 1 (i.e. the analysis 397 * filter to go from resolution level 1 to resolution level 0). If there 398 * are less elements than the maximum resolution level, then the last 399 * element is assumed to be repeated. 400 * 401 * @param t The tile index, in raster scan order 402 * 403 * @param c The component index. 404 * 405 * @return The array of horizontal analysis filters for component 'n' and 406 * tile 't'. 407 * */ 408 public AnWTFilter[] getHFilters(int t, int c) { 409 AnWTFilter[][] an = (AnWTFilter[][])getSpec(t,c); 410 return an[0]; 411 } 412 413 /** 414 * Returns the vertical analysis filters to be used in component 'n' and 415 * tile 't'. 416 * 417 * <P>The vertical analysis filters are returned in an array of 418 * AnWTFilter. Each element contains the vertical filter for each 419 * resolution level starting with resolution level 1 (i.e. the analysis 420 * filter to go from resolution level 1 to resolution level 0). If there 421 * are less elements than the maximum resolution level, then the last 422 * element is assumed to be repeated. 423 * 424 * @param t The tile index, in raster scan order 425 * 426 * @param c The component index. 427 * 428 * @return The array of horizontal analysis filters for component 'n' and 429 * tile 't'. 430 * */ 431 public AnWTFilter[] getVFilters(int t,int c) { 432 AnWTFilter[][] an = (AnWTFilter[][])getSpec(t,c); 433 return an[1]; 434 } 435 436 /** Debugging method */ 437 public String toString(){ 438 String str = ""; 439 AnWTFilter[][] an; 440 441 str += "nTiles="+nTiles+"\nnComp="+nComp+"\n\n"; 442 443 for(int t=0; t<nTiles; t++){ 444 for(int c=0; c<nComp; c++){ 445 an = (AnWTFilter[][])getSpec(t,c); 446 447 str += "(t:"+t+",c:"+c+")\n"; 448 449 // Horizontal filters 450 str += "\tH:"; 451 for(int i=0; i<an[0].length; i++) 452 str += " "+an[0][i]; 453 // Horizontal filters 454 str += "\n\tV:"; 455 for(int i=0; i<an[1].length; i++) 456 str += " "+an[1][i]; 457 str += "\n"; 458 } 459 } 460 461 return str; 462 } 463 464 /** 465 * Check the reversibility of filters contained is the given 466 * tile-component. 467 * 468 * @param t The index of the tile 469 * 470 * @param c The index of the component 471 * */ 472 public boolean isReversible(int t,int c){ 473 // Note: no need to buffer the result since this method is 474 // normally called once per tile-component. 475 AnWTFilter[] 476 hfilter = getHFilters(t,c), 477 vfilter = getVFilters(t,c); 478 479 // As soon as a filter is not reversible, false can be returned 480 for(int i=hfilter.length-1; i>=0; i--) 481 if(!hfilter[i].isReversible() || !vfilter[i].isReversible()) 482 return false; 483 return true; 484 } 485}