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