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