001/* 002 * $RCSfile: HeaderEncoder.java,v $ 003 * $Revision: 1.1 $ 004 * $Date: 2005/02/11 05:02:02 $ 005 * $State: Exp $ 006 * 007 * Class: HeaderEncoder 008 * 009 * Description: Write codestream headers. 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.codestream.writer; 045import java.awt.Point; 046 047import jj2000.j2k.quantization.quantizer.*; 048import jj2000.j2k.wavelet.analysis.*; 049import jj2000.j2k.entropy.encoder.*; 050import jj2000.j2k.quantization.*; 051import jj2000.j2k.image.input.*; 052import jj2000.j2k.roi.encoder.*; 053import jj2000.j2k.codestream.*; 054import jj2000.j2k.wavelet.*; 055import jj2000.j2k.entropy.*; 056import jj2000.j2k.image.*; 057import jj2000.j2k.util.*; 058import jj2000.j2k.io.*; 059import jj2000.j2k.*; 060 061import java.util.*; 062import java.io.*; 063 064import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava; 065/** 066 * This class writes almost of the markers and marker segments in main header 067 * and in tile-part headers. It is created by the run() method of the Encoder 068 * instance. 069 * 070 * <p>A marker segment includes a marker and eventually marker segment 071 * parameters. It is designed by the three letter code of the marker 072 * associated with the marker segment. JPEG 2000 part I defines 6 types of 073 * markers: <ul> <li> Delimiting : SOC,SOT,SOD,EOC (written in 074 * FileCodestreamWriter).</li> <li> Fixed information: SIZ.</li> <li> 075 * Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream: SOP,EPH.</li> 076 * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li> <li> Informational: 077 * CRG,COM.</li></ul> 078 * 079 * <p>Main Header is written when Encoder instance calls encodeMainHeader 080 * whereas tile-part headers are written when the EBCOTRateAllocator instance 081 * calls encodeTilePartHeader. 082 * 083 * @see Encoder 084 * @see Markers 085 * @see EBCOTRateAllocator 086 * */ 087public class HeaderEncoder implements Markers, StdEntropyCoderOptions { 088 089 /** Nominal range bit of the component defining default values in QCD for 090 * main header */ 091 private int defimgn; 092 093 /** Nominal range bit of the component defining default values in QCD for 094 * tile headers */ 095 private int deftilenr; 096 097 /** The number of components in the image */ 098 protected int nComp; 099 100 /** Whether or not to write the JJ2000 COM marker segment */ 101 private boolean enJJ2KMarkSeg = true; 102 103 /** Other COM marker segments specified in the command line */ 104 private String otherCOMMarkSeg = null; 105 106 /** The ByteArrayOutputStream to store header data. This handler 107 * is kept in order to use methods not accessible from a general 108 * DataOutputStream. For the other methods, it's better to use 109 * variable hbuf. 110 * 111 * @see #hbuf */ 112 protected ByteArrayOutputStream baos; 113 114 /** The DataOutputStream to store header data. This kind of object 115 * is useful to write short, int, .... It's constructor takes 116 * baos as parameter. 117 * 118 * @see #baos 119 **/ 120 protected DataOutputStream hbuf; 121 122 /** The image data reader. Source of original data info */ 123 protected ImgData origSrc; 124 125 /** An array specifying, for each component,if the data was signed 126 or not */ 127 protected boolean isOrigSig[]; 128 129 /** Reference to the rate allocator */ 130 protected PostCompRateAllocator ralloc; 131 132 /** Reference to the DWT module */ 133 protected ForwardWT dwt; 134 135 /** Reference to the tiler module */ 136 protected Tiler tiler; 137 138 /** Reference to the ROI module */ 139 protected ROIScaler roiSc; 140 141 /** The encoder specifications */ 142 protected J2KImageWriteParamJava wp; 143 144 /** 145 * Initializes the header writer with the references to the coding chain. 146 * 147 * @param origsrc The original image data (before any component mixing, 148 * tiling, etc.) 149 * 150 * @param isorigsig An array specifying for each component if it was 151 * originally signed or not. 152 * 153 * @param dwt The discrete wavelet transform module. 154 * 155 * @param tiler The tiler module. 156 * 157 * @param encSpec The encoder specifications 158 * 159 * @param roiSc The ROI scaler module. 160 * 161 * @param ralloc The post compression rate allocator. 162 * */ 163 public HeaderEncoder(ImgData origsrc, boolean isorigsig[], 164 ForwardWT dwt, Tiler tiler,J2KImageWriteParamJava wp, 165 ROIScaler roiSc, PostCompRateAllocator ralloc) { 166 if (origsrc.getNumComps() != isorigsig.length) { 167 throw new IllegalArgumentException(); 168 } 169 this.origSrc = origsrc; 170 this.isOrigSig = isorigsig; 171 this.dwt = dwt; 172 this.tiler = tiler; 173 this.wp = wp; 174 this.roiSc = roiSc; 175 this.ralloc = ralloc; 176 177 baos = new ByteArrayOutputStream(); 178 hbuf = new DataOutputStream(baos); 179 nComp = origsrc.getNumComps(); 180// enJJ2KMarkSeg = wp.getHjj2000_COM(); 181// otherCOMMarkSeg = wp.getHCOM(); 182 } 183 184 /** 185 * Resets the contents of this HeaderEncoder to its initial state. It 186 * erases all the data in the header buffer and reactualizes the 187 * headerLength field of the bit stream writer. 188 * */ 189 public void reset() { 190 baos.reset(); 191 hbuf = new DataOutputStream(baos); 192 } 193 194 /** 195 * Returns the byte-buffer used to store the codestream header. 196 * 197 * @return A byte array countaining codestream header 198 * */ 199 protected byte[] getBuffer(){ 200 return baos.toByteArray(); 201 } 202 203 /** 204 * Returns the length of the header. 205 * 206 * @return The length of the header in bytes 207 * */ 208 public int getLength() { 209 return hbuf.size(); 210 } 211 212 /** 213 * Writes the header to the specified BinaryDataOutput. 214 * 215 * @param out Where to write the header. 216 * */ 217 public void writeTo(BinaryDataOutput out) throws IOException { 218 int i,len; 219 byte buf[]; 220 221 buf = getBuffer(); 222 len = getLength(); 223 224 for (i=0; i<len; i++) { 225 out.writeByte(buf[i]); 226 } 227 } 228 229 /** 230 * Returns the number of bytes used in the codestream header's 231 * buffer. 232 * 233 * @return Header length in buffer (without any header 234 * overhead) 235 * */ 236 protected int getBufferLength(){ 237 return baos.size(); 238 } 239 240 /** 241 * Writes the header to the specified OutputStream. 242 * 243 * @param out Where to write the header. 244 * */ 245 public void writeTo(OutputStream out) throws IOException { 246 out.write(getBuffer(),0,getBufferLength()); 247 } 248 249 /** 250 * Start Of Codestream marker (SOC) signalling the beginning of a 251 * codestream. 252 * */ 253 private void writeSOC() throws IOException { 254 hbuf.writeShort(SOC); 255 } 256 257 /** 258 * Writes SIZ marker segment of the codestream header. It is a fixed 259 * information marker segment containing informations about image and tile 260 * sizes. It is required in the main header immediately after SOC marker 261 * segment. 262 * */ 263 private void writeSIZ() throws IOException { 264 int tmp; 265 266 // SIZ marker 267 hbuf.writeShort(SIZ); 268 269 // Lsiz (Marker length) corresponding to 270 // Lsiz(2 bytes)+Rsiz(2)+Xsiz(4)+Ysiz(4)+XOsiz(4)+YOsiz(4)+ 271 // XTsiz(4)+YTsiz(4)+XTOsiz(4)+YTOsiz(4)+Csiz(2)+ 272 // (Ssiz(1)+XRsiz(1)+YRsiz(1))*nComp 273 // markSegLen = 38 + 3*nComp; 274 int markSegLen = 38 + 3*nComp; 275 hbuf.writeShort(markSegLen); 276 277 // Rsiz (codestream capabilities) 278 hbuf.writeShort(0); // JPEG 2000 - Part I 279 280 // Xsiz (original image width) 281 hbuf.writeInt(tiler.getImgWidth()+tiler.getImgULX()); 282 283 // Ysiz (original image height) 284 hbuf.writeInt(tiler.getImgHeight()+tiler.getImgULY()); 285 286 // XOsiz (horizontal offset from the origin of the reference 287 // grid to the left side of the image area) 288 hbuf.writeInt(tiler.getImgULX()); 289 290 // YOsiz (vertical offset from the origin of the reference 291 // grid to the top side of the image area) 292 hbuf.writeInt(tiler.getImgULY()); 293 294 // XTsiz (nominal tile width) 295 hbuf.writeInt(tiler.getNomTileWidth()); 296 297 // YTsiz (nominal tile height) 298 hbuf.writeInt(tiler.getNomTileHeight()); 299 300 Point torig = tiler.getTilingOrigin(null); 301 // XTOsiz (Horizontal offset from the origin of the reference 302 // grid to the left side of the first tile) 303 hbuf.writeInt(torig.x); 304 305 // YTOsiz (Vertical offset from the origin of the reference 306 // grid to the top side of the first tile) 307 hbuf.writeInt(torig.y); 308 309 // Csiz (number of components) 310 hbuf.writeShort(nComp); 311 312 // Bit-depth and downsampling factors. 313 for(int c=0; c<nComp; c++){ // Loop on each component 314 315 // Ssiz bit-depth before mixing 316 tmp = origSrc.getNomRangeBits(c)-1; 317 318 tmp |= ( (isOrigSig[c]?1:0)<<SSIZ_DEPTH_BITS ); 319 hbuf.write(tmp); 320 321 // XRsiz (component sub-sampling value x-wise) 322 hbuf.write(tiler.getCompSubsX(c)); 323 324 // YRsiz (component sub-sampling value y-wise) 325 hbuf.write(tiler.getCompSubsY(c)); 326 327 } // End loop on each component 328 329 } 330 331 /** 332 * Writes COD marker segment. COD is a functional marker segment 333 * containing the code style default (coding style, decomposition, 334 * layering) used for compressing all the components in an image. 335 * 336 * <p>The values can be overriden for an individual component by a COC 337 * marker in either the main or the tile header. 338 * 339 * @param mh Flag indicating whether this marker belongs to the main 340 * header 341 * 342 * @param tileIdx Tile index if the marker belongs to a tile-part header 343 * 344 * @see #writeCOC 345 * */ 346 protected void writeCOD(boolean mh, int tileIdx) 347 throws IOException { 348 AnWTFilter[][] filt; 349 boolean precinctPartitionUsed; 350 int tmp; 351 int mrl=0,a=0; 352 int ppx=0, ppy=0; 353 Progression[] prog; 354 355 if (mh) { 356 mrl = ((Integer)wp.getDecompositionLevel().getDefault()).intValue(); 357 // get default precinct size 358 ppx = wp.getPrecinctPartition().getPPX(-1,-1,mrl); 359 ppy = wp.getPrecinctPartition().getPPY(-1,-1,mrl); 360 prog = (Progression[])(wp.getProgressionType().getDefault()); 361 } 362 else { 363 mrl = ((Integer)wp.getDecompositionLevel().getTileDef(tileIdx)).intValue(); 364 // get precinct size for specified tile 365 ppx = wp.getPrecinctPartition().getPPX(tileIdx,-1,mrl); 366 ppy = wp.getPrecinctPartition().getPPY(tileIdx,-1,mrl); 367 prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx)); 368 } 369 370 if ( ppx != PRECINCT_PARTITION_DEF_SIZE || 371 ppy != PRECINCT_PARTITION_DEF_SIZE ) { 372 precinctPartitionUsed = true; 373 } 374 else { 375 precinctPartitionUsed = false; 376 } 377 378 if ( precinctPartitionUsed ) { 379 // If precinct partition is used we add one byte per resolution 380 // level i.e. mrl+1 (+1 for resolution 0). 381 a = mrl+1; 382 } 383 384 // Write COD marker 385 hbuf.writeShort(COD); 386 387 // Lcod (marker segment length (in bytes)) Basic : Lcod(2 388 // bytes)+Scod(1)+SGcod(4)+SPcod(5+a) where: 389 // a=0 if no precinct partition is used 390 // a=mrl+1 if precinct partition used 391 int markSegLen = 12+a; 392 hbuf.writeShort(markSegLen); 393 394 // Scod (coding style parameter) 395 tmp=0; 396 if ( precinctPartitionUsed ) 397 tmp=SCOX_PRECINCT_PARTITION; 398 399 // Are SOP markers used ? 400 if (mh) { 401 if( ((String)wp.getSOP().getDefault().toString()) 402 .equalsIgnoreCase("true") ) { 403 tmp |= SCOX_USE_SOP; 404 } 405 } 406 else { 407 if ( ((String)wp.getSOP().getTileDef(tileIdx).toString()) 408 .equalsIgnoreCase("true") ) { 409 tmp |= SCOX_USE_SOP; 410 } 411 } 412 413 // Are EPH markers used ? 414 if(mh){ 415 if ( ((String)wp.getEPH().getDefault().toString()) 416 .equalsIgnoreCase("true") ) { 417 tmp |= SCOX_USE_EPH; 418 } 419 } 420 else{ 421 if ( ((String)wp.getEPH().getTileDef(tileIdx).toString()) 422 .equalsIgnoreCase("true") ) { 423 tmp |= SCOX_USE_EPH; 424 } 425 } 426 if (dwt.getCbULX()!=0) tmp |= SCOX_HOR_CB_PART; 427 if (dwt.getCbULY()!=0) tmp |= SCOX_VER_CB_PART; 428 hbuf.write(tmp); 429 430 // SGcod 431 // Progression order 432 hbuf.write(prog[0].type); 433 434 // Number of layers 435 hbuf.writeShort(ralloc.getNumLayers()); 436 437 // Multiple component transform 438 // CSsiz (Color transform) 439 String str = null; 440 if(mh) 441 str = (String)wp.getComponentTransformation().getDefault(); 442 else 443 str = (String)wp.getComponentTransformation().getTileDef(tileIdx); 444 445 if(str.equals("none")) 446 hbuf.write(0); 447 else 448 hbuf.write(1); 449 450 // SPcod 451 // Number of decomposition levels 452 hbuf.write(mrl); 453 454 // Code-block width and height 455 if ( mh ) { 456 // main header, get default values 457 tmp = wp.getCodeBlockSize(). 458 getCBlkWidth(ModuleSpec.SPEC_DEF,-1,-1); 459 hbuf.write(MathUtil.log2(tmp)-2); 460 tmp = wp.getCodeBlockSize(). 461 getCBlkHeight(ModuleSpec.SPEC_DEF,-1,-1); 462 hbuf.write(MathUtil.log2(tmp)-2); 463 } 464 else { 465 // tile header, get tile default values 466 tmp = wp.getCodeBlockSize(). 467 getCBlkWidth(ModuleSpec.SPEC_TILE_DEF,tileIdx,-1); 468 hbuf.write(MathUtil.log2(tmp)-2); 469 tmp = wp.getCodeBlockSize(). 470 getCBlkHeight(ModuleSpec.SPEC_TILE_DEF,tileIdx,-1); 471 hbuf.write(MathUtil.log2(tmp)-2); 472 } 473 474 // Style of the code-block coding passes 475 tmp = 0; 476 if(mh){ // Main header 477 // Selective arithmetic coding bypass ? 478 if( ((String)wp.getBypass().getDefault()).equals("true")) { 479 tmp |= OPT_BYPASS; 480 } 481 // MQ reset after each coding pass ? 482 if( ((String)wp.getResetMQ().getDefault()).equals("true")) { 483 tmp |= OPT_RESET_MQ; 484 } 485 // MQ termination after each arithmetically coded coding pass ? 486 if( ((String)wp.getTerminateOnByte().getDefault()).equals("true") ) { 487 tmp |= OPT_TERM_PASS; 488 } 489 // Vertically stripe-causal context mode ? 490 if( ((String)wp.getCausalCXInfo().getDefault()).equals("true") ) { 491 tmp |= OPT_VERT_STR_CAUSAL; 492 } 493 // Predictable termination ? 494 if( ((String)wp.getMethodForMQTermination().getDefault()).equals("predict")){ 495 tmp |= OPT_PRED_TERM; 496 } 497 // Error resilience segmentation symbol insertion ? 498 if( ((String)wp.getCodeSegSymbol().getDefault()).equals("true")) { 499 tmp |= OPT_SEG_SYMBOLS; 500 } 501 } 502 else{ // Tile header 503 504 // Selective arithmetic coding bypass ? 505 if( ((String)wp.getBypass().getTileDef(tileIdx)).equals("true")) { 506 tmp |= OPT_BYPASS; 507 } 508 // MQ reset after each coding pass ? 509 if( ((String)wp.getResetMQ().getTileDef(tileIdx)).equals("true")) { 510 tmp |= OPT_RESET_MQ; 511 } 512 // MQ termination after each arithmetically coded coding pass ? 513 if( ((String)wp.getTerminateOnByte().getTileDef(tileIdx)).equals("true") ) { 514 tmp |= OPT_TERM_PASS; 515 } 516 // Vertically stripe-causal context mode ? 517 if( ((String)wp.getCausalCXInfo().getTileDef(tileIdx)).equals("true") ) { 518 tmp |= OPT_VERT_STR_CAUSAL; 519 } 520 // Predictable termination ? 521 if( ((String)wp.getMethodForMQTermination().getTileDef(tileIdx)).equals("predict")){ 522 tmp |= OPT_PRED_TERM; 523 } 524 // Error resilience segmentation symbol insertion ? 525 if( ((String)wp.getCodeSegSymbol().getTileDef(tileIdx)).equals("true")) { 526 tmp |= OPT_SEG_SYMBOLS; 527 } 528 } 529 hbuf.write(tmp); 530 531 // Wavelet transform 532 // Wavelet Filter 533 if(mh){ 534 filt=((AnWTFilter[][])wp.getFilters().getDefault()); 535 hbuf.write(filt[0][0].getFilterType()); 536 }else{ 537 filt=((AnWTFilter[][])wp.getFilters().getTileDef(tileIdx)); 538 hbuf.write(filt[0][0].getFilterType()); 539 } 540 541 // Precinct partition 542 if ( precinctPartitionUsed ) { 543 // Write the precinct size for each resolution level + 1 544 // (resolution 0) if precinct partition is used. 545 Vector v[] = null; 546 if ( mh ) { 547 v = (Vector[])wp.getPrecinctPartition().getDefault(); 548 } 549 else { 550 v = (Vector[])wp.getPrecinctPartition().getTileDef(tileIdx); 551 } 552 for (int r=mrl ; r>=0 ; r--) { 553 if ( r>=v[1].size() ) { 554 tmp = ((Integer)v[1].elementAt(v[1].size()-1)). 555 intValue(); 556 } 557 else { 558 tmp = ((Integer)v[1].elementAt(r)).intValue(); 559 } 560 int yExp = (MathUtil.log2(tmp)<< 4) & 0x00F0; 561 562 if ( r>=v[0].size() ) { 563 tmp = ((Integer)v[0].elementAt(v[0].size()-1)). 564 intValue(); 565 } 566 else { 567 tmp = ((Integer)v[0].elementAt(r)).intValue(); 568 } 569 int xExp = MathUtil.log2(tmp) & 0x000F; 570 hbuf.write(yExp|xExp); 571 } 572 } 573 } 574 575 /** 576 * Writes COC marker segment . It is a functional marker containing the 577 * coding style for one component (coding style, decomposition, layering). 578 * 579 * <P>Its values overrides any value previously set in COD in the main 580 * header or in the tile header. 581 * 582 * @param mh Flag indicating whether the main header is to be written 583 * 584 * @param tileIdx Tile index 585 * 586 * @param compIdx index of the component which need use of the COC marker 587 * segment. 588 * 589 * @see #writeCOD 590 * */ 591 protected void writeCOC(boolean mh, int tileIdx, int compIdx) 592 throws IOException { 593 AnWTFilter[][] filt; 594 boolean precinctPartitionUsed; 595 int tmp; 596 int mrl=0,a=0; 597 int ppx=0, ppy=0; 598 Progression[] prog; 599 600 if (mh) { 601 mrl = ((Integer)wp.getDecompositionLevel().getCompDef(compIdx)).intValue(); 602 // Get precinct size for specified component 603 ppx = wp.getPrecinctPartition().getPPX(-1, compIdx, mrl); 604 ppy = wp.getPrecinctPartition().getPPY(-1, compIdx, mrl); 605 prog = (Progression[])(wp.getProgressionType().getCompDef(compIdx)); 606 } 607 else { 608 mrl = ((Integer)wp.getDecompositionLevel().getTileCompVal(tileIdx,compIdx)). 609 intValue(); 610 // Get precinct size for specified component/tile 611 ppx = wp.getPrecinctPartition().getPPX(tileIdx, compIdx, mrl); 612 ppy = wp.getPrecinctPartition().getPPY(tileIdx, compIdx, mrl); 613 prog = (Progression[])(wp.getProgressionType().getTileCompVal(tileIdx,compIdx)); 614 } 615 616 if ( ppx != Markers.PRECINCT_PARTITION_DEF_SIZE || 617 ppy != Markers.PRECINCT_PARTITION_DEF_SIZE ) { 618 precinctPartitionUsed = true; 619 } 620 else { 621 precinctPartitionUsed = false; 622 } 623 if ( precinctPartitionUsed ) { 624 // If precinct partition is used we add one byte per resolution 625 // level i.e. mrl+1 (+1 for resolution 0). 626 a = mrl+1; 627 } 628 629 // COC marker 630 hbuf.writeShort(COC); 631 632 // Lcoc (marker segment length (in bytes)) 633 // Basic: Lcoc(2 bytes)+Scoc(1)+ Ccoc(1 or 2)+SPcod(5+a) 634 int markSegLen = 8 + ((nComp < 257) ? 1 : 2)+a; 635 636 // Rounded to the nearest even value greater or equals 637 hbuf.writeShort(markSegLen); 638 639 // Ccoc 640 if(nComp < 257) { 641 hbuf.write(compIdx); 642 } 643 else { 644 hbuf.writeShort(compIdx); 645 } 646 647 // Scod (coding style parameter) 648 tmp=0; 649 if ( precinctPartitionUsed ) { 650 tmp=SCOX_PRECINCT_PARTITION; 651 } 652 hbuf.write(tmp); 653 654 655 // SPcoc 656 657 // Number of decomposition levels 658 hbuf.write(mrl); 659 660 // Code-block width and height 661 if ( mh ) { 662 // main header, get component default values 663 tmp = wp.getCodeBlockSize(). 664 getCBlkWidth(ModuleSpec.SPEC_COMP_DEF, -1, compIdx); 665 hbuf.write(MathUtil.log2(tmp)-2); 666 tmp = wp.getCodeBlockSize(). 667 getCBlkHeight(ModuleSpec.SPEC_COMP_DEF, -1, compIdx); 668 hbuf.write(MathUtil.log2(tmp)-2); 669 } 670 else { 671 // tile header, get tile component values 672 tmp = wp.getCodeBlockSize(). 673 getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx); 674 hbuf.write(MathUtil.log2(tmp)-2); 675 tmp = wp.getCodeBlockSize(). 676 getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx); 677 hbuf.write(MathUtil.log2(tmp)-2); 678 } 679 680 // Entropy coding mode options 681 tmp = 0; 682 if(mh){ // Main header 683 // Lazy coding mode ? 684 if( ((String)wp.getBypass().getCompDef(compIdx)).equals("true")) { 685 tmp |= OPT_BYPASS; 686 } 687 // MQ reset after each coding pass ? 688 if( ((String)wp.getResetMQ().getCompDef(compIdx)). 689 equalsIgnoreCase("true")) { 690 tmp |= OPT_RESET_MQ; 691 } 692 // MQ termination after each arithmetically coded coding pass ? 693 if( ((String)wp.getTerminateOnByte().getCompDef(compIdx)).equals("true") ) { 694 tmp |= OPT_TERM_PASS; 695 } 696 // Vertically stripe-causal context mode ? 697 if( ((String)wp.getCausalCXInfo().getCompDef(compIdx)).equals("true") ) { 698 tmp |= OPT_VERT_STR_CAUSAL; 699 } 700 // Predictable termination ? 701 if( ((String)wp.getMethodForMQTermination().getCompDef(compIdx)).equals("predict")){ 702 tmp |= OPT_PRED_TERM; 703 } 704 // Error resilience segmentation symbol insertion ? 705 if( ((String)wp.getCodeSegSymbol().getCompDef(compIdx)).equals("true")) { 706 tmp |= OPT_SEG_SYMBOLS; 707 } 708 } 709 else{ // Tile Header 710 if( ((String)wp.getBypass().getTileCompVal(tileIdx,compIdx)). 711 equals("true")) { 712 tmp |= OPT_BYPASS; 713 } 714 // MQ reset after each coding pass ? 715 if( ((String)wp.getResetMQ().getTileCompVal(tileIdx,compIdx)). 716 equals("true")) { 717 tmp |= OPT_RESET_MQ; 718 } 719 // MQ termination after each arithmetically coded coding pass ? 720 if( ((String)wp.getTerminateOnByte().getTileCompVal(tileIdx,compIdx)). 721 equals("true") ) { 722 tmp |= OPT_TERM_PASS; 723 } 724 // Vertically stripe-causal context mode ? 725 if( ((String)wp.getCausalCXInfo().getTileCompVal(tileIdx,compIdx)). 726 equals("true") ) { 727 tmp |= OPT_VERT_STR_CAUSAL; 728 } 729 // Predictable termination ? 730 if( ((String)wp.getMethodForMQTermination().getTileCompVal(tileIdx,compIdx)). 731 equals("predict")){ 732 tmp |= OPT_PRED_TERM; 733 } 734 // Error resilience segmentation symbol insertion ? 735 if( ((String)wp.getCodeSegSymbol().getTileCompVal(tileIdx,compIdx)). 736 equals("true")) { 737 tmp |= OPT_SEG_SYMBOLS; 738 } 739 } 740 hbuf.write(tmp); 741 742 // Wavelet transform 743 // Wavelet Filter 744 if(mh){ 745 filt=((AnWTFilter[][])wp.getFilters().getCompDef(compIdx)); 746 hbuf.write(filt[0][0].getFilterType()); 747 }else{ 748 filt=((AnWTFilter[][])wp.getFilters().getTileCompVal(tileIdx,compIdx)); 749 hbuf.write(filt[0][0].getFilterType()); 750 } 751 752 // Precinct partition 753 if ( precinctPartitionUsed ) { 754 // Write the precinct size for each resolution level + 1 755 // (resolution 0) if precinct partition is used. 756 Vector v[] = null; 757 if ( mh ) { 758 v = (Vector[])wp.getPrecinctPartition().getCompDef(compIdx); 759 } 760 else { 761 v = (Vector[])wp.getPrecinctPartition().getTileCompVal(tileIdx, compIdx); 762 } 763 for (int r=mrl ; r>=0 ; r--) { 764 if ( r>=v[1].size() ) { 765 tmp = ((Integer)v[1].elementAt(v[1].size()-1)). 766 intValue(); 767 } 768 else { 769 tmp = ((Integer)v[1].elementAt(r)).intValue(); 770 } 771 int yExp = (MathUtil.log2(tmp)<< 4) & 0x00F0; 772 773 if ( r>=v[0].size() ) { 774 tmp = ((Integer)v[0].elementAt(v[0].size()-1)). 775 intValue(); 776 } 777 else { 778 tmp = ((Integer)v[0].elementAt(r)).intValue(); 779 } 780 int xExp = MathUtil.log2(tmp) & 0x000F; 781 hbuf.write(yExp|xExp); 782 } 783 } 784 785 } 786 787 /** 788 * Writes QCD marker segment in main header. QCD is a functional marker 789 * segment countaining the quantization default used for compressing all 790 * the components in an image. The values can be overriden for an 791 * individual component by a QCC marker in either the main or the tile 792 * header. 793 * */ 794 protected void writeMainQCD() throws IOException{ 795 float step; 796 797 String qType = (String)wp.getQuantizationType().getDefault(); 798 float baseStep = ((Float)wp.getQuantizationStep().getDefault()).floatValue(); 799 int gb = ((Integer)wp.getGuardBits().getDefault()).intValue(); 800 801 boolean isDerived = qType.equals("derived"); 802 boolean isReversible = qType.equals("reversible"); 803 int mrl = ((Integer)wp.getDecompositionLevel().getDefault()).intValue(); 804 805 int nt = dwt.getNumTiles(); 806 int nc = dwt.getNumComps(); 807 int tmpI; 808 int[] tcIdx = new int[2]; 809 String tmpStr; 810 boolean notFound = true; 811 for(int t=0; t<nt && notFound; t++) { 812 for(int c=0; c<nc && notFound; c++) { 813 tmpI = ((Integer)wp.getDecompositionLevel().getTileCompVal(t,c)).intValue(); 814 tmpStr = (String)wp.getQuantizationType().getTileCompVal(t,c); 815 if(tmpI==mrl && tmpStr.equals(qType)) { 816 tcIdx[0] = t; tcIdx[1] = c; 817 notFound = false; 818 } 819 } 820 } 821 if(notFound) { 822 throw new Error("Default representative for quantization type "+ 823 " and number of decomposition levels not found "+ 824 " in main QCD marker segment. "+ 825 "You have found a JJ2000 bug."); 826 } 827 SubbandAn sb,csb, 828 sbRoot = dwt.getAnSubbandTree(tcIdx[0],tcIdx[1]); 829 defimgn = dwt.getNomRangeBits(tcIdx[1]); 830 831 int nqcd; // Number of quantization step-size to transmit 832 833 // Get the quantization style 834 int qstyle = (isReversible) ? SQCX_NO_QUANTIZATION : 835 ((isDerived) ? SQCX_SCALAR_DERIVED : SQCX_SCALAR_EXPOUNDED); 836 837 // QCD marker 838 hbuf.writeShort(QCD); 839 840 841 // Compute the number of steps to send 842 switch (qstyle) { 843 case SQCX_SCALAR_DERIVED: 844 nqcd = 1; // Just the LL value 845 break; 846 case SQCX_NO_QUANTIZATION: 847 case SQCX_SCALAR_EXPOUNDED: 848 // One value per subband 849 nqcd=0; 850 851 sb=sbRoot; 852 853 // Get the subband at first resolution level 854 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 855 856 // Count total number of subbands 857 for (int j=0; j<=mrl; j++) { 858 csb = sb; 859 while (csb != null) { 860 nqcd++; 861 csb = (SubbandAn) csb.nextSubband(); 862 } 863 // Go up one resolution level 864 sb = (SubbandAn) sb.getNextResLevel(); 865 } 866 break; 867 default: 868 throw new Error("Internal JJ2000 error"); 869 } 870 871 // Lqcd (marker segment length (in bytes)) 872 // Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd) 873 int markSegLen = 3 + ((isReversible) ? nqcd : 2*nqcd); 874 875 // Rounded to the nearest even value greater or equals 876 hbuf.writeShort(markSegLen); 877 878 // Sqcd 879 hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT)); 880 881 // SPqcd 882 switch (qstyle) { 883 case SQCX_NO_QUANTIZATION: 884 sb = sbRoot; 885 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 886 887 // Output one exponent per subband 888 for (int j=0; j<=mrl; j++) { 889 csb = sb; 890 while(csb != null) { 891 int tmp = (defimgn + csb.anGainExp); 892 hbuf.write(tmp<<SQCX_EXP_SHIFT); 893 894 csb = (SubbandAn)csb.nextSubband(); 895 // Go up one resolution level 896 } 897 sb = (SubbandAn)sb.getNextResLevel(); 898 } 899 break; 900 case SQCX_SCALAR_DERIVED: 901 sb = sbRoot; 902 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 903 904 // Calculate subband step (normalized to unit 905 // dynamic range) 906 step = baseStep/(1<<sb.level); 907 908 // Write exponent-mantissa, 16 bits 909 hbuf.writeShort(StdQuantizer. 910 convertToExpMantissa(step)); 911 break; 912 case SQCX_SCALAR_EXPOUNDED: 913 sb = sbRoot; 914 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 915 916 // Output one step per subband 917 for (int j=0; j<=mrl; j++) { 918 csb = sb; 919 while(csb != null) { 920 // Calculate subband step (normalized to unit 921 // dynamic range) 922 step = baseStep/(csb.l2Norm*(1<<csb.anGainExp)); 923 924 // Write exponent-mantissa, 16 bits 925 hbuf.writeShort(StdQuantizer. 926 convertToExpMantissa(step)); 927 928 csb = (SubbandAn)csb.nextSubband(); 929 } 930 // Go up one resolution level 931 sb = (SubbandAn)sb.getNextResLevel(); 932 } 933 break; 934 default: 935 throw new Error("Internal JJ2000 error"); 936 } 937 } 938 939 /** 940 * Writes QCC marker segment in main header. It is a functional 941 * marker segment countaining the quantization used for 942 * compressing the specified component in an image. The values 943 * override for the specified component what was defined by a QCC 944 * marker in either the main or the tile header. 945 * 946 * @param compIdx Index of the component which needs QCC marker 947 * segment. 948 * */ 949 protected void writeMainQCC(int compIdx) 950 throws IOException{ 951 952 int mrl; 953 int qstyle; 954 int tIdx = 0; 955 float step; 956 957 SubbandAn sb,sb2; 958 SubbandAn sbRoot; 959 960 int imgnr = dwt.getNomRangeBits(compIdx); 961 String qType = (String)wp.getQuantizationType().getCompDef(compIdx); 962 float baseStep = ((Float)wp.getQuantizationStep().getCompDef(compIdx)).floatValue(); 963 int gb = ((Integer)wp.getGuardBits().getCompDef(compIdx)).intValue(); 964 965 boolean isReversible = qType.equals("reversible"); 966 boolean isDerived = qType.equals("derived"); 967 968 mrl = ((Integer)wp.getDecompositionLevel().getCompDef(compIdx)).intValue(); 969 970 int nt = dwt.getNumTiles(); 971 int nc = dwt.getNumComps(); 972 int tmpI; 973 String tmpStr; 974 boolean notFound = true; 975 for(int t=0; t<nt && notFound; t++) { 976 for(int c=0; c<nc && notFound; c++) { 977 tmpI = ((Integer)wp.getDecompositionLevel().getTileCompVal(t,c)).intValue(); 978 tmpStr = (String)wp.getQuantizationType().getTileCompVal(t,c); 979 if(tmpI==mrl && tmpStr.equals(qType)) { 980 tIdx = t; 981 notFound = false; 982 } 983 } 984 } 985 if(notFound) { 986 throw new Error("Default representative for quantization type "+ 987 " and number of decomposition levels not found "+ 988 " in main QCC (c="+compIdx+") marker segment. "+ 989 "You have found a JJ2000 bug."); 990 } 991 sbRoot = dwt.getAnSubbandTree(tIdx,compIdx); 992 993 int nqcc; // Number of quantization step-size to transmit 994 995 // Get the quantization style 996 if(isReversible) { 997 qstyle = SQCX_NO_QUANTIZATION; 998 } 999 else if (isDerived) { 1000 qstyle = SQCX_SCALAR_DERIVED; 1001 } 1002 else { 1003 qstyle = SQCX_SCALAR_EXPOUNDED; 1004 } 1005 1006 // QCC marker 1007 hbuf.writeShort(QCC); 1008 1009 // Compute the number of steps to send 1010 switch (qstyle) { 1011 case SQCX_SCALAR_DERIVED: 1012 nqcc = 1; // Just the LL value 1013 break; 1014 case SQCX_NO_QUANTIZATION: 1015 case SQCX_SCALAR_EXPOUNDED: 1016 // One value per subband 1017 nqcc = 0; 1018 1019 sb = sbRoot; 1020 mrl = sb.resLvl; 1021 1022 // Get the subband at first resolution level 1023 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 1024 1025 // Find root element for LL subband 1026 while (sb.resLvl != 0) { 1027 sb = sb.subb_LL; 1028 } 1029 1030 // Count total number of subbands 1031 for (int j=0; j<=mrl; j++) { 1032 sb2 = sb; 1033 while (sb2 != null) { 1034 nqcc++; 1035 sb2 = (SubbandAn) sb2.nextSubband(); 1036 } 1037 // Go up one resolution level 1038 sb = (SubbandAn) sb.getNextResLevel(); 1039 } 1040 break; 1041 default: 1042 throw new Error("Internal JJ2000 error"); 1043 } 1044 1045 // Lqcc (marker segment length (in bytes)) 1046 // Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc) 1047 int markSegLen = 3 + ((nComp < 257) ? 1 : 2) + 1048 ((isReversible) ? nqcc : 2*nqcc); 1049 hbuf.writeShort(markSegLen); 1050 1051 // Cqcc 1052 if (nComp < 257) { 1053 hbuf.write(compIdx); 1054 } 1055 else { 1056 hbuf.writeShort(compIdx); 1057 } 1058 1059 // Sqcc (quantization style) 1060 hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT)); 1061 1062 // SPqcc 1063 switch (qstyle) { 1064 case SQCX_NO_QUANTIZATION: 1065 // Get resolution level 0 subband 1066 sb = sbRoot; 1067 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1068 1069 // Output one exponent per subband 1070 for (int j=0; j<=mrl; j++) { 1071 sb2 = sb; 1072 while (sb2 != null) { 1073 int tmp = (imgnr+sb2.anGainExp); 1074 hbuf.write(tmp<<SQCX_EXP_SHIFT); 1075 1076 sb2 = (SubbandAn)sb2.nextSubband(); 1077 } 1078 // Go up one resolution level 1079 sb = (SubbandAn)sb.getNextResLevel(); 1080 } 1081 break; 1082 case SQCX_SCALAR_DERIVED: 1083 // Get resolution level 0 subband 1084 sb = sbRoot; 1085 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1086 1087 // Calculate subband step (normalized to unit 1088 // dynamic range) 1089 step = baseStep/(1<<sb.level); 1090 1091 // Write exponent-mantissa, 16 bits 1092 hbuf.writeShort(StdQuantizer. 1093 convertToExpMantissa(step)); 1094 break; 1095 case SQCX_SCALAR_EXPOUNDED: 1096 // Get resolution level 0 subband 1097 sb = sbRoot; 1098 mrl = sb.resLvl; 1099 1100 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1101 1102 for (int j=0; j<=mrl; j++) { 1103 sb2 = sb; 1104 while (sb2 != null) { 1105 // Calculate subband step (normalized to unit 1106 // dynamic range) 1107 step = baseStep/(sb2.l2Norm*(1<<sb2.anGainExp)); 1108 1109 // Write exponent-mantissa, 16 bits 1110 hbuf.writeShort(StdQuantizer. 1111 convertToExpMantissa(step)); 1112 sb2 = (SubbandAn)sb2.nextSubband(); 1113 } 1114 // Go up one resolution level 1115 sb = (SubbandAn) sb.getNextResLevel(); 1116 } 1117 break; 1118 default: 1119 throw new Error("Internal JJ2000 error"); 1120 } 1121 } 1122 1123 /** 1124 * Writes QCD marker segment in tile header. QCD is a functional 1125 * marker segment countaining the quantization default used for 1126 * compressing all the components in an image. The values can be 1127 * overriden for an individual component by a QCC marker in either 1128 * the main or the tile header. 1129 * 1130 * @param tIdx Tile index 1131 * */ 1132 protected void writeTileQCD(int tIdx) throws IOException{ 1133 int mrl; 1134 int qstyle; 1135 1136 float step; 1137 SubbandAn sb,csb,sbRoot; 1138 1139 String qType = (String)wp.getQuantizationType().getTileDef(tIdx); 1140 float baseStep = ((Float)wp.getQuantizationStep().getTileDef(tIdx)).floatValue(); 1141 mrl = ((Integer)wp.getDecompositionLevel().getTileDef(tIdx)).intValue(); 1142 1143 int nc = dwt.getNumComps(); 1144 int tmpI; 1145 String tmpStr; 1146 boolean notFound = true; 1147 int compIdx = 0; 1148 for(int c=0; c<nc && notFound; c++) { 1149 tmpI = ((Integer)wp.getDecompositionLevel().getTileCompVal(tIdx,c)).intValue(); 1150 tmpStr = (String)wp.getQuantizationStep().getTileCompVal(tIdx,c); 1151 if(tmpI==mrl && tmpStr.equals(qType)) { 1152 compIdx = c; 1153 notFound = false; 1154 } 1155 } 1156 if(notFound) { 1157 throw new Error("Default representative for quantization type "+ 1158 " and number of decomposition levels not found "+ 1159 " in tile QCD (t="+tIdx+") marker segment. "+ 1160 "You have found a JJ2000 bug."); 1161 } 1162 1163 sbRoot = dwt.getAnSubbandTree(tIdx,compIdx); 1164 deftilenr = dwt.getNomRangeBits(compIdx); 1165 int gb = ((Integer)wp.getGuardBits().getTileDef(tIdx)).intValue(); 1166 1167 boolean isDerived = qType.equals("derived"); 1168 boolean isReversible = qType.equals("reversible"); 1169 1170 int nqcd; // Number of quantization step-size to transmit 1171 1172 // Get the quantization style 1173 qstyle = (isReversible) ? SQCX_NO_QUANTIZATION : 1174 ((isDerived) ? SQCX_SCALAR_DERIVED : SQCX_SCALAR_EXPOUNDED); 1175 1176 // QCD marker 1177 hbuf.writeShort(QCD); 1178 1179 // Compute the number of steps to send 1180 switch (qstyle) { 1181 case SQCX_SCALAR_DERIVED: 1182 nqcd = 1; // Just the LL value 1183 break; 1184 case SQCX_NO_QUANTIZATION: 1185 case SQCX_SCALAR_EXPOUNDED: 1186 // One value per subband 1187 nqcd=0; 1188 1189 sb=sbRoot; 1190 1191 // Get the subband at first resolution level 1192 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1193 1194 // Count total number of subbands 1195 for (int j=0; j<=mrl; j++) { 1196 csb = sb; 1197 while (csb != null) { 1198 nqcd++; 1199 csb = (SubbandAn) csb.nextSubband(); 1200 } 1201 // Go up one resolution level 1202 sb = (SubbandAn) sb.getNextResLevel(); 1203 } 1204 break; 1205 default: 1206 throw new Error("Internal JJ2000 error"); 1207 } 1208 1209 // Lqcd (marker segment length (in bytes)) 1210 // Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd) 1211 int markSegLen = 3 + ((isReversible) ? nqcd : 2*nqcd); 1212 1213 // Rounded to the nearest even value greater or equals 1214 hbuf.writeShort(markSegLen); 1215 1216 // Sqcd 1217 hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT)); 1218 1219 // SPqcd 1220 switch (qstyle) { 1221 case SQCX_NO_QUANTIZATION: 1222 sb = sbRoot; 1223 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 1224 1225 // Output one exponent per subband 1226 for (int j=0; j<=mrl; j++) { 1227 csb = sb; 1228 while(csb != null) { 1229 int tmp = (deftilenr+csb.anGainExp); 1230 hbuf.write(tmp<<SQCX_EXP_SHIFT); 1231 1232 csb = (SubbandAn)csb.nextSubband(); 1233 // Go up one resolution level 1234 } 1235 sb = (SubbandAn)sb.getNextResLevel(); 1236 } 1237 break; 1238 case SQCX_SCALAR_DERIVED: 1239 sb = sbRoot; 1240 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 1241 1242 // Calculate subband step (normalized to unit 1243 // dynamic range) 1244 step = baseStep/(1<<sb.level); 1245 1246 // Write exponent-mantissa, 16 bits 1247 hbuf.writeShort(StdQuantizer. 1248 convertToExpMantissa(step)); 1249 break; 1250 case SQCX_SCALAR_EXPOUNDED: 1251 sb = sbRoot; 1252 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 1253 1254 // Output one step per subband 1255 for (int j=0; j<=mrl; j++) { 1256 csb = sb; 1257 while(csb != null) { 1258 // Calculate subband step (normalized to unit 1259 // dynamic range) 1260 step = baseStep/(csb.l2Norm*(1<<csb.anGainExp)); 1261 1262 // Write exponent-mantissa, 16 bits 1263 hbuf.writeShort(StdQuantizer. 1264 convertToExpMantissa(step)); 1265 1266 csb = (SubbandAn)csb.nextSubband(); 1267 } 1268 // Go up one resolution level 1269 sb = (SubbandAn)sb.getNextResLevel(); 1270 } 1271 break; 1272 default: 1273 throw new Error("Internal JJ2000 error"); 1274 } 1275 } 1276 1277 /** 1278 * Writes QCC marker segment in tile header. It is a functional 1279 * marker segment countaining the quantization used for 1280 * compressing the specified component in an image. The values 1281 * override for the specified component what was defined by a QCC 1282 * marker in either the main or the tile header. 1283 * 1284 * @param t Tile index 1285 * 1286 * @param compIdx Index of the component which needs QCC marker 1287 * segment. 1288 * */ 1289 protected void writeTileQCC(int t,int compIdx) 1290 throws IOException{ 1291 1292 int mrl; 1293 int qstyle; 1294 float step; 1295 1296 SubbandAn sb,sb2; 1297 int nqcc; // Number of quantization step-size to transmit 1298 1299 SubbandAn sbRoot = dwt.getAnSubbandTree(t,compIdx); 1300 int imgnr = dwt.getNomRangeBits(compIdx); 1301 String qType = (String)wp.getQuantizationType().getTileCompVal(t,compIdx); 1302 float baseStep = ((Float)wp.getQuantizationStep().getTileCompVal(t,compIdx)). 1303 floatValue(); 1304 int gb = ((Integer)wp.getGuardBits().getTileCompVal(t,compIdx)).intValue(); 1305 1306 boolean isReversible = qType.equals("reversible"); 1307 boolean isDerived = qType.equals("derived"); 1308 1309 mrl = ((Integer)wp.getDecompositionLevel().getTileCompVal(t,compIdx)).intValue(); 1310 1311 // Get the quantization style 1312 if(isReversible) { 1313 qstyle = SQCX_NO_QUANTIZATION; 1314 } 1315 else if (isDerived) { 1316 qstyle = SQCX_SCALAR_DERIVED; 1317 } 1318 else { 1319 qstyle = SQCX_SCALAR_EXPOUNDED; 1320 } 1321 1322 // QCC marker 1323 hbuf.writeShort(QCC); 1324 1325 // Compute the number of steps to send 1326 switch (qstyle) { 1327 case SQCX_SCALAR_DERIVED: 1328 nqcc = 1; // Just the LL value 1329 break; 1330 case SQCX_NO_QUANTIZATION: 1331 case SQCX_SCALAR_EXPOUNDED: 1332 // One value per subband 1333 nqcc = 0; 1334 1335 sb = sbRoot; 1336 mrl = sb.resLvl; 1337 1338 // Get the subband at first resolution level 1339 sb = (SubbandAn)sb.getSubbandByIdx(0,0); 1340 1341 // Find root element for LL subband 1342 while (sb.resLvl != 0) { 1343 sb = sb.subb_LL; 1344 } 1345 1346 // Count total number of subbands 1347 for (int j=0; j<=mrl; j++) { 1348 sb2 = sb; 1349 while (sb2 != null) { 1350 nqcc++; 1351 sb2 = (SubbandAn) sb2.nextSubband(); 1352 } 1353 // Go up one resolution level 1354 sb = (SubbandAn) sb.getNextResLevel(); 1355 } 1356 break; 1357 default: 1358 throw new Error("Internal JJ2000 error"); 1359 } 1360 1361 // Lqcc (marker segment length (in bytes)) 1362 // Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc) 1363 int markSegLen = 3 + ((nComp < 257) ? 1 : 2) + 1364 ((isReversible) ? nqcc : 2*nqcc); 1365 hbuf.writeShort(markSegLen); 1366 1367 // Cqcc 1368 if (nComp < 257) { 1369 hbuf.write(compIdx); 1370 } 1371 else { 1372 hbuf.writeShort(compIdx); 1373 } 1374 1375 // Sqcc (quantization style) 1376 hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT)); 1377 1378 // SPqcc 1379 switch (qstyle) { 1380 case SQCX_NO_QUANTIZATION: 1381 // Get resolution level 0 subband 1382 sb = sbRoot; 1383 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1384 1385 // Output one exponent per subband 1386 for (int j=0; j<=mrl; j++) { 1387 sb2 = sb; 1388 while (sb2 != null) { 1389 int tmp = (imgnr+sb2.anGainExp); 1390 hbuf.write(tmp<<SQCX_EXP_SHIFT); 1391 1392 sb2 = (SubbandAn)sb2.nextSubband(); 1393 } 1394 // Go up one resolution level 1395 sb = (SubbandAn)sb.getNextResLevel(); 1396 } 1397 break; 1398 case SQCX_SCALAR_DERIVED: 1399 // Get resolution level 0 subband 1400 sb = sbRoot; 1401 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1402 1403 // Calculate subband step (normalized to unit 1404 // dynamic range) 1405 step = baseStep/(1<<sb.level); 1406 1407 // Write exponent-mantissa, 16 bits 1408 hbuf.writeShort(StdQuantizer. 1409 convertToExpMantissa(step)); 1410 break; 1411 case SQCX_SCALAR_EXPOUNDED: 1412 // Get resolution level 0 subband 1413 sb = sbRoot; 1414 mrl = sb.resLvl; 1415 1416 sb = (SubbandAn) sb.getSubbandByIdx(0,0); 1417 1418 for (int j=0; j<=mrl; j++) { 1419 sb2 = sb; 1420 while (sb2 != null) { 1421 // Calculate subband step (normalized to unit 1422 // dynamic range) 1423 step = baseStep/(sb2.l2Norm*(1<<sb2.anGainExp)); 1424 1425 // Write exponent-mantissa, 16 bits 1426 hbuf.writeShort(StdQuantizer. 1427 convertToExpMantissa(step)); 1428 sb2 = (SubbandAn)sb2.nextSubband(); 1429 } 1430 // Go up one resolution level 1431 sb = (SubbandAn) sb.getNextResLevel(); 1432 } 1433 break; 1434 default: 1435 throw new Error("Internal JJ2000 error"); 1436 } 1437 } 1438 1439 /** 1440 * Writes POC marker segment. POC is a functional marker segment 1441 * containing the bounds and progression order for any progression order 1442 * other than default in the codestream. 1443 * 1444 * @param mh Flag indicating whether the main header is to be written 1445 * 1446 * @param tileIdx Tile index 1447 * */ 1448 protected void writePOC(boolean mh, int tileIdx) throws IOException { 1449 int markSegLen=0; // Segment marker length 1450 int lenCompField; // Holds the size of any component field as 1451 // this size depends on the number of 1452 //components 1453 Progression[] prog = null; // Holds the progression(s) 1454 int npoc; // Number of progression order changes 1455 1456 // Get the progression order changes, their number and checks 1457 // if it is ok 1458 if(mh){ 1459 prog = (Progression[])(wp.getProgressionType().getDefault()); 1460 } 1461 else { 1462 prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx)); 1463 } 1464 1465 // Calculate the length of a component field (depends on the number of 1466 // components) 1467 lenCompField = (nComp<257 ? 1 : 2); 1468 1469 // POC marker 1470 hbuf.writeShort(POC); 1471 1472 // Lpoc (marker segment length (in bytes)) 1473 // Basic: Lpoc(2 bytes) + npoc * [ RSpoc(1) + CSpoc(1 or 2) + LYEpoc(2) 1474 // + REpoc(1) + CEpoc(1 or 2) + Ppoc(1) ] 1475 npoc = prog.length; 1476 markSegLen = 2 + npoc * (1+lenCompField+2+1+lenCompField+1); 1477 hbuf.writeShort(markSegLen); 1478 1479 // Write each progression order change 1480 for (int i=0 ; i<npoc ; i++){ 1481 // RSpoc(i) 1482 hbuf.write(prog[i].rs); 1483 // CSpoc(i) 1484 if ( lenCompField==2 ) { 1485 hbuf.writeShort(prog[i].cs); 1486 } 1487 else { 1488 hbuf.write(prog[i].cs); 1489 } 1490 // LYEpoc(i) 1491 hbuf.writeShort(prog[i].lye); 1492 // REpoc(i) 1493 hbuf.write(prog[i].re); 1494 // CEpoc(i) 1495 if ( lenCompField==2 ) { 1496 hbuf.writeShort(prog[i].ce); 1497 } 1498 else { 1499 hbuf.write(prog[i].ce); 1500 } 1501 // Ppoc(i) 1502 hbuf.write(prog[i].type); 1503 } 1504 } 1505 1506 1507 /** 1508 * Write main header. JJ2000 main header corresponds to the following 1509 * sequence of marker 1510 * segments:<ol><li>SOC</li><li>SIZ</li><li>COD</li><li>COC (if 1511 * needed)</li><li>QCD</li><li>QCC (if needed)</li><li>POC (if 1512 * needed)</li></ol> 1513 * */ 1514 public void encodeMainHeader() throws IOException { 1515 int i; 1516 1517 1518 // +---------------------------------+ 1519 // | SOC marker segment | 1520 // +---------------------------------+ 1521 writeSOC(); 1522 1523 // +---------------------------------+ 1524 // | Image and tile SIZe (SIZ) | 1525 // +---------------------------------+ 1526 writeSIZ(); 1527 1528 // +-------------------------------+ 1529 // | COding style Default (COD) | 1530 // +-------------------------------+ 1531 boolean isEresUsed = ((String)wp.getTerminateOnByte().getDefault()). 1532 equals("predict"); 1533 writeCOD(true,0); 1534 1535 // +---------------------------------+ 1536 // | COding style Component (COC) | 1537 // +---------------------------------+ 1538 for (i= 0; i<nComp; i++) { 1539 boolean isEresUsedinComp = ((String)wp.getTerminateOnByte().getCompDef(i)). 1540 equals("predict"); 1541 if(wp.getFilters().isCompSpecified(i) || 1542 wp.getDecompositionLevel().isCompSpecified(i) || 1543 wp.getBypass().isCompSpecified(i) || 1544 wp.getResetMQ().isCompSpecified(i) || 1545 wp.getMethodForMQTermination().isCompSpecified(i) || 1546 wp.getCodeSegSymbol().isCompSpecified(i) || 1547 wp.getCausalCXInfo().isCompSpecified(i) || 1548 wp.getPrecinctPartition().isCompSpecified(i) || 1549 wp.getCodeBlockSize().isCompSpecified(i) || 1550 (isEresUsed != isEresUsedinComp ) ) 1551 // Some component non-default stuff => need COC 1552 writeCOC(true,0,i); 1553 } 1554 1555 // +-------------------------------+ 1556 // | Quantization Default (QCD) | 1557 // +-------------------------------+ 1558 writeMainQCD(); 1559 1560 // +-------------------------------+ 1561 // | Quantization Component (QCC) | 1562 // +-------------------------------+ 1563 // Write needed QCC markers 1564 for(i=0; i<nComp; i++){ 1565 if(dwt.getNomRangeBits(i)!= defimgn || 1566 wp.getQuantizationType().isCompSpecified(i) || 1567 wp.getQuantizationStep().isCompSpecified(i) || 1568 wp.getDecompositionLevel().isCompSpecified(i) || 1569 wp.getGuardBits().isCompSpecified(i)){ 1570 writeMainQCC(i); 1571 } 1572 } 1573 1574 // +--------------------------+ 1575 // | POC maker segment | 1576 // +--------------------------+ 1577 Progression[] prog = (Progression[])(wp.getProgressionType().getDefault()); 1578 if(prog.length>1) 1579 writePOC(true, 0); 1580 1581 // +--------------------------+ 1582 // | Comment (COM) | 1583 // +--------------------------+ 1584 writeCOM(); 1585 } 1586 1587 /** 1588 * Write a COM marker segment adding some comments to the codestream. 1589 * 1590 * <p> This marker is currently written in main header and indicates the 1591 * JJ2000 encoder's version that has created the codestream. 1592 * */ 1593 private void writeCOM() throws IOException { 1594 // JJ2000 COM marker segment 1595 if(enJJ2KMarkSeg) { 1596 String str = "Created by: JJ2000 version "+JJ2KInfo.version; 1597 int markSegLen; // the marker segment length 1598 1599 // COM marker 1600 hbuf.writeShort(COM); 1601 1602 // Calculate length: Lcom(2) + Rcom (2) + string's length; 1603 markSegLen = 2 + 2 + str.length(); 1604 hbuf.writeShort(markSegLen); 1605 1606 // Rcom 1607 hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin) values) 1608 1609 byte[] chars = str.getBytes(); 1610 for(int i=0; i<chars.length; i++) { 1611 hbuf.writeByte(chars[i]); 1612 } 1613 } 1614 // other COM marker segments 1615 if(otherCOMMarkSeg!=null) { 1616 StringTokenizer stk = new StringTokenizer(otherCOMMarkSeg,"#"); 1617 while(stk.hasMoreTokens()) { 1618 String str = stk.nextToken(); 1619 int markSegLen; // the marker segment length 1620 1621 // COM marker 1622 hbuf.writeShort(COM); 1623 1624 // Calculate length: Lcom(2) + Rcom (2) + string's length; 1625 markSegLen = 2 + 2 + str.length(); 1626 hbuf.writeShort(markSegLen); 1627 1628 // Rcom 1629 hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin) 1630 // values) 1631 1632 byte[] chars = str.getBytes(); 1633 for(int i=0; i<chars.length; i++) { 1634 hbuf.writeByte(chars[i]); 1635 } 1636 } 1637 } 1638 } 1639 1640 /** 1641 * Writes the RGN marker segment in the tile header. It describes the 1642 * scaling value in each tile component 1643 * 1644 * <P>May be used in tile or main header. If used in main header, it 1645 * refers to a ROI of the whole image, regardless of tiling. When used in 1646 * tile header, only the particular tile is affected. 1647 * 1648 * @param tIdx The tile index 1649 * 1650 * @exception IOException If an I/O error occurs while reading from the 1651 * encoder header stream 1652 * */ 1653 private void writeRGN(int tIdx) throws IOException { 1654 int i; 1655 int markSegLen; // the marker length 1656 1657 // Write one RGN marker per component 1658 for(i=0;i<nComp;i++){ 1659 // RGN marker 1660 hbuf.writeShort(RGN); 1661 1662 // Calculate length (Lrgn) 1663 // Basic: Lrgn (2) + Srgn (1) + SPrgn + one byte 1664 // or two for component number 1665 markSegLen = 4+((nComp<257)? 1:2); 1666 hbuf.writeShort(markSegLen); 1667 1668 // Write component (Crgn) 1669 if(nComp<257) 1670 hbuf.writeByte(i); 1671 else 1672 hbuf.writeShort(i); 1673 1674 // Write type of ROI (Srgn) 1675 hbuf.writeByte(SRGN_IMPLICIT); 1676 1677 // Write ROI info (SPrgn) 1678 hbuf.writeByte(((Integer)(wp.getROIs(). 1679 getTileCompVal(tIdx,i))).intValue()); 1680 } 1681 } 1682 /** 1683 * Writes tile-part header. JJ2000 tile-part header corresponds to the 1684 * following sequence of marker segments:<ol> <li>SOT</li> <li>COD (if 1685 * needed)</li> <li>COC (if needed)</li> <li>QCD (if needed)</li> <li>QCC 1686 * (if needed)</li> <li>RGN (if needed)</li> <li>POC (if needed)</li> 1687 * <li>SOD</li> </ol> 1688 * 1689 * @param length The length of the current tile-part. 1690 * 1691 * @param tileIdx Index of the tile to write 1692 * */ 1693 public void encodeTilePartHeader(int tileLength,int tileIdx) 1694 throws IOException { 1695 1696 int tmp; 1697 Point numTiles = ralloc.getNumTiles(null); 1698 ralloc.setTile(tileIdx%numTiles.x,tileIdx/numTiles.x); 1699 1700 // +--------------------------+ 1701 // | SOT maker segment | 1702 // +--------------------------+ 1703 // SOT marker 1704 hbuf.writeByte(SOT>>8); 1705 hbuf.writeByte(SOT); 1706 1707 // Lsot (10 bytes) 1708 hbuf.writeByte(0); 1709 hbuf.writeByte(10); 1710 1711 // Isot 1712 if(tileIdx>65534){ 1713 throw new IllegalArgumentException("Trying to write a tile-part "+ 1714 "header whose tile index is too"+ 1715 " high"); 1716 } 1717 hbuf.writeByte(tileIdx>>8); 1718 hbuf.writeByte(tileIdx); 1719 1720 // Psot 1721 tmp = tileLength; 1722 hbuf.writeByte(tmp>>24); 1723 hbuf.writeByte(tmp>>16); 1724 hbuf.writeByte(tmp>>8); 1725 hbuf.writeByte(tmp); 1726 1727 // TPsot 1728 hbuf.writeByte(0); // Only one tile-part currently supported ! 1729 1730 // TNsot 1731 hbuf.writeByte(1); // Only one tile-part currently supported ! 1732 1733 // +--------------------------+ 1734 // | COD maker segment | 1735 // +--------------------------+ 1736 boolean isEresUsed = ((String)wp.getMethodForMQTermination().getDefault()). 1737 equals("predict"); 1738 boolean isEresUsedInTile = ((String)wp.getMethodForMQTermination().getTileDef(tileIdx)). 1739 equals("predict"); 1740 boolean tileCODwritten = false; 1741 if(wp.getFilters().isTileSpecified(tileIdx) || 1742 wp.getComponentTransformation().isTileSpecified(tileIdx) || 1743 wp.getDecompositionLevel().isTileSpecified(tileIdx) || 1744 wp.getBypass().isTileSpecified(tileIdx) || 1745 wp.getResetMQ().isTileSpecified(tileIdx) || 1746 wp.getTerminateOnByte().isTileSpecified(tileIdx) || 1747 wp.getCausalCXInfo().isTileSpecified(tileIdx) || 1748 wp.getPrecinctPartition().isTileSpecified(tileIdx) || 1749 wp.getSOP().isTileSpecified(tileIdx) || 1750 wp.getCodeSegSymbol().isTileSpecified(tileIdx) || 1751 wp.getProgressionType().isTileSpecified(tileIdx) || 1752 wp.getEPH().isTileSpecified(tileIdx) || 1753 wp.getCodeBlockSize().isTileSpecified(tileIdx) || 1754 ( isEresUsed != isEresUsedInTile ) ) { 1755 writeCOD(false,tileIdx); 1756 tileCODwritten = true; 1757 } 1758 1759 // +--------------------------+ 1760 // | COC maker segment | 1761 // +--------------------------+ 1762 for(int c=0; c<nComp; c++){ 1763 boolean isEresUsedInTileComp = ((String)wp.getMethodForMQTermination(). 1764 getTileCompVal(tileIdx,c)). 1765 equals("predict"); 1766 1767 if(wp.getFilters().isTileCompSpecified(tileIdx,c) || 1768 wp.getDecompositionLevel().isTileCompSpecified(tileIdx,c) || 1769 wp.getBypass().isTileCompSpecified(tileIdx,c) || 1770 wp.getResetMQ().isTileCompSpecified(tileIdx,c) || 1771 wp.getTerminateOnByte().isTileCompSpecified(tileIdx,c) || 1772 wp.getCausalCXInfo().isTileCompSpecified(tileIdx,c) || 1773 wp.getPrecinctPartition().isTileCompSpecified(tileIdx,c) || 1774 wp.getCodeSegSymbol().isTileCompSpecified(tileIdx,c) || 1775 wp.getCodeBlockSize().isTileCompSpecified(tileIdx,c) || 1776 ( isEresUsedInTileComp != isEresUsed ) ) { 1777 writeCOC(false,tileIdx,c); 1778 } 1779 else if(tileCODwritten){ 1780 if(wp.getFilters().isCompSpecified(c) || 1781 wp.getDecompositionLevel().isCompSpecified(c) || 1782 wp.getBypass().isCompSpecified(c) || 1783 wp.getResetMQ().isCompSpecified(c) || 1784 wp.getTerminateOnByte().isCompSpecified(c) || 1785 wp.getCodeSegSymbol().isCompSpecified(c) || 1786 wp.getCausalCXInfo().isCompSpecified(c) || 1787 wp.getPrecinctPartition().isCompSpecified(c) || 1788 wp.getCodeBlockSize().isCompSpecified(c) || 1789 (wp.getMethodForMQTermination().isCompSpecified(c)&& 1790 ((String)wp.getMethodForMQTermination().getCompDef(c)).equals("predict"))){ 1791 writeCOC(false,tileIdx,c); 1792 } 1793 } 1794 } 1795 1796 // +--------------------------+ 1797 // | QCD maker segment | 1798 // +--------------------------+ 1799 boolean tileQCDwritten = false; 1800 if(wp.getQuantizationType().isTileSpecified(tileIdx) || 1801 wp.getQuantizationStep().isTileSpecified(tileIdx) || 1802 wp.getDecompositionLevel().isTileSpecified(tileIdx) || 1803 wp.getGuardBits().isTileSpecified(tileIdx)){ 1804 writeTileQCD(tileIdx); 1805 tileQCDwritten = true; 1806 } else { 1807 deftilenr = defimgn; 1808 } 1809 1810 // +--------------------------+ 1811 // | QCC maker segment | 1812 // +--------------------------+ 1813 for(int c=0; c<nComp; c++){ 1814 if(dwt.getNomRangeBits(c)!= deftilenr || 1815 wp.getQuantizationType().isTileCompSpecified(tileIdx,c) || 1816 wp.getQuantizationStep().isTileCompSpecified(tileIdx,c) || 1817 wp.getDecompositionLevel().isTileCompSpecified(tileIdx,c) || 1818 wp.getGuardBits().isTileCompSpecified(tileIdx,c)){ 1819 writeTileQCC(tileIdx,c); 1820 } 1821 else if(tileQCDwritten){ 1822 if(wp.getQuantizationType().isCompSpecified(c) || 1823 wp.getQuantizationStep().isCompSpecified(c) || 1824 wp.getDecompositionLevel().isCompSpecified(c) || 1825 wp.getGuardBits().isCompSpecified(c)){ 1826 writeTileQCC(tileIdx,c); 1827 } 1828 } 1829 } 1830 1831 // +--------------------------+ 1832 // | RGN maker segment | 1833 // +--------------------------+ 1834 if(roiSc.useRoi() &&(!roiSc.getBlockAligned())) 1835 writeRGN(tileIdx); 1836 1837 // +--------------------------+ 1838 // | POC maker segment | 1839 // +--------------------------+ 1840 Progression[] prog; 1841 if( wp.getProgressionType().isTileSpecified(tileIdx) ){ 1842 prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx)); 1843 if(prog.length>1) 1844 writePOC(false,tileIdx); 1845 } 1846 1847 // +--------------------------+ 1848 // | SOD maker | 1849 // +--------------------------+ 1850 hbuf.writeByte(SOD>>8); 1851 hbuf.writeByte(SOD); 1852 } 1853} 1854