001/* 002 * $RCSfile: ForwWTFull.java,v $ 003 * $Revision: 1.1 $ 004 * $Date: 2005/02/11 05:02:31 $ 005 * $State: Exp $ 006 * 007 * Class: ForwWTFull 008 * 009 * Description: This class implements the full page 010 * forward wavelet transform for both integer 011 * and floating point implementations. 012 * 013 * 014 * 015 * COPYRIGHT: 016 * 017 * This software module was originally developed by Raphaël Grosbois and 018 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel 019 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David 020 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research 021 * Centre France S.A) in the course of development of the JPEG2000 022 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This 023 * software module is an implementation of a part of the JPEG 2000 024 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio 025 * Systems AB and Canon Research Centre France S.A (collectively JJ2000 026 * Partners) agree not to assert against ISO/IEC and users of the JPEG 027 * 2000 Standard (Users) any of their rights under the copyright, not 028 * including other intellectual property rights, for this software module 029 * with respect to the usage by ISO/IEC and Users of this software module 030 * or modifications thereof for use in hardware or software products 031 * claiming conformance to the JPEG 2000 Standard. Those intending to use 032 * this software module in hardware or software products are advised that 033 * their use may infringe existing patents. The original developers of 034 * this software module, JJ2000 Partners and ISO/IEC assume no liability 035 * for use of this software module or modifications thereof. No license 036 * or right to this software module is granted for non JPEG 2000 Standard 037 * conforming products. JJ2000 Partners have full right to use this 038 * software module for his/her own purpose, assign or donate this 039 * software module to any third party and to inhibit third parties from 040 * using this software module for non JPEG 2000 Standard conforming 041 * products. This copyright notice must be included in all copies or 042 * derivative works of this software module. 043 * 044 * Copyright (c) 1999/2000 JJ2000 Partners. 045 * */ 046package jj2000.j2k.wavelet.analysis; 047import java.awt.Point; 048 049import jj2000.j2k.IntegerSpec; 050import jj2000.j2k.ModuleSpec; 051import jj2000.j2k.codestream.Markers; 052import jj2000.j2k.entropy.CBlkSizeSpec; 053import jj2000.j2k.entropy.PrecinctSizeSpec; 054//import jj2000.j2k.encoder.*; 055import jj2000.j2k.image.BlkImgDataSrc; 056import jj2000.j2k.image.DataBlk; 057import jj2000.j2k.image.DataBlkFloat; 058import jj2000.j2k.image.DataBlkInt; 059import jj2000.j2k.util.MathUtil; 060import jj2000.j2k.wavelet.Subband; 061import jj2000.j2k.wavelet.WaveletTransform; 062 063import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava; 064/** 065 * This class implements the ForwardWT with the full-page approach to be used 066 * either with integer or floating-point filters 067 * */ 068public class ForwWTFull extends ForwardWT { 069 070 /** Boolean to know if one are currently dealing with int or float 071 data. */ 072 private boolean intData; 073 074 /** 075 * The subband trees for each component, in each tile. The array is 076 * allocated by the constructor of this class. This array is updated by 077 * the getSubbandTree() method, an a as needed basis. The first index is 078 * the tile index (in lexicographical order) and the second index is the 079 * component index. 080 * 081 * <P>The subband tree for a component in the current tile is created on 082 * the first call to getSubbandTree() for that component, in the current 083 * tile. Before that the element in 'subbTrees' is null. 084 * */ 085 private SubbandAn subbTrees[][]; 086 087 /** The source of image data */ 088 private BlkImgDataSrc src; 089 090 /** The horizontal coordinate of the code-block partition origin on the 091 reference grid */ 092 private int cb0x; 093 094 /** The vertical coordinate of the code-block partition on the reference 095 grid */ 096 private int cb0y; 097 098 /** The number of decomposition levels specification */ 099 private IntegerSpec dls; 100 101 /** Wavelet filters for all components and tiles */ 102 private AnWTFilterSpec filters; 103 104 /** The code-block size specifications */ 105 private CBlkSizeSpec cblks; 106 107 /** The precinct partition specifications */ 108 private PrecinctSizeSpec pss; 109 110 /** Block storing the full band decomposition for each component. */ 111 private DataBlk decomposedComps[]; 112 113 /** 114 * The horizontal index of the last code-block "sent" in the current 115 * subband in each component. It should be -1 if none have been sent yet. 116 * */ 117 private int lastn[]; 118 119 /** 120 * The vertical index of the last code-block "sent" in the current subband 121 * in each component. It should be 0 if none have been sent yet. 122 * */ 123 private int lastm[]; 124 125 /** The subband being dealt with in each component */ 126 SubbandAn currentSubband[]; 127 128 /** Cache object to avoid excessive allocation/deallocation. This variable 129 * makes the class inheritently thread unsafe. */ 130 Point ncblks; 131 132 /** 133 * Initializes this object with the given source of image data and with 134 * all the decompositon parameters 135 * 136 * @param src From where the image data should be obtained. 137 * 138 * @param encSpec The encoder specifications 139 * 140 * @param pox The horizontal coordinate of the cell and code-block 141 * partition origin with respect to the canvas origin, on the reference 142 * grid. 143 * 144 * @param poy The vertical coordinate of the cell and code-block partition 145 * origin with respect to the canvas origin, on the reference grid. 146 * 147 * @see ForwardWT 148 * */ 149 public ForwWTFull(BlkImgDataSrc src,J2KImageWriteParamJava wp,int pox,int poy) { 150 super(src); 151 this.src = src; 152 153 this.cb0x = cb0x; 154 this.cb0y = cb0y; 155 this.dls = wp.getDecompositionLevel(); 156 this.filters = wp.getFilters(); 157 this.cblks = wp.getCodeBlockSize(); 158 this.pss = wp.getPrecinctPartition(); 159 160 int ncomp = src.getNumComps(); 161 int ntiles = src.getNumTiles(); 162 163 currentSubband = new SubbandAn[ncomp]; 164 decomposedComps = new DataBlk[ncomp]; 165 subbTrees = new SubbandAn[ntiles][ncomp]; 166 lastn = new int[ncomp]; 167 lastm = new int[ncomp]; 168 } 169 170 /** 171 * Returns the implementation type of this wavelet transform, WT_IMPL_FULL 172 * (full-page based transform). All components return the same. 173 * 174 * @param c The index of the component. 175 * 176 * @return WT_IMPL_FULL 177 * */ 178 public int getImplementationType(int c) { 179 return WaveletTransform.WT_IMPL_FULL; 180 } 181 182 /** 183 * Returns the number of decomposition levels that are applied to the LL 184 * band, in the specified tile-component. A value of 0 means that no 185 * wavelet transform is applied. 186 * 187 * @param t The tile index 188 * 189 * @param c The index of the component. 190 * 191 * @return The number of decompositions applied to the LL band (0 for no 192 * wavelet transform). 193 * */ 194 public int getDecompLevels(int t,int c) { 195 return ((Integer)dls.getTileCompVal(t,c)).intValue(); 196 } 197 198 /** 199 * Returns the wavelet tree decomposition. Actually JPEG 2000 part 1 only 200 * supports WT_DECOMP_DYADIC decomposition. 201 * 202 * @param t The tile-index 203 * 204 * @param c The index of the component. 205 * 206 * @return The wavelet decomposition. 207 * */ 208 public int getDecomp(int t,int c) { 209 return WT_DECOMP_DYADIC; 210 } 211 212 /** 213 * Returns the horizontal analysis wavelet filters used in each level, for 214 * the specified component and tile. The first element in the array is the 215 * filter used to obtain the lowest resolution (resolution level 0) 216 * subbands (i.e. lowest frequency LL subband), the second element is the 217 * one used to generate the resolution level 1 subbands, and so on. If 218 * there are less elements in the array than the number of resolution 219 * levels, then the last one is assumed to repeat itself. 220 * 221 * <P>The returned filters are applicable only to the specified component 222 * and in the current tile. 223 * 224 * <P>The resolution level of a subband is the resolution level to which a 225 * subband contributes, which is different from its decomposition level. 226 * 227 * @param t The index of the tile for which to return the filters. 228 * 229 * @param c The index of the component for which to return the filters. 230 * 231 * @return The horizontal analysis wavelet filters used in each level. 232 * */ 233 public AnWTFilter[] getHorAnWaveletFilters(int t,int c) { 234 return filters.getHFilters(t,c); 235 } 236 237 /** 238 * Returns the vertical analysis wavelet filters used in each level, for 239 * the specified component and tile. The first element in the array is the 240 * filter used to obtain the lowest resolution (resolution level 0) 241 * subbands (i.e. lowest frequency LL subband), the second element is the 242 * one used to generate the resolution level 1 subbands, and so on. If 243 * there are less elements in the array than the number of resolution 244 * levels, then the last one is assumed to repeat itself. 245 * 246 * <P>The returned filters are applicable only to the specified component 247 * and in the current tile. 248 * 249 * <P>The resolution level of a subband is the resolution level to which a 250 * subband contributes, which is different from its decomposition level. 251 * 252 * @param t The index of the tile for which to return the filters. 253 * 254 * @param c The index of the component for which to return the filters. 255 * 256 * @return The vertical analysis wavelet filters used in each level. 257 * */ 258 public AnWTFilter[] getVertAnWaveletFilters(int t,int c) { 259 return filters.getVFilters(t,c); 260 } 261 262 /** 263 * Returns the reversibility of the wavelet transform for the specified 264 * component and tile. A wavelet transform is reversible when it is 265 * suitable for lossless and lossy-to-lossless compression. 266 * 267 * @param t The index of the tile. 268 * 269 * @param c The index of the component. 270 * 271 * @return true is the wavelet transform is reversible, false if not. 272 * */ 273 public boolean isReversible(int t,int c) { 274 return filters.isReversible(t,c); 275 } 276 277 /** 278 * Returns the horizontal offset of the code-block partition. Allowable 279 * values are 0 and 1, nothing else. 280 * */ 281 public int getCbULX() { 282 return cb0x; 283 } 284 285 /** 286 * Returns the vertical offset of the code-block partition. Allowable 287 * values are 0 and 1, nothing else. 288 * */ 289 public int getCbULY() { 290 return cb0y; 291 } 292 293 /** 294 * Returns the position of the fixed point in the specified 295 * component. This is the position of the least significant integral 296 * (i.e. non-fractional) bit, which is equivalent to the number of 297 * fractional bits. For instance, for fixed-point values with 2 fractional 298 * bits, 2 is returned. For floating-point data this value does not apply 299 * and 0 should be returned. Position 0 is the position of the least 300 * significant bit in the data. 301 * 302 * @param c The index of the component. 303 * 304 * @return The position of the fixed-point, which is the same as the 305 * number of fractional bits. For floating-point data 0 is returned. 306 * */ 307 public int getFixedPoint(int c) { 308 return src.getFixedPoint(c); 309 } 310 311 312 /** 313 * Returns the next code-block in the current tile for the specified 314 * component. The order in which code-blocks are returned is not 315 * specified. However each code-block is returned only once and all 316 * code-blocks will be returned if the method is called 'N' times, where 317 * 'N' is the number of code-blocks in the tile. After all the code-blocks 318 * have been returned for the current tile calls to this method will 319 * return 'null'. 320 * 321 * <p>When changing the current tile (through 'setTile()' or 'nextTile()') 322 * this method will always return the first code-block, as if this method 323 * was never called before for the new current tile.</p> 324 * 325 * <p>The data returned by this method is the data in the internal buffer 326 * of this object, and thus can not be modified by the caller. The 327 * 'offset' and 'scanw' of the returned data have, in general, some 328 * non-zero value. The 'magbits' of the returned data is not set by this 329 * method and should be ignored. See the 'CBlkWTData' class.</p> 330 * 331 * <p>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object 332 * contain the coordinates of the top-left corner of the block, with 333 * respect to the tile, not the subband.</p> 334 * 335 * @param c The component for which to return the next code-block. 336 * 337 * @param cblk If non-null this object will be used to return the new 338 * code-block. If null a new one will be allocated and returned. 339 * 340 * @return The next code-block in the current tile for component 'n', or 341 * null if all code-blocks for the current tile have been returned. 342 * 343 * @see CBlkWTData 344 * */ 345 public CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk) { 346 int cbm,cbn,cn,cm; 347 int acb0x, acb0y; 348 SubbandAn sb; 349 intData = (filters.getWTDataType(tIdx,c)==DataBlk.TYPE_INT); 350 351 //If the source image has not been decomposed 352 if(decomposedComps[c]==null) { 353 int k,w,h; 354 DataBlk bufblk; 355 Object dst_data; 356 357 w = getTileCompWidth(tIdx,c); 358 h = getTileCompHeight(tIdx,c); 359 360 //Get the source image data 361 if(intData) { 362 decomposedComps[c] = new DataBlkInt(0,0,w,h); 363 bufblk = new DataBlkInt(); 364 } else { 365 decomposedComps[c] = new DataBlkFloat(0,0,w,h); 366 bufblk = new DataBlkFloat(); 367 } 368 369 // Get data from source line by line (this diminishes the memory 370 // requirements on the data source) 371 dst_data = decomposedComps[c].getData(); 372 int lstart = getCompULX(c); 373 bufblk.ulx = lstart; 374 bufblk.w = w; 375 bufblk.h = 1; 376 int kk = getCompULY(c); 377 for (k=0; k<h; k++,kk++) { 378 bufblk.uly = kk; 379 bufblk.ulx = lstart; 380 bufblk = src.getInternCompData(bufblk,c); 381 System.arraycopy(bufblk.getData(),bufblk.offset, 382 dst_data,k*w,w); 383 } 384 385 //Decompose source image 386 waveletTreeDecomposition(decomposedComps[c], 387 getAnSubbandTree(tIdx,c),c); 388 389 // Make the first subband the current one 390 currentSubband[c] = getNextSubband(c); 391 392 lastn[c] = -1; 393 lastm[c] = 0; 394 } 395 396 // Get the next code-block to "send" 397 do { 398 // Calculate number of code-blocks in current subband 399 ncblks = currentSubband[c].numCb; 400 // Goto next code-block 401 lastn[c]++; 402 if (lastn[c] == ncblks.x) { // Got to end of this row of 403 // code-blocks 404 lastn[c] = 0; 405 lastm[c]++; 406 } 407 if (lastm[c] < ncblks.y) { 408 // Not past the last code-block in the subband, we can return 409 // this code-block 410 break; 411 } 412 // If we get here we already sent all code-blocks in this subband, 413 // goto next subband 414 currentSubband[c] = getNextSubband(c); 415 lastn[c] = -1; 416 lastm[c] = 0; 417 if ( currentSubband[c] == null ) { 418 // We don't need the transformed data any more (a priori) 419 decomposedComps[c] = null; 420 // All code-blocks from all subbands in the current 421 // tile have been returned so we return a null 422 // reference 423 return null; 424 } 425 // Loop to find the next code-block 426 } while (true); 427 428 429 // Project code-block partition origin to subband. Since the origin is 430 // always 0 or 1, it projects to the low-pass side (throught the ceil 431 // operator) as itself (i.e. no change) and to the high-pass side 432 // (through the floor operator) as 0, always. 433 acb0x = cb0x; 434 acb0y = cb0y; 435 switch (currentSubband[c].sbandIdx) { 436 case Subband.WT_ORIENT_LL: 437 // No need to project since all low-pass => nothing to do 438 break; 439 case Subband.WT_ORIENT_HL: 440 acb0x = 0; 441 break; 442 case Subband.WT_ORIENT_LH: 443 acb0y = 0; 444 break; 445 case Subband.WT_ORIENT_HH: 446 acb0x = 0; 447 acb0y = 0; 448 break; 449 default: 450 throw new Error("Internal JJ2000 error"); 451 } 452 // Initialize output code-block 453 if (cblk==null) { 454 if (intData) { 455 cblk = new CBlkWTDataInt(); 456 } else { 457 cblk = new CBlkWTDataFloat(); 458 } 459 } 460 cbn = lastn[c]; 461 cbm = lastm[c]; 462 sb = currentSubband[c]; 463 cblk.n = cbn; 464 cblk.m = cbm; 465 cblk.sb = sb; 466 // Calculate the indexes of first code-block in subband with respect 467 // to the partitioning origin, to then calculate the position and size 468 // NOTE: when calculating "floor()" by integer division the dividend 469 // and divisor must be positive, we ensure that by adding the divisor 470 // to the dividend and then substracting 1 to the result of the 471 // division 472 cn = (sb.ulcx-acb0x+sb.nomCBlkW)/sb.nomCBlkW-1; 473 cm = (sb.ulcy-acb0y+sb.nomCBlkH)/sb.nomCBlkH-1; 474 if (cbn == 0) { // Left-most code-block, starts where subband starts 475 cblk.ulx = sb.ulx; 476 } else { 477 // Calculate starting canvas coordinate and convert to subb. coords 478 cblk.ulx = (cn+cbn)*sb.nomCBlkW - (sb.ulcx-acb0x) + sb.ulx; 479 } 480 if (cbm == 0) { // Bottom-most code-block, starts where subband starts 481 cblk.uly = sb.uly; 482 } else { 483 cblk.uly = (cm+cbm)*sb.nomCBlkH - (sb.ulcy-acb0y) + sb.uly; 484 } 485 if (cbn < ncblks.x-1) { 486 // Calculate where next code-block starts => width 487 cblk.w = (cn+cbn+1)*sb.nomCBlkW - (sb.ulcx-acb0x) + sb.ulx - 488 cblk.ulx; 489 } else { // Right-most code-block, ends where subband ends 490 cblk.w = sb.ulx+sb.w-cblk.ulx; 491 } 492 if (cbm < ncblks.y-1) { 493 // Calculate where next code-block starts => height 494 cblk.h = (cm+cbm+1)*sb.nomCBlkH - (sb.ulcy-acb0y) + sb.uly - 495 cblk.uly; 496 } else { // Bottom-most code-block, ends where subband ends 497 cblk.h = sb.uly+sb.h-cblk.uly; 498 } 499 cblk.wmseScaling = 1f; 500 501 // Since we are in getNextInternCodeBlock() we can return a 502 // reference to the internal buffer, no need to copy. Just initialize 503 // the 'offset' and 'scanw' 504 cblk.offset = cblk.uly*decomposedComps[c].w+cblk.ulx; 505 cblk.scanw = decomposedComps[c].w; 506 507 // For the data just put a reference to our buffer 508 cblk.setData(decomposedComps[c].getData()); 509 // Return code-block 510 return cblk; 511 } 512 513 /** 514 * Returns the next code-block in the current tile for the specified 515 * component, as a copy (see below). The order in which code-blocks are 516 * returned is not specified. However each code-block is returned only 517 * once and all code-blocks will be returned if the method is called 'N' 518 * times, where 'N' is the number of code-blocks in the tile. After all 519 * the code-blocks have been returned for the current tile calls to this 520 * method will return 'null'. 521 * 522 * <P>When changing the current tile (through 'setTile()' or 'nextTile()') 523 * this method will always return the first code-block, as if this method 524 * was never called before for the new current tile. 525 * 526 * <P>The data returned by this method is always a copy of the internal 527 * data of this object, and it can be modified "in place" without 528 * any problems after being returned. The 'offset' of the returned data is 529 * 0, and the 'scanw' is the same as the code-block width. The 'magbits' 530 * of the returned data is not set by this method and should be 531 * ignored. See the 'CBlkWTData' class. 532 * 533 * <P>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object 534 * contain the coordinates of the top-left corner of the block, with 535 * respect to the tile, not the subband. 536 * 537 * @param c The component for which to return the next code-block. 538 * 539 * @param cblk If non-null this object will be used to return the new 540 * code-block. If null a new one will be allocated and returned. If the 541 * "data" array of the object is non-null it will be reused, if possible, 542 * to return the data. 543 * 544 * @return The next code-block in the current tile for component 'c', or 545 * null if all code-blocks for the current tile have been returned. 546 * 547 * @see CBlkWTData 548 * */ 549 public CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk) { 550 // We can not directly use getNextInternCodeBlock() since that returns 551 // a reference to the internal buffer, we have to copy that data 552 553 int j,k; 554 int w; 555 Object dst_data; // a int[] or float[] object 556 int[] dst_data_int; 557 float[] dst_data_float; 558 Object src_data; // a int[] or float[] object 559 560 intData = (filters.getWTDataType(tIdx,c)==DataBlk.TYPE_INT); 561 562 dst_data = null; 563 564 // Cache the data array, if any 565 if (cblk != null) { 566 dst_data = cblk.getData(); 567 } 568 569 // Get the next code-block 570 cblk = getNextInternCodeBlock(c,cblk); 571 572 if (cblk == null) { 573 return null; // No more code-blocks in current tile for component 574 // c 575 } 576 577 // Ensure size of output buffer 578 if (intData) { // int data 579 dst_data_int = (int[]) dst_data; 580 if (dst_data_int == null || dst_data_int.length < cblk.w*cblk.h) { 581 dst_data = new int[cblk.w*cblk.h]; 582 } 583 } 584 else { // float data 585 dst_data_float = (float[]) dst_data; 586 if (dst_data_float == null || 587 dst_data_float.length < cblk.w*cblk.h) { 588 dst_data = new float[cblk.w*cblk.h]; 589 } 590 } 591 592 // Copy data line by line 593 src_data = cblk.getData(); 594 w = cblk.w; 595 for (j = w*(cblk.h-1), k = cblk.offset+(cblk.h-1)*cblk.scanw; 596 j >= 0; j -= w, k -= cblk.scanw) { 597 System.arraycopy(src_data,k,dst_data,j,w); 598 } 599 cblk.setData(dst_data); 600 cblk.offset = 0; 601 cblk.scanw = w; 602 603 return cblk; 604 } 605 606 /** 607 * Return the data type of this CBlkWTDataSrc. Its value should be either 608 * DataBlk.TYPE_INT or DataBlk.TYPE_FLOAT but can change according to the 609 * current tile-component. 610 * 611 * @param t The index of the tile for which to return the data type. 612 * 613 * @param c The index of the component for which to return the data type. 614 * 615 * @return Current data type 616 * */ 617 public int getDataType(int t,int c){ 618 return filters.getWTDataType(t,c); 619 } 620 621 /** 622 * Returns the next subband that will be used to get the next code-block 623 * to return by the getNext[Intern]CodeBlock method. 624 * 625 * @param c The component 626 * 627 * @return Its returns the next subband that will be used to get the next 628 * code-block to return by the getNext[Intern]CodeBlock method. 629 **/ 630 private SubbandAn getNextSubband(int c) { 631 int down = 1; 632 int up = 0; 633 int direction = down; 634 SubbandAn nextsb; 635 636 nextsb = currentSubband[c]; 637 //If it is the first call to this method 638 if(nextsb == null) { 639 nextsb = this.getAnSubbandTree(tIdx,c); 640 //If there is no decomposition level then send the whole image 641 if(!nextsb.isNode) { 642 return nextsb; 643 } 644 } 645 646 //Find the next subband to send 647 do { 648 //If the current subband is null then break 649 if(nextsb == null) { 650 break; 651 } 652 653 //If the current subband is a leaf then select the next leaf to 654 //send or go up in the decomposition tree if the leaf was a LL 655 //one. 656 else if(!nextsb.isNode) { 657 switch (nextsb.orientation) { 658 case Subband.WT_ORIENT_HH : 659 nextsb = (SubbandAn)nextsb.getParent().getLH(); 660 direction = down; 661 break; 662 case Subband.WT_ORIENT_LH : 663 nextsb = (SubbandAn)nextsb.getParent().getHL(); 664 direction = down; 665 break; 666 case Subband.WT_ORIENT_HL : 667 nextsb = (SubbandAn)nextsb.getParent().getLL(); 668 direction = down; 669 break; 670 case Subband.WT_ORIENT_LL : 671 nextsb = (SubbandAn)nextsb.getParent(); 672 direction = up; 673 break; 674 } 675 } 676 677 //Else if the current subband is a node 678 else if(nextsb.isNode) { 679 //If the direction is down the select the HH subband of the 680 //current node. 681 if(direction == down) { 682 nextsb = (SubbandAn)nextsb.getHH(); 683 } 684 //Else the direction is up the select the next node to cover 685 //or still go up in the decomposition tree if the node is a LL 686 //subband 687 else if(direction == up) { 688 switch (nextsb.orientation) { 689 case Subband.WT_ORIENT_HH : 690 nextsb = (SubbandAn)nextsb.getParent().getLH(); 691 direction = down; 692 break; 693 case Subband.WT_ORIENT_LH : 694 nextsb = (SubbandAn)nextsb.getParent().getHL(); 695 direction = down; 696 break; 697 case Subband.WT_ORIENT_HL : 698 nextsb = (SubbandAn)nextsb.getParent().getLL(); 699 direction = down; 700 break; 701 case Subband.WT_ORIENT_LL : 702 nextsb = (SubbandAn)nextsb.getParent(); 703 direction = up; 704 break; 705 } 706 } 707 } 708 709 if(nextsb == null) { 710 break; 711 } 712 } while(nextsb.isNode); 713 return nextsb; 714 } 715 716 /** 717 * Performs the forward wavelet transform on the whole band. It 718 * iteratively decomposes the subbands from the top node to the leaves. 719 * 720 * @param band The band containing the float data to decompose 721 * 722 * @param subband The structure containing the coordinates of the current 723 * subband in the whole band to decompose. 724 * 725 * @param c The index of the current component to decompose 726 * */ 727 private void waveletTreeDecomposition(DataBlk band, 728 SubbandAn subband, int c) { 729 730 //If the current subband is a leaf then nothing to be done (a leaf is 731 //not decomposed). 732 if(!subband.isNode) 733 return; 734 735 else { 736 //Perform the 2D wavelet decomposition of the current subband 737 wavelet2DDecomposition(band, (SubbandAn)subband, c); 738 739 //Perform the decomposition of the four resulting subbands 740 waveletTreeDecomposition(band, (SubbandAn)subband.getHH(), c); 741 waveletTreeDecomposition(band, (SubbandAn)subband.getLH(), c); 742 waveletTreeDecomposition(band, (SubbandAn)subband.getHL(), c); 743 waveletTreeDecomposition(band, (SubbandAn)subband.getLL(), c); 744 } 745 } 746 747 /** 748 * Performs the 2D forward wavelet transform on a subband of the initial 749 * band. This method will successively perform 1D filtering steps on all 750 * lines and then all columns of the subband. In this class only filters 751 * with floating point implementations can be used. 752 * 753 * @param band The band containing the float data to decompose 754 * 755 * @param subband The structure containing the coordinates of the subband 756 * in the whole band to decompose. 757 * 758 * @param c The index of the current component to decompose 759 * */ 760 private void wavelet2DDecomposition(DataBlk band, 761 SubbandAn subband, int c) { 762 763 int ulx, uly, w, h; 764 int band_w, band_h; 765 766 // If subband is empty (i.e. zero size) nothing to do 767 if (subband.w == 0 || subband.h == 0) { 768 return; 769 } 770 771 ulx = subband.ulx; 772 uly = subband.uly; 773 w = subband.w; 774 h = subband.h; 775 band_w = getTileCompWidth(tIdx, c); 776 band_h = getTileCompHeight(tIdx, c); 777 778 if ( intData ) { 779 //Perform the decompositions if the filter is implemented with an 780 //integer arithmetic. 781 int i, j; 782 int offset; 783 int[] tmpVector = new int[java.lang.Math.max(w,h)]; 784 785 int[] data = ((DataBlkInt)band).getDataInt(); 786 787 //Perform the vertical decomposition 788 if (subband.ulcy%2==0) { // Even start index => use LPF 789 for(j=0; j<w; j++) { 790 offset = uly*band_w + ulx+j; 791 for(i=0; i<h; i++) 792 tmpVector[i] = data[offset+(i*band_w)]; 793 subband.vFilter.analyze_lpf(tmpVector, 0, h, 1, 794 data, offset, band_w, 795 data, offset+((h+1)/2)*band_w, 796 band_w); 797 } 798 } 799 else { // Odd start index => use HPF 800 for(j=0; j<w; j++) { 801 offset = uly*band_w + ulx+j; 802 for(i=0; i<h; i++) 803 tmpVector[i] = data[offset+(i*band_w)]; 804 subband.vFilter.analyze_hpf(tmpVector, 0, h, 1, 805 data, offset, band_w, 806 data, offset+(h/2)*band_w, 807 band_w); 808 } 809 } 810 811 //Perform the horizontal decomposition. 812 if (subband.ulcx%2==0) { // Even start index => use LPF 813 for(i=0; i<h; i++) { 814 offset = (uly+i)*band_w + ulx; 815 for(j=0; j<w; j++) 816 tmpVector[j] = data[offset+j]; 817 subband.hFilter.analyze_lpf(tmpVector, 0, w, 1, 818 data, offset, 1, 819 data, offset+(w+1)/2, 1); 820 } 821 } 822 else { // Odd start index => use HPF 823 for(i=0; i<h; i++) { 824 offset = (uly+i)*band_w + ulx; 825 for(j=0; j<w; j++) 826 tmpVector[j] = data[offset+j]; 827 subband.hFilter.analyze_hpf(tmpVector, 0, w, 1, 828 data, offset, 1, 829 data, offset+w/2, 1); 830 } 831 } 832 } 833 else { 834 //Perform the decompositions if the filter is implemented with a 835 //float arithmetic. 836 int i, j; 837 int offset; 838 float[] tmpVector = new float[java.lang.Math.max(w,h)]; 839 float[]data = ((DataBlkFloat)band).getDataFloat(); 840 841 //Perform the vertical decomposition. 842 if (subband.ulcy%2==0) { // Even start index => use LPF 843 for(j=0; j<w; j++) { 844 offset = uly*band_w + ulx+j; 845 for(i=0; i<h; i++) 846 tmpVector[i] = data[offset+(i*band_w)]; 847 subband.vFilter.analyze_lpf(tmpVector, 0, h, 1, 848 data, offset, band_w, 849 data, offset+((h+1)/2)*band_w, 850 band_w); 851 } 852 } 853 else { // Odd start index => use HPF 854 for(j=0; j<w; j++) { 855 offset = uly*band_w + ulx+j; 856 for(i=0; i<h; i++) 857 tmpVector[i] = data[offset+(i*band_w)]; 858 subband.vFilter.analyze_hpf(tmpVector, 0, h, 1, 859 data, offset, band_w, 860 data, offset+(h/2)*band_w, 861 band_w); 862 } 863 } 864 //Perform the horizontal decomposition. 865 if (subband.ulcx%2==0) { // Even start index => use LPF 866 for(i=0; i<h; i++) { 867 offset = (uly+i)*band_w + ulx; 868 for(j=0; j<w; j++) 869 tmpVector[j] = data[offset+j]; 870 subband.hFilter.analyze_lpf(tmpVector, 0, w, 1, 871 data, offset, 1, 872 data, offset+(w+1)/2, 1); 873 } 874 } 875 else { // Odd start index => use HPF 876 for(i=0; i<h; i++) { 877 offset = (uly+i)*band_w + ulx; 878 for(j=0; j<w; j++) 879 tmpVector[j] = data[offset+j]; 880 subband.hFilter.analyze_hpf(tmpVector, 0, w, 1, 881 data, offset, 1, 882 data, offset+w/2, 1); 883 } 884 } 885 } 886 } 887 888 /** 889 * Changes the current tile, given the new coordinates. 890 * 891 * <P>This method resets the 'subbTrees' array, and recalculates the 892 * values of the 'reversible' array. It also resets the decomposed 893 * component buffers. 894 * 895 * @param x The horizontal coordinate of the tile. 896 * 897 * @param y The vertical coordinate of the new tile. 898 * */ 899 public void setTile(int x, int y) { 900 int i; 901 902 // Change tile 903 super.setTile(x,y); 904 905 // Reset the decomposed component buffers. 906 if (decomposedComps != null) { 907 for (i=decomposedComps.length-1; i>=0; i--) { 908 decomposedComps[i] = null; 909 currentSubband[i] = null; 910 } 911 } 912 913 } 914 915 /** 916 * Advances to the next tile, in standard scan-line order (by rows then 917 * columns). An NoNextElementException is thrown if the current tile is 918 * the last one (i.e. there is no next tile). 919 * 920 * <P>This method resets the 'subbTrees' array, and recalculates the 921 * values of the 'reversible' array. It also resets the decomposed 922 * component buffers. 923 * */ 924 public void nextTile() { 925 int i; 926 927 // Change tile 928 super.nextTile(); 929 // Reset the decomposed component buffers 930 if (decomposedComps != null) { 931 for (i=decomposedComps.length-1; i>=0; i--) { 932 decomposedComps[i] = null; 933 currentSubband[i] = null; 934 } 935 } 936 937 } 938 939 /** 940 * Returns a reference to the subband tree structure representing the 941 * subband decomposition for the specified tile-component of the source. 942 * 943 * @param t The index of the tile. 944 * 945 * @param c The index of the component. 946 * 947 * @return The subband tree structure, see Subband. 948 * 949 * @see SubbandAn 950 * @see Subband 951 * */ 952 public SubbandAn getAnSubbandTree(int t,int c) { 953 if (subbTrees[t][c] == null) { 954 subbTrees[t][c] = 955 new SubbandAn(getTileCompWidth(tIdx, c),getTileCompHeight(tIdx, c), 956 getCompULX(c),getCompULY(c), 957 getDecompLevels(t,c), 958 getHorAnWaveletFilters(t,c), 959 getVertAnWaveletFilters(t,c)); 960 initSubbandsFields(t,c,subbTrees[t][c]); 961 } 962 return subbTrees[t][c]; 963 } 964 965 /** 966 * Initialises subbands fields, such as number of code-blocks and 967 * code-blocks dimension, in the subband tree. The nominal code-block 968 * width/height depends on the precincts dimensions if used. 969 * 970 * @param t The tile index of the subband 971 * 972 * @param c The component index 973 * 974 * @param sb The subband tree to be initialised. 975 * */ 976 private void initSubbandsFields(int t,int c,Subband sb) { 977 int cbw = cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_COMP,t,c); 978 int cbh = cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_COMP,t,c); 979 980 if (!sb.isNode) { 981 // Code-blocks dimension 982 int ppx, ppy; 983 int ppxExp, ppyExp, cbwExp, cbhExp; 984 ppx = pss.getPPX(t,c,sb.resLvl); 985 ppy = pss.getPPY(t,c,sb.resLvl); 986 987 if (ppx!=Markers.PRECINCT_PARTITION_DEF_SIZE 988 || ppy!=Markers.PRECINCT_PARTITION_DEF_SIZE ) { 989 990 ppxExp = MathUtil.log2(ppx); 991 ppyExp = MathUtil.log2(ppy); 992 cbwExp = MathUtil.log2(cbw); 993 cbhExp = MathUtil.log2(cbh); 994 995 // Precinct partition is used 996 switch (sb.resLvl) { 997 case 0: 998 sb.nomCBlkW = ( cbwExp<ppxExp ? 999 (1<<cbwExp) : (1<<ppxExp) ); 1000 sb.nomCBlkH = ( cbhExp<ppyExp ? 1001 (1<<cbhExp) : (1<<ppyExp) ); 1002 break; 1003 1004 default: 1005 sb.nomCBlkW = ( cbwExp<ppxExp-1 ? 1006 (1<<cbwExp) : (1<<(ppxExp-1)) ); 1007 sb.nomCBlkH = ( cbhExp<ppyExp-1 ? 1008 (1<<cbhExp) : (1<<(ppyExp-1)) ); 1009 break; 1010 } 1011 } else { 1012 sb.nomCBlkW = cbw; 1013 sb.nomCBlkH = cbh; 1014 } 1015 1016 // Number of code-blocks 1017 if(sb.numCb==null) sb.numCb = new Point(); 1018 if(sb.w!=0 && sb.h!=0) { 1019 int acb0x = cb0x; 1020 int acb0y = cb0y; 1021 int tmp; 1022 1023 // Project code-block partition origin to subband. Since the 1024 // origin is always 0 or 1, it projects to the low-pass side 1025 // (throught the ceil operator) as itself (i.e. no change) and 1026 // to the high-pass side (through the floor operator) as 0, 1027 // always. 1028 switch (sb.sbandIdx) { 1029 case Subband.WT_ORIENT_LL: 1030 // No need to project since all low-pass => nothing to do 1031 break; 1032 case Subband.WT_ORIENT_HL: 1033 acb0x = 0; 1034 break; 1035 case Subband.WT_ORIENT_LH: 1036 acb0y = 0; 1037 break; 1038 case Subband.WT_ORIENT_HH: 1039 acb0x = 0; 1040 acb0y = 0; 1041 break; 1042 default: 1043 throw new Error("Internal JJ2000 error"); 1044 } 1045 if(sb.ulcx-acb0x<0 || sb.ulcy-acb0y<0) { 1046 throw new IllegalArgumentException("Invalid code-blocks "+ 1047 "partition origin or "+ 1048 "image offset in the "+ 1049 "reference grid."); 1050 } 1051 // NOTE: when calculating "floor()" by integer division the 1052 // dividend and divisor must be positive, we ensure that by 1053 // adding the divisor to the dividend and then substracting 1 1054 // to the result of the division 1055 tmp = sb.ulcx-acb0x+sb.nomCBlkW; 1056 sb.numCb.x = (tmp+sb.w-1)/sb.nomCBlkW - (tmp/sb.nomCBlkW-1); 1057 tmp = sb.ulcy-acb0y+sb.nomCBlkH; 1058 sb.numCb.y = (tmp+sb.h-1)/sb.nomCBlkH - (tmp/sb.nomCBlkH-1); 1059 } else { 1060 sb.numCb.x = sb.numCb.y = 0; 1061 } 1062 } else { 1063 initSubbandsFields(t,c,sb.getLL()); 1064 initSubbandsFields(t,c,sb.getHL()); 1065 initSubbandsFields(t,c,sb.getLH()); 1066 initSubbandsFields(t,c,sb.getHH()); 1067 } 1068 } 1069 1070}