0001: /*
0002: * $RCSfile: HeaderEncoder.java,v $
0003: * $Revision: 1.1 $
0004: * $Date: 2005/02/11 05:02:02 $
0005: * $State: Exp $
0006: *
0007: * Class: HeaderEncoder
0008: *
0009: * Description: Write codestream headers.
0010: *
0011: *
0012: *
0013: * COPYRIGHT:
0014: *
0015: * This software module was originally developed by Raphaël Grosbois and
0016: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
0017: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
0018: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
0019: * Centre France S.A) in the course of development of the JPEG2000
0020: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
0021: * software module is an implementation of a part of the JPEG 2000
0022: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
0023: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
0024: * Partners) agree not to assert against ISO/IEC and users of the JPEG
0025: * 2000 Standard (Users) any of their rights under the copyright, not
0026: * including other intellectual property rights, for this software module
0027: * with respect to the usage by ISO/IEC and Users of this software module
0028: * or modifications thereof for use in hardware or software products
0029: * claiming conformance to the JPEG 2000 Standard. Those intending to use
0030: * this software module in hardware or software products are advised that
0031: * their use may infringe existing patents. The original developers of
0032: * this software module, JJ2000 Partners and ISO/IEC assume no liability
0033: * for use of this software module or modifications thereof. No license
0034: * or right to this software module is granted for non JPEG 2000 Standard
0035: * conforming products. JJ2000 Partners have full right to use this
0036: * software module for his/her own purpose, assign or donate this
0037: * software module to any third party and to inhibit third parties from
0038: * using this software module for non JPEG 2000 Standard conforming
0039: * products. This copyright notice must be included in all copies or
0040: * derivative works of this software module.
0041: *
0042: * Copyright (c) 1999/2000 JJ2000 Partners.
0043: * */
0044: package jj2000.j2k.codestream.writer;
0045:
0046: import java.awt.Point;
0047:
0048: import jj2000.j2k.quantization.quantizer.*;
0049: import jj2000.j2k.wavelet.analysis.*;
0050: import jj2000.j2k.entropy.encoder.*;
0051: import jj2000.j2k.quantization.*;
0052: import jj2000.j2k.image.input.*;
0053: import jj2000.j2k.roi.encoder.*;
0054: import jj2000.j2k.codestream.*;
0055: import jj2000.j2k.wavelet.*;
0056: import jj2000.j2k.entropy.*;
0057: import jj2000.j2k.image.*;
0058: import jj2000.j2k.util.*;
0059: import jj2000.j2k.io.*;
0060: import jj2000.j2k.*;
0061:
0062: import java.util.*;
0063: import java.io.*;
0064:
0065: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
0066:
0067: /**
0068: * This class writes almost of the markers and marker segments in main header
0069: * and in tile-part headers. It is created by the run() method of the Encoder
0070: * instance.
0071: *
0072: * <p>A marker segment includes a marker and eventually marker segment
0073: * parameters. It is designed by the three letter code of the marker
0074: * associated with the marker segment. JPEG 2000 part I defines 6 types of
0075: * markers: <ul> <li> Delimiting : SOC,SOT,SOD,EOC (written in
0076: * FileCodestreamWriter).</li> <li> Fixed information: SIZ.</li> <li>
0077: * Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream: SOP,EPH.</li>
0078: * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li> <li> Informational:
0079: * CRG,COM.</li></ul>
0080: *
0081: * <p>Main Header is written when Encoder instance calls encodeMainHeader
0082: * whereas tile-part headers are written when the EBCOTRateAllocator instance
0083: * calls encodeTilePartHeader.
0084: *
0085: * @see Encoder
0086: * @see Markers
0087: * @see EBCOTRateAllocator
0088: * */
0089: public class HeaderEncoder implements Markers, StdEntropyCoderOptions {
0090:
0091: /** Nominal range bit of the component defining default values in QCD for
0092: * main header */
0093: private int defimgn;
0094:
0095: /** Nominal range bit of the component defining default values in QCD for
0096: * tile headers */
0097: private int deftilenr;
0098:
0099: /** The number of components in the image */
0100: protected int nComp;
0101:
0102: /** Whether or not to write the JJ2000 COM marker segment */
0103: private boolean enJJ2KMarkSeg = true;
0104:
0105: /** Other COM marker segments specified in the command line */
0106: private String otherCOMMarkSeg = null;
0107:
0108: /** The ByteArrayOutputStream to store header data. This handler
0109: * is kept in order to use methods not accessible from a general
0110: * DataOutputStream. For the other methods, it's better to use
0111: * variable hbuf.
0112: *
0113: * @see #hbuf */
0114: protected ByteArrayOutputStream baos;
0115:
0116: /** The DataOutputStream to store header data. This kind of object
0117: * is useful to write short, int, .... It's constructor takes
0118: * baos as parameter.
0119: *
0120: * @see #baos
0121: **/
0122: protected DataOutputStream hbuf;
0123:
0124: /** The image data reader. Source of original data info */
0125: protected ImgData origSrc;
0126:
0127: /** An array specifying, for each component,if the data was signed
0128: or not */
0129: protected boolean isOrigSig[];
0130:
0131: /** Reference to the rate allocator */
0132: protected PostCompRateAllocator ralloc;
0133:
0134: /** Reference to the DWT module */
0135: protected ForwardWT dwt;
0136:
0137: /** Reference to the tiler module */
0138: protected Tiler tiler;
0139:
0140: /** Reference to the ROI module */
0141: protected ROIScaler roiSc;
0142:
0143: /** The encoder specifications */
0144: protected J2KImageWriteParamJava wp;
0145:
0146: /**
0147: * Initializes the header writer with the references to the coding chain.
0148: *
0149: * @param origsrc The original image data (before any component mixing,
0150: * tiling, etc.)
0151: *
0152: * @param isorigsig An array specifying for each component if it was
0153: * originally signed or not.
0154: *
0155: * @param dwt The discrete wavelet transform module.
0156: *
0157: * @param tiler The tiler module.
0158: *
0159: * @param encSpec The encoder specifications
0160: *
0161: * @param roiSc The ROI scaler module.
0162: *
0163: * @param ralloc The post compression rate allocator.
0164: * */
0165: public HeaderEncoder(ImgData origsrc, boolean isorigsig[],
0166: ForwardWT dwt, Tiler tiler, J2KImageWriteParamJava wp,
0167: ROIScaler roiSc, PostCompRateAllocator ralloc) {
0168: if (origsrc.getNumComps() != isorigsig.length) {
0169: throw new IllegalArgumentException();
0170: }
0171: this .origSrc = origsrc;
0172: this .isOrigSig = isorigsig;
0173: this .dwt = dwt;
0174: this .tiler = tiler;
0175: this .wp = wp;
0176: this .roiSc = roiSc;
0177: this .ralloc = ralloc;
0178:
0179: baos = new ByteArrayOutputStream();
0180: hbuf = new DataOutputStream(baos);
0181: nComp = origsrc.getNumComps();
0182: // enJJ2KMarkSeg = wp.getHjj2000_COM();
0183: // otherCOMMarkSeg = wp.getHCOM();
0184: }
0185:
0186: /**
0187: * Resets the contents of this HeaderEncoder to its initial state. It
0188: * erases all the data in the header buffer and reactualizes the
0189: * headerLength field of the bit stream writer.
0190: * */
0191: public void reset() {
0192: baos.reset();
0193: hbuf = new DataOutputStream(baos);
0194: }
0195:
0196: /**
0197: * Returns the byte-buffer used to store the codestream header.
0198: *
0199: * @return A byte array countaining codestream header
0200: * */
0201: protected byte[] getBuffer() {
0202: return baos.toByteArray();
0203: }
0204:
0205: /**
0206: * Returns the length of the header.
0207: *
0208: * @return The length of the header in bytes
0209: * */
0210: public int getLength() {
0211: return hbuf.size();
0212: }
0213:
0214: /**
0215: * Writes the header to the specified BinaryDataOutput.
0216: *
0217: * @param out Where to write the header.
0218: * */
0219: public void writeTo(BinaryDataOutput out) throws IOException {
0220: int i, len;
0221: byte buf[];
0222:
0223: buf = getBuffer();
0224: len = getLength();
0225:
0226: for (i = 0; i < len; i++) {
0227: out.writeByte(buf[i]);
0228: }
0229: }
0230:
0231: /**
0232: * Returns the number of bytes used in the codestream header's
0233: * buffer.
0234: *
0235: * @return Header length in buffer (without any header
0236: * overhead)
0237: * */
0238: protected int getBufferLength() {
0239: return baos.size();
0240: }
0241:
0242: /**
0243: * Writes the header to the specified OutputStream.
0244: *
0245: * @param out Where to write the header.
0246: * */
0247: public void writeTo(OutputStream out) throws IOException {
0248: out.write(getBuffer(), 0, getBufferLength());
0249: }
0250:
0251: /**
0252: * Start Of Codestream marker (SOC) signalling the beginning of a
0253: * codestream.
0254: * */
0255: private void writeSOC() throws IOException {
0256: hbuf.writeShort(SOC);
0257: }
0258:
0259: /**
0260: * Writes SIZ marker segment of the codestream header. It is a fixed
0261: * information marker segment containing informations about image and tile
0262: * sizes. It is required in the main header immediately after SOC marker
0263: * segment.
0264: * */
0265: private void writeSIZ() throws IOException {
0266: int tmp;
0267:
0268: // SIZ marker
0269: hbuf.writeShort(SIZ);
0270:
0271: // Lsiz (Marker length) corresponding to
0272: // Lsiz(2 bytes)+Rsiz(2)+Xsiz(4)+Ysiz(4)+XOsiz(4)+YOsiz(4)+
0273: // XTsiz(4)+YTsiz(4)+XTOsiz(4)+YTOsiz(4)+Csiz(2)+
0274: // (Ssiz(1)+XRsiz(1)+YRsiz(1))*nComp
0275: // markSegLen = 38 + 3*nComp;
0276: int markSegLen = 38 + 3 * nComp;
0277: hbuf.writeShort(markSegLen);
0278:
0279: // Rsiz (codestream capabilities)
0280: hbuf.writeShort(0); // JPEG 2000 - Part I
0281:
0282: // Xsiz (original image width)
0283: hbuf.writeInt(tiler.getImgWidth() + tiler.getImgULX());
0284:
0285: // Ysiz (original image height)
0286: hbuf.writeInt(tiler.getImgHeight() + tiler.getImgULY());
0287:
0288: // XOsiz (horizontal offset from the origin of the reference
0289: // grid to the left side of the image area)
0290: hbuf.writeInt(tiler.getImgULX());
0291:
0292: // YOsiz (vertical offset from the origin of the reference
0293: // grid to the top side of the image area)
0294: hbuf.writeInt(tiler.getImgULY());
0295:
0296: // XTsiz (nominal tile width)
0297: hbuf.writeInt(tiler.getNomTileWidth());
0298:
0299: // YTsiz (nominal tile height)
0300: hbuf.writeInt(tiler.getNomTileHeight());
0301:
0302: Point torig = tiler.getTilingOrigin(null);
0303: // XTOsiz (Horizontal offset from the origin of the reference
0304: // grid to the left side of the first tile)
0305: hbuf.writeInt(torig.x);
0306:
0307: // YTOsiz (Vertical offset from the origin of the reference
0308: // grid to the top side of the first tile)
0309: hbuf.writeInt(torig.y);
0310:
0311: // Csiz (number of components)
0312: hbuf.writeShort(nComp);
0313:
0314: // Bit-depth and downsampling factors.
0315: for (int c = 0; c < nComp; c++) { // Loop on each component
0316:
0317: // Ssiz bit-depth before mixing
0318: tmp = origSrc.getNomRangeBits(c) - 1;
0319:
0320: tmp |= ((isOrigSig[c] ? 1 : 0) << SSIZ_DEPTH_BITS);
0321: hbuf.write(tmp);
0322:
0323: // XRsiz (component sub-sampling value x-wise)
0324: hbuf.write(tiler.getCompSubsX(c));
0325:
0326: // YRsiz (component sub-sampling value y-wise)
0327: hbuf.write(tiler.getCompSubsY(c));
0328:
0329: } // End loop on each component
0330:
0331: }
0332:
0333: /**
0334: * Writes COD marker segment. COD is a functional marker segment
0335: * containing the code style default (coding style, decomposition,
0336: * layering) used for compressing all the components in an image.
0337: *
0338: * <p>The values can be overriden for an individual component by a COC
0339: * marker in either the main or the tile header.
0340: *
0341: * @param mh Flag indicating whether this marker belongs to the main
0342: * header
0343: *
0344: * @param tileIdx Tile index if the marker belongs to a tile-part header
0345: *
0346: * @see #writeCOC
0347: * */
0348: protected void writeCOD(boolean mh, int tileIdx) throws IOException {
0349: AnWTFilter[][] filt;
0350: boolean precinctPartitionUsed;
0351: int tmp;
0352: int mrl = 0, a = 0;
0353: int ppx = 0, ppy = 0;
0354: Progression[] prog;
0355:
0356: if (mh) {
0357: mrl = ((Integer) wp.getDecompositionLevel().getDefault())
0358: .intValue();
0359: // get default precinct size
0360: ppx = wp.getPrecinctPartition().getPPX(-1, -1, mrl);
0361: ppy = wp.getPrecinctPartition().getPPY(-1, -1, mrl);
0362: prog = (Progression[]) (wp.getProgressionType()
0363: .getDefault());
0364: } else {
0365: mrl = ((Integer) wp.getDecompositionLevel().getTileDef(
0366: tileIdx)).intValue();
0367: // get precinct size for specified tile
0368: ppx = wp.getPrecinctPartition().getPPX(tileIdx, -1, mrl);
0369: ppy = wp.getPrecinctPartition().getPPY(tileIdx, -1, mrl);
0370: prog = (Progression[]) (wp.getProgressionType()
0371: .getTileDef(tileIdx));
0372: }
0373:
0374: if (ppx != PRECINCT_PARTITION_DEF_SIZE
0375: || ppy != PRECINCT_PARTITION_DEF_SIZE) {
0376: precinctPartitionUsed = true;
0377: } else {
0378: precinctPartitionUsed = false;
0379: }
0380:
0381: if (precinctPartitionUsed) {
0382: // If precinct partition is used we add one byte per resolution
0383: // level i.e. mrl+1 (+1 for resolution 0).
0384: a = mrl + 1;
0385: }
0386:
0387: // Write COD marker
0388: hbuf.writeShort(COD);
0389:
0390: // Lcod (marker segment length (in bytes)) Basic : Lcod(2
0391: // bytes)+Scod(1)+SGcod(4)+SPcod(5+a) where:
0392: // a=0 if no precinct partition is used
0393: // a=mrl+1 if precinct partition used
0394: int markSegLen = 12 + a;
0395: hbuf.writeShort(markSegLen);
0396:
0397: // Scod (coding style parameter)
0398: tmp = 0;
0399: if (precinctPartitionUsed)
0400: tmp = SCOX_PRECINCT_PARTITION;
0401:
0402: // Are SOP markers used ?
0403: if (mh) {
0404: if (((String) wp.getSOP().getDefault().toString())
0405: .equalsIgnoreCase("true")) {
0406: tmp |= SCOX_USE_SOP;
0407: }
0408: } else {
0409: if (((String) wp.getSOP().getTileDef(tileIdx).toString())
0410: .equalsIgnoreCase("true")) {
0411: tmp |= SCOX_USE_SOP;
0412: }
0413: }
0414:
0415: // Are EPH markers used ?
0416: if (mh) {
0417: if (((String) wp.getEPH().getDefault().toString())
0418: .equalsIgnoreCase("true")) {
0419: tmp |= SCOX_USE_EPH;
0420: }
0421: } else {
0422: if (((String) wp.getEPH().getTileDef(tileIdx).toString())
0423: .equalsIgnoreCase("true")) {
0424: tmp |= SCOX_USE_EPH;
0425: }
0426: }
0427: if (dwt.getCbULX() != 0)
0428: tmp |= SCOX_HOR_CB_PART;
0429: if (dwt.getCbULY() != 0)
0430: tmp |= SCOX_VER_CB_PART;
0431: hbuf.write(tmp);
0432:
0433: // SGcod
0434: // Progression order
0435: hbuf.write(prog[0].type);
0436:
0437: // Number of layers
0438: hbuf.writeShort(ralloc.getNumLayers());
0439:
0440: // Multiple component transform
0441: // CSsiz (Color transform)
0442: String str = null;
0443: if (mh)
0444: str = (String) wp.getComponentTransformation().getDefault();
0445: else
0446: str = (String) wp.getComponentTransformation().getTileDef(
0447: tileIdx);
0448:
0449: if (str.equals("none"))
0450: hbuf.write(0);
0451: else
0452: hbuf.write(1);
0453:
0454: // SPcod
0455: // Number of decomposition levels
0456: hbuf.write(mrl);
0457:
0458: // Code-block width and height
0459: if (mh) {
0460: // main header, get default values
0461: tmp = wp.getCodeBlockSize().getCBlkWidth(
0462: ModuleSpec.SPEC_DEF, -1, -1);
0463: hbuf.write(MathUtil.log2(tmp) - 2);
0464: tmp = wp.getCodeBlockSize().getCBlkHeight(
0465: ModuleSpec.SPEC_DEF, -1, -1);
0466: hbuf.write(MathUtil.log2(tmp) - 2);
0467: } else {
0468: // tile header, get tile default values
0469: tmp = wp.getCodeBlockSize().getCBlkWidth(
0470: ModuleSpec.SPEC_TILE_DEF, tileIdx, -1);
0471: hbuf.write(MathUtil.log2(tmp) - 2);
0472: tmp = wp.getCodeBlockSize().getCBlkHeight(
0473: ModuleSpec.SPEC_TILE_DEF, tileIdx, -1);
0474: hbuf.write(MathUtil.log2(tmp) - 2);
0475: }
0476:
0477: // Style of the code-block coding passes
0478: tmp = 0;
0479: if (mh) { // Main header
0480: // Selective arithmetic coding bypass ?
0481: if (((String) wp.getBypass().getDefault()).equals("true")) {
0482: tmp |= OPT_BYPASS;
0483: }
0484: // MQ reset after each coding pass ?
0485: if (((String) wp.getResetMQ().getDefault()).equals("true")) {
0486: tmp |= OPT_RESET_MQ;
0487: }
0488: // MQ termination after each arithmetically coded coding pass ?
0489: if (((String) wp.getTerminateOnByte().getDefault())
0490: .equals("true")) {
0491: tmp |= OPT_TERM_PASS;
0492: }
0493: // Vertically stripe-causal context mode ?
0494: if (((String) wp.getCausalCXInfo().getDefault())
0495: .equals("true")) {
0496: tmp |= OPT_VERT_STR_CAUSAL;
0497: }
0498: // Predictable termination ?
0499: if (((String) wp.getMethodForMQTermination().getDefault())
0500: .equals("predict")) {
0501: tmp |= OPT_PRED_TERM;
0502: }
0503: // Error resilience segmentation symbol insertion ?
0504: if (((String) wp.getCodeSegSymbol().getDefault())
0505: .equals("true")) {
0506: tmp |= OPT_SEG_SYMBOLS;
0507: }
0508: } else { // Tile header
0509:
0510: // Selective arithmetic coding bypass ?
0511: if (((String) wp.getBypass().getTileDef(tileIdx))
0512: .equals("true")) {
0513: tmp |= OPT_BYPASS;
0514: }
0515: // MQ reset after each coding pass ?
0516: if (((String) wp.getResetMQ().getTileDef(tileIdx))
0517: .equals("true")) {
0518: tmp |= OPT_RESET_MQ;
0519: }
0520: // MQ termination after each arithmetically coded coding pass ?
0521: if (((String) wp.getTerminateOnByte().getTileDef(tileIdx))
0522: .equals("true")) {
0523: tmp |= OPT_TERM_PASS;
0524: }
0525: // Vertically stripe-causal context mode ?
0526: if (((String) wp.getCausalCXInfo().getTileDef(tileIdx))
0527: .equals("true")) {
0528: tmp |= OPT_VERT_STR_CAUSAL;
0529: }
0530: // Predictable termination ?
0531: if (((String) wp.getMethodForMQTermination().getTileDef(
0532: tileIdx)).equals("predict")) {
0533: tmp |= OPT_PRED_TERM;
0534: }
0535: // Error resilience segmentation symbol insertion ?
0536: if (((String) wp.getCodeSegSymbol().getTileDef(tileIdx))
0537: .equals("true")) {
0538: tmp |= OPT_SEG_SYMBOLS;
0539: }
0540: }
0541: hbuf.write(tmp);
0542:
0543: // Wavelet transform
0544: // Wavelet Filter
0545: if (mh) {
0546: filt = ((AnWTFilter[][]) wp.getFilters().getDefault());
0547: hbuf.write(filt[0][0].getFilterType());
0548: } else {
0549: filt = ((AnWTFilter[][]) wp.getFilters()
0550: .getTileDef(tileIdx));
0551: hbuf.write(filt[0][0].getFilterType());
0552: }
0553:
0554: // Precinct partition
0555: if (precinctPartitionUsed) {
0556: // Write the precinct size for each resolution level + 1
0557: // (resolution 0) if precinct partition is used.
0558: Vector v[] = null;
0559: if (mh) {
0560: v = (Vector[]) wp.getPrecinctPartition().getDefault();
0561: } else {
0562: v = (Vector[]) wp.getPrecinctPartition().getTileDef(
0563: tileIdx);
0564: }
0565: for (int r = mrl; r >= 0; r--) {
0566: if (r >= v[1].size()) {
0567: tmp = ((Integer) v[1].elementAt(v[1].size() - 1))
0568: .intValue();
0569: } else {
0570: tmp = ((Integer) v[1].elementAt(r)).intValue();
0571: }
0572: int yExp = (MathUtil.log2(tmp) << 4) & 0x00F0;
0573:
0574: if (r >= v[0].size()) {
0575: tmp = ((Integer) v[0].elementAt(v[0].size() - 1))
0576: .intValue();
0577: } else {
0578: tmp = ((Integer) v[0].elementAt(r)).intValue();
0579: }
0580: int xExp = MathUtil.log2(tmp) & 0x000F;
0581: hbuf.write(yExp | xExp);
0582: }
0583: }
0584: }
0585:
0586: /**
0587: * Writes COC marker segment . It is a functional marker containing the
0588: * coding style for one component (coding style, decomposition, layering).
0589: *
0590: * <P>Its values overrides any value previously set in COD in the main
0591: * header or in the tile header.
0592: *
0593: * @param mh Flag indicating whether the main header is to be written
0594: *
0595: * @param tileIdx Tile index
0596: *
0597: * @param compIdx index of the component which need use of the COC marker
0598: * segment.
0599: *
0600: * @see #writeCOD
0601: * */
0602: protected void writeCOC(boolean mh, int tileIdx, int compIdx)
0603: throws IOException {
0604: AnWTFilter[][] filt;
0605: boolean precinctPartitionUsed;
0606: int tmp;
0607: int mrl = 0, a = 0;
0608: int ppx = 0, ppy = 0;
0609: Progression[] prog;
0610:
0611: if (mh) {
0612: mrl = ((Integer) wp.getDecompositionLevel().getCompDef(
0613: compIdx)).intValue();
0614: // Get precinct size for specified component
0615: ppx = wp.getPrecinctPartition().getPPX(-1, compIdx, mrl);
0616: ppy = wp.getPrecinctPartition().getPPY(-1, compIdx, mrl);
0617: prog = (Progression[]) (wp.getProgressionType()
0618: .getCompDef(compIdx));
0619: } else {
0620: mrl = ((Integer) wp.getDecompositionLevel().getTileCompVal(
0621: tileIdx, compIdx)).intValue();
0622: // Get precinct size for specified component/tile
0623: ppx = wp.getPrecinctPartition().getPPX(tileIdx, compIdx,
0624: mrl);
0625: ppy = wp.getPrecinctPartition().getPPY(tileIdx, compIdx,
0626: mrl);
0627: prog = (Progression[]) (wp.getProgressionType()
0628: .getTileCompVal(tileIdx, compIdx));
0629: }
0630:
0631: if (ppx != Markers.PRECINCT_PARTITION_DEF_SIZE
0632: || ppy != Markers.PRECINCT_PARTITION_DEF_SIZE) {
0633: precinctPartitionUsed = true;
0634: } else {
0635: precinctPartitionUsed = false;
0636: }
0637: if (precinctPartitionUsed) {
0638: // If precinct partition is used we add one byte per resolution
0639: // level i.e. mrl+1 (+1 for resolution 0).
0640: a = mrl + 1;
0641: }
0642:
0643: // COC marker
0644: hbuf.writeShort(COC);
0645:
0646: // Lcoc (marker segment length (in bytes))
0647: // Basic: Lcoc(2 bytes)+Scoc(1)+ Ccoc(1 or 2)+SPcod(5+a)
0648: int markSegLen = 8 + ((nComp < 257) ? 1 : 2) + a;
0649:
0650: // Rounded to the nearest even value greater or equals
0651: hbuf.writeShort(markSegLen);
0652:
0653: // Ccoc
0654: if (nComp < 257) {
0655: hbuf.write(compIdx);
0656: } else {
0657: hbuf.writeShort(compIdx);
0658: }
0659:
0660: // Scod (coding style parameter)
0661: tmp = 0;
0662: if (precinctPartitionUsed) {
0663: tmp = SCOX_PRECINCT_PARTITION;
0664: }
0665: hbuf.write(tmp);
0666:
0667: // SPcoc
0668:
0669: // Number of decomposition levels
0670: hbuf.write(mrl);
0671:
0672: // Code-block width and height
0673: if (mh) {
0674: // main header, get component default values
0675: tmp = wp.getCodeBlockSize().getCBlkWidth(
0676: ModuleSpec.SPEC_COMP_DEF, -1, compIdx);
0677: hbuf.write(MathUtil.log2(tmp) - 2);
0678: tmp = wp.getCodeBlockSize().getCBlkHeight(
0679: ModuleSpec.SPEC_COMP_DEF, -1, compIdx);
0680: hbuf.write(MathUtil.log2(tmp) - 2);
0681: } else {
0682: // tile header, get tile component values
0683: tmp = wp.getCodeBlockSize().getCBlkWidth(
0684: ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
0685: hbuf.write(MathUtil.log2(tmp) - 2);
0686: tmp = wp.getCodeBlockSize().getCBlkHeight(
0687: ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
0688: hbuf.write(MathUtil.log2(tmp) - 2);
0689: }
0690:
0691: // Entropy coding mode options
0692: tmp = 0;
0693: if (mh) { // Main header
0694: // Lazy coding mode ?
0695: if (((String) wp.getBypass().getCompDef(compIdx))
0696: .equals("true")) {
0697: tmp |= OPT_BYPASS;
0698: }
0699: // MQ reset after each coding pass ?
0700: if (((String) wp.getResetMQ().getCompDef(compIdx))
0701: .equalsIgnoreCase("true")) {
0702: tmp |= OPT_RESET_MQ;
0703: }
0704: // MQ termination after each arithmetically coded coding pass ?
0705: if (((String) wp.getTerminateOnByte().getCompDef(compIdx))
0706: .equals("true")) {
0707: tmp |= OPT_TERM_PASS;
0708: }
0709: // Vertically stripe-causal context mode ?
0710: if (((String) wp.getCausalCXInfo().getCompDef(compIdx))
0711: .equals("true")) {
0712: tmp |= OPT_VERT_STR_CAUSAL;
0713: }
0714: // Predictable termination ?
0715: if (((String) wp.getMethodForMQTermination().getCompDef(
0716: compIdx)).equals("predict")) {
0717: tmp |= OPT_PRED_TERM;
0718: }
0719: // Error resilience segmentation symbol insertion ?
0720: if (((String) wp.getCodeSegSymbol().getCompDef(compIdx))
0721: .equals("true")) {
0722: tmp |= OPT_SEG_SYMBOLS;
0723: }
0724: } else { // Tile Header
0725: if (((String) wp.getBypass().getTileCompVal(tileIdx,
0726: compIdx)).equals("true")) {
0727: tmp |= OPT_BYPASS;
0728: }
0729: // MQ reset after each coding pass ?
0730: if (((String) wp.getResetMQ().getTileCompVal(tileIdx,
0731: compIdx)).equals("true")) {
0732: tmp |= OPT_RESET_MQ;
0733: }
0734: // MQ termination after each arithmetically coded coding pass ?
0735: if (((String) wp.getTerminateOnByte().getTileCompVal(
0736: tileIdx, compIdx)).equals("true")) {
0737: tmp |= OPT_TERM_PASS;
0738: }
0739: // Vertically stripe-causal context mode ?
0740: if (((String) wp.getCausalCXInfo().getTileCompVal(tileIdx,
0741: compIdx)).equals("true")) {
0742: tmp |= OPT_VERT_STR_CAUSAL;
0743: }
0744: // Predictable termination ?
0745: if (((String) wp.getMethodForMQTermination()
0746: .getTileCompVal(tileIdx, compIdx))
0747: .equals("predict")) {
0748: tmp |= OPT_PRED_TERM;
0749: }
0750: // Error resilience segmentation symbol insertion ?
0751: if (((String) wp.getCodeSegSymbol().getTileCompVal(tileIdx,
0752: compIdx)).equals("true")) {
0753: tmp |= OPT_SEG_SYMBOLS;
0754: }
0755: }
0756: hbuf.write(tmp);
0757:
0758: // Wavelet transform
0759: // Wavelet Filter
0760: if (mh) {
0761: filt = ((AnWTFilter[][]) wp.getFilters()
0762: .getCompDef(compIdx));
0763: hbuf.write(filt[0][0].getFilterType());
0764: } else {
0765: filt = ((AnWTFilter[][]) wp.getFilters().getTileCompVal(
0766: tileIdx, compIdx));
0767: hbuf.write(filt[0][0].getFilterType());
0768: }
0769:
0770: // Precinct partition
0771: if (precinctPartitionUsed) {
0772: // Write the precinct size for each resolution level + 1
0773: // (resolution 0) if precinct partition is used.
0774: Vector v[] = null;
0775: if (mh) {
0776: v = (Vector[]) wp.getPrecinctPartition().getCompDef(
0777: compIdx);
0778: } else {
0779: v = (Vector[]) wp.getPrecinctPartition()
0780: .getTileCompVal(tileIdx, compIdx);
0781: }
0782: for (int r = mrl; r >= 0; r--) {
0783: if (r >= v[1].size()) {
0784: tmp = ((Integer) v[1].elementAt(v[1].size() - 1))
0785: .intValue();
0786: } else {
0787: tmp = ((Integer) v[1].elementAt(r)).intValue();
0788: }
0789: int yExp = (MathUtil.log2(tmp) << 4) & 0x00F0;
0790:
0791: if (r >= v[0].size()) {
0792: tmp = ((Integer) v[0].elementAt(v[0].size() - 1))
0793: .intValue();
0794: } else {
0795: tmp = ((Integer) v[0].elementAt(r)).intValue();
0796: }
0797: int xExp = MathUtil.log2(tmp) & 0x000F;
0798: hbuf.write(yExp | xExp);
0799: }
0800: }
0801:
0802: }
0803:
0804: /**
0805: * Writes QCD marker segment in main header. QCD is a functional marker
0806: * segment countaining the quantization default used for compressing all
0807: * the components in an image. The values can be overriden for an
0808: * individual component by a QCC marker in either the main or the tile
0809: * header.
0810: * */
0811: protected void writeMainQCD() throws IOException {
0812: float step;
0813:
0814: String qType = (String) wp.getQuantizationType().getDefault();
0815: float baseStep = ((Float) wp.getQuantizationStep().getDefault())
0816: .floatValue();
0817: int gb = ((Integer) wp.getGuardBits().getDefault()).intValue();
0818:
0819: boolean isDerived = qType.equals("derived");
0820: boolean isReversible = qType.equals("reversible");
0821: int mrl = ((Integer) wp.getDecompositionLevel().getDefault())
0822: .intValue();
0823:
0824: int nt = dwt.getNumTiles();
0825: int nc = dwt.getNumComps();
0826: int tmpI;
0827: int[] tcIdx = new int[2];
0828: String tmpStr;
0829: boolean notFound = true;
0830: for (int t = 0; t < nt && notFound; t++) {
0831: for (int c = 0; c < nc && notFound; c++) {
0832: tmpI = ((Integer) wp.getDecompositionLevel()
0833: .getTileCompVal(t, c)).intValue();
0834: tmpStr = (String) wp.getQuantizationType()
0835: .getTileCompVal(t, c);
0836: if (tmpI == mrl && tmpStr.equals(qType)) {
0837: tcIdx[0] = t;
0838: tcIdx[1] = c;
0839: notFound = false;
0840: }
0841: }
0842: }
0843: if (notFound) {
0844: throw new Error(
0845: "Default representative for quantization type "
0846: + " and number of decomposition levels not found "
0847: + " in main QCD marker segment. "
0848: + "You have found a JJ2000 bug.");
0849: }
0850: SubbandAn sb, csb, sbRoot = dwt.getAnSubbandTree(tcIdx[0],
0851: tcIdx[1]);
0852: defimgn = dwt.getNomRangeBits(tcIdx[1]);
0853:
0854: int nqcd; // Number of quantization step-size to transmit
0855:
0856: // Get the quantization style
0857: int qstyle = (isReversible) ? SQCX_NO_QUANTIZATION
0858: : ((isDerived) ? SQCX_SCALAR_DERIVED
0859: : SQCX_SCALAR_EXPOUNDED);
0860:
0861: // QCD marker
0862: hbuf.writeShort(QCD);
0863:
0864: // Compute the number of steps to send
0865: switch (qstyle) {
0866: case SQCX_SCALAR_DERIVED:
0867: nqcd = 1; // Just the LL value
0868: break;
0869: case SQCX_NO_QUANTIZATION:
0870: case SQCX_SCALAR_EXPOUNDED:
0871: // One value per subband
0872: nqcd = 0;
0873:
0874: sb = sbRoot;
0875:
0876: // Get the subband at first resolution level
0877: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
0878:
0879: // Count total number of subbands
0880: for (int j = 0; j <= mrl; j++) {
0881: csb = sb;
0882: while (csb != null) {
0883: nqcd++;
0884: csb = (SubbandAn) csb.nextSubband();
0885: }
0886: // Go up one resolution level
0887: sb = (SubbandAn) sb.getNextResLevel();
0888: }
0889: break;
0890: default:
0891: throw new Error("Internal JJ2000 error");
0892: }
0893:
0894: // Lqcd (marker segment length (in bytes))
0895: // Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd)
0896: int markSegLen = 3 + ((isReversible) ? nqcd : 2 * nqcd);
0897:
0898: // Rounded to the nearest even value greater or equals
0899: hbuf.writeShort(markSegLen);
0900:
0901: // Sqcd
0902: hbuf.write(qstyle + (gb << SQCX_GB_SHIFT));
0903:
0904: // SPqcd
0905: switch (qstyle) {
0906: case SQCX_NO_QUANTIZATION:
0907: sb = sbRoot;
0908: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
0909:
0910: // Output one exponent per subband
0911: for (int j = 0; j <= mrl; j++) {
0912: csb = sb;
0913: while (csb != null) {
0914: int tmp = (defimgn + csb.anGainExp);
0915: hbuf.write(tmp << SQCX_EXP_SHIFT);
0916:
0917: csb = (SubbandAn) csb.nextSubband();
0918: // Go up one resolution level
0919: }
0920: sb = (SubbandAn) sb.getNextResLevel();
0921: }
0922: break;
0923: case SQCX_SCALAR_DERIVED:
0924: sb = sbRoot;
0925: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
0926:
0927: // Calculate subband step (normalized to unit
0928: // dynamic range)
0929: step = baseStep / (1 << sb.level);
0930:
0931: // Write exponent-mantissa, 16 bits
0932: hbuf.writeShort(StdQuantizer.convertToExpMantissa(step));
0933: break;
0934: case SQCX_SCALAR_EXPOUNDED:
0935: sb = sbRoot;
0936: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
0937:
0938: // Output one step per subband
0939: for (int j = 0; j <= mrl; j++) {
0940: csb = sb;
0941: while (csb != null) {
0942: // Calculate subband step (normalized to unit
0943: // dynamic range)
0944: step = baseStep
0945: / (csb.l2Norm * (1 << csb.anGainExp));
0946:
0947: // Write exponent-mantissa, 16 bits
0948: hbuf.writeShort(StdQuantizer
0949: .convertToExpMantissa(step));
0950:
0951: csb = (SubbandAn) csb.nextSubband();
0952: }
0953: // Go up one resolution level
0954: sb = (SubbandAn) sb.getNextResLevel();
0955: }
0956: break;
0957: default:
0958: throw new Error("Internal JJ2000 error");
0959: }
0960: }
0961:
0962: /**
0963: * Writes QCC marker segment in main header. It is a functional
0964: * marker segment countaining the quantization used for
0965: * compressing the specified component in an image. The values
0966: * override for the specified component what was defined by a QCC
0967: * marker in either the main or the tile header.
0968: *
0969: * @param compIdx Index of the component which needs QCC marker
0970: * segment.
0971: * */
0972: protected void writeMainQCC(int compIdx) throws IOException {
0973:
0974: int mrl;
0975: int qstyle;
0976: int tIdx = 0;
0977: float step;
0978:
0979: SubbandAn sb, sb2;
0980: SubbandAn sbRoot;
0981:
0982: int imgnr = dwt.getNomRangeBits(compIdx);
0983: String qType = (String) wp.getQuantizationType().getCompDef(
0984: compIdx);
0985: float baseStep = ((Float) wp.getQuantizationStep().getCompDef(
0986: compIdx)).floatValue();
0987: int gb = ((Integer) wp.getGuardBits().getCompDef(compIdx))
0988: .intValue();
0989:
0990: boolean isReversible = qType.equals("reversible");
0991: boolean isDerived = qType.equals("derived");
0992:
0993: mrl = ((Integer) wp.getDecompositionLevel().getCompDef(compIdx))
0994: .intValue();
0995:
0996: int nt = dwt.getNumTiles();
0997: int nc = dwt.getNumComps();
0998: int tmpI;
0999: String tmpStr;
1000: boolean notFound = true;
1001: for (int t = 0; t < nt && notFound; t++) {
1002: for (int c = 0; c < nc && notFound; c++) {
1003: tmpI = ((Integer) wp.getDecompositionLevel()
1004: .getTileCompVal(t, c)).intValue();
1005: tmpStr = (String) wp.getQuantizationType()
1006: .getTileCompVal(t, c);
1007: if (tmpI == mrl && tmpStr.equals(qType)) {
1008: tIdx = t;
1009: notFound = false;
1010: }
1011: }
1012: }
1013: if (notFound) {
1014: throw new Error(
1015: "Default representative for quantization type "
1016: + " and number of decomposition levels not found "
1017: + " in main QCC (c=" + compIdx
1018: + ") marker segment. "
1019: + "You have found a JJ2000 bug.");
1020: }
1021: sbRoot = dwt.getAnSubbandTree(tIdx, compIdx);
1022:
1023: int nqcc; // Number of quantization step-size to transmit
1024:
1025: // Get the quantization style
1026: if (isReversible) {
1027: qstyle = SQCX_NO_QUANTIZATION;
1028: } else if (isDerived) {
1029: qstyle = SQCX_SCALAR_DERIVED;
1030: } else {
1031: qstyle = SQCX_SCALAR_EXPOUNDED;
1032: }
1033:
1034: // QCC marker
1035: hbuf.writeShort(QCC);
1036:
1037: // Compute the number of steps to send
1038: switch (qstyle) {
1039: case SQCX_SCALAR_DERIVED:
1040: nqcc = 1; // Just the LL value
1041: break;
1042: case SQCX_NO_QUANTIZATION:
1043: case SQCX_SCALAR_EXPOUNDED:
1044: // One value per subband
1045: nqcc = 0;
1046:
1047: sb = sbRoot;
1048: mrl = sb.resLvl;
1049:
1050: // Get the subband at first resolution level
1051: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1052:
1053: // Find root element for LL subband
1054: while (sb.resLvl != 0) {
1055: sb = sb.subb_LL;
1056: }
1057:
1058: // Count total number of subbands
1059: for (int j = 0; j <= mrl; j++) {
1060: sb2 = sb;
1061: while (sb2 != null) {
1062: nqcc++;
1063: sb2 = (SubbandAn) sb2.nextSubband();
1064: }
1065: // Go up one resolution level
1066: sb = (SubbandAn) sb.getNextResLevel();
1067: }
1068: break;
1069: default:
1070: throw new Error("Internal JJ2000 error");
1071: }
1072:
1073: // Lqcc (marker segment length (in bytes))
1074: // Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc)
1075: int markSegLen = 3 + ((nComp < 257) ? 1 : 2)
1076: + ((isReversible) ? nqcc : 2 * nqcc);
1077: hbuf.writeShort(markSegLen);
1078:
1079: // Cqcc
1080: if (nComp < 257) {
1081: hbuf.write(compIdx);
1082: } else {
1083: hbuf.writeShort(compIdx);
1084: }
1085:
1086: // Sqcc (quantization style)
1087: hbuf.write(qstyle + (gb << SQCX_GB_SHIFT));
1088:
1089: // SPqcc
1090: switch (qstyle) {
1091: case SQCX_NO_QUANTIZATION:
1092: // Get resolution level 0 subband
1093: sb = sbRoot;
1094: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1095:
1096: // Output one exponent per subband
1097: for (int j = 0; j <= mrl; j++) {
1098: sb2 = sb;
1099: while (sb2 != null) {
1100: int tmp = (imgnr + sb2.anGainExp);
1101: hbuf.write(tmp << SQCX_EXP_SHIFT);
1102:
1103: sb2 = (SubbandAn) sb2.nextSubband();
1104: }
1105: // Go up one resolution level
1106: sb = (SubbandAn) sb.getNextResLevel();
1107: }
1108: break;
1109: case SQCX_SCALAR_DERIVED:
1110: // Get resolution level 0 subband
1111: sb = sbRoot;
1112: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1113:
1114: // Calculate subband step (normalized to unit
1115: // dynamic range)
1116: step = baseStep / (1 << sb.level);
1117:
1118: // Write exponent-mantissa, 16 bits
1119: hbuf.writeShort(StdQuantizer.convertToExpMantissa(step));
1120: break;
1121: case SQCX_SCALAR_EXPOUNDED:
1122: // Get resolution level 0 subband
1123: sb = sbRoot;
1124: mrl = sb.resLvl;
1125:
1126: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1127:
1128: for (int j = 0; j <= mrl; j++) {
1129: sb2 = sb;
1130: while (sb2 != null) {
1131: // Calculate subband step (normalized to unit
1132: // dynamic range)
1133: step = baseStep
1134: / (sb2.l2Norm * (1 << sb2.anGainExp));
1135:
1136: // Write exponent-mantissa, 16 bits
1137: hbuf.writeShort(StdQuantizer
1138: .convertToExpMantissa(step));
1139: sb2 = (SubbandAn) sb2.nextSubband();
1140: }
1141: // Go up one resolution level
1142: sb = (SubbandAn) sb.getNextResLevel();
1143: }
1144: break;
1145: default:
1146: throw new Error("Internal JJ2000 error");
1147: }
1148: }
1149:
1150: /**
1151: * Writes QCD marker segment in tile header. QCD is a functional
1152: * marker segment countaining the quantization default used for
1153: * compressing all the components in an image. The values can be
1154: * overriden for an individual component by a QCC marker in either
1155: * the main or the tile header.
1156: *
1157: * @param tIdx Tile index
1158: * */
1159: protected void writeTileQCD(int tIdx) throws IOException {
1160: int mrl;
1161: int qstyle;
1162:
1163: float step;
1164: SubbandAn sb, csb, sbRoot;
1165:
1166: String qType = (String) wp.getQuantizationType().getTileDef(
1167: tIdx);
1168: float baseStep = ((Float) wp.getQuantizationStep().getTileDef(
1169: tIdx)).floatValue();
1170: mrl = ((Integer) wp.getDecompositionLevel().getTileDef(tIdx))
1171: .intValue();
1172:
1173: int nc = dwt.getNumComps();
1174: int tmpI;
1175: String tmpStr;
1176: boolean notFound = true;
1177: int compIdx = 0;
1178: for (int c = 0; c < nc && notFound; c++) {
1179: tmpI = ((Integer) wp.getDecompositionLevel()
1180: .getTileCompVal(tIdx, c)).intValue();
1181: tmpStr = (String) wp.getQuantizationStep().getTileCompVal(
1182: tIdx, c);
1183: if (tmpI == mrl && tmpStr.equals(qType)) {
1184: compIdx = c;
1185: notFound = false;
1186: }
1187: }
1188: if (notFound) {
1189: throw new Error(
1190: "Default representative for quantization type "
1191: + " and number of decomposition levels not found "
1192: + " in tile QCD (t=" + tIdx
1193: + ") marker segment. "
1194: + "You have found a JJ2000 bug.");
1195: }
1196:
1197: sbRoot = dwt.getAnSubbandTree(tIdx, compIdx);
1198: deftilenr = dwt.getNomRangeBits(compIdx);
1199: int gb = ((Integer) wp.getGuardBits().getTileDef(tIdx))
1200: .intValue();
1201:
1202: boolean isDerived = qType.equals("derived");
1203: boolean isReversible = qType.equals("reversible");
1204:
1205: int nqcd; // Number of quantization step-size to transmit
1206:
1207: // Get the quantization style
1208: qstyle = (isReversible) ? SQCX_NO_QUANTIZATION
1209: : ((isDerived) ? SQCX_SCALAR_DERIVED
1210: : SQCX_SCALAR_EXPOUNDED);
1211:
1212: // QCD marker
1213: hbuf.writeShort(QCD);
1214:
1215: // Compute the number of steps to send
1216: switch (qstyle) {
1217: case SQCX_SCALAR_DERIVED:
1218: nqcd = 1; // Just the LL value
1219: break;
1220: case SQCX_NO_QUANTIZATION:
1221: case SQCX_SCALAR_EXPOUNDED:
1222: // One value per subband
1223: nqcd = 0;
1224:
1225: sb = sbRoot;
1226:
1227: // Get the subband at first resolution level
1228: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1229:
1230: // Count total number of subbands
1231: for (int j = 0; j <= mrl; j++) {
1232: csb = sb;
1233: while (csb != null) {
1234: nqcd++;
1235: csb = (SubbandAn) csb.nextSubband();
1236: }
1237: // Go up one resolution level
1238: sb = (SubbandAn) sb.getNextResLevel();
1239: }
1240: break;
1241: default:
1242: throw new Error("Internal JJ2000 error");
1243: }
1244:
1245: // Lqcd (marker segment length (in bytes))
1246: // Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd)
1247: int markSegLen = 3 + ((isReversible) ? nqcd : 2 * nqcd);
1248:
1249: // Rounded to the nearest even value greater or equals
1250: hbuf.writeShort(markSegLen);
1251:
1252: // Sqcd
1253: hbuf.write(qstyle + (gb << SQCX_GB_SHIFT));
1254:
1255: // SPqcd
1256: switch (qstyle) {
1257: case SQCX_NO_QUANTIZATION:
1258: sb = sbRoot;
1259: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1260:
1261: // Output one exponent per subband
1262: for (int j = 0; j <= mrl; j++) {
1263: csb = sb;
1264: while (csb != null) {
1265: int tmp = (deftilenr + csb.anGainExp);
1266: hbuf.write(tmp << SQCX_EXP_SHIFT);
1267:
1268: csb = (SubbandAn) csb.nextSubband();
1269: // Go up one resolution level
1270: }
1271: sb = (SubbandAn) sb.getNextResLevel();
1272: }
1273: break;
1274: case SQCX_SCALAR_DERIVED:
1275: sb = sbRoot;
1276: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1277:
1278: // Calculate subband step (normalized to unit
1279: // dynamic range)
1280: step = baseStep / (1 << sb.level);
1281:
1282: // Write exponent-mantissa, 16 bits
1283: hbuf.writeShort(StdQuantizer.convertToExpMantissa(step));
1284: break;
1285: case SQCX_SCALAR_EXPOUNDED:
1286: sb = sbRoot;
1287: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1288:
1289: // Output one step per subband
1290: for (int j = 0; j <= mrl; j++) {
1291: csb = sb;
1292: while (csb != null) {
1293: // Calculate subband step (normalized to unit
1294: // dynamic range)
1295: step = baseStep
1296: / (csb.l2Norm * (1 << csb.anGainExp));
1297:
1298: // Write exponent-mantissa, 16 bits
1299: hbuf.writeShort(StdQuantizer
1300: .convertToExpMantissa(step));
1301:
1302: csb = (SubbandAn) csb.nextSubband();
1303: }
1304: // Go up one resolution level
1305: sb = (SubbandAn) sb.getNextResLevel();
1306: }
1307: break;
1308: default:
1309: throw new Error("Internal JJ2000 error");
1310: }
1311: }
1312:
1313: /**
1314: * Writes QCC marker segment in tile header. It is a functional
1315: * marker segment countaining the quantization used for
1316: * compressing the specified component in an image. The values
1317: * override for the specified component what was defined by a QCC
1318: * marker in either the main or the tile header.
1319: *
1320: * @param t Tile index
1321: *
1322: * @param compIdx Index of the component which needs QCC marker
1323: * segment.
1324: * */
1325: protected void writeTileQCC(int t, int compIdx) throws IOException {
1326:
1327: int mrl;
1328: int qstyle;
1329: float step;
1330:
1331: SubbandAn sb, sb2;
1332: int nqcc; // Number of quantization step-size to transmit
1333:
1334: SubbandAn sbRoot = dwt.getAnSubbandTree(t, compIdx);
1335: int imgnr = dwt.getNomRangeBits(compIdx);
1336: String qType = (String) wp.getQuantizationType()
1337: .getTileCompVal(t, compIdx);
1338: float baseStep = ((Float) wp.getQuantizationStep()
1339: .getTileCompVal(t, compIdx)).floatValue();
1340: int gb = ((Integer) wp.getGuardBits()
1341: .getTileCompVal(t, compIdx)).intValue();
1342:
1343: boolean isReversible = qType.equals("reversible");
1344: boolean isDerived = qType.equals("derived");
1345:
1346: mrl = ((Integer) wp.getDecompositionLevel().getTileCompVal(t,
1347: compIdx)).intValue();
1348:
1349: // Get the quantization style
1350: if (isReversible) {
1351: qstyle = SQCX_NO_QUANTIZATION;
1352: } else if (isDerived) {
1353: qstyle = SQCX_SCALAR_DERIVED;
1354: } else {
1355: qstyle = SQCX_SCALAR_EXPOUNDED;
1356: }
1357:
1358: // QCC marker
1359: hbuf.writeShort(QCC);
1360:
1361: // Compute the number of steps to send
1362: switch (qstyle) {
1363: case SQCX_SCALAR_DERIVED:
1364: nqcc = 1; // Just the LL value
1365: break;
1366: case SQCX_NO_QUANTIZATION:
1367: case SQCX_SCALAR_EXPOUNDED:
1368: // One value per subband
1369: nqcc = 0;
1370:
1371: sb = sbRoot;
1372: mrl = sb.resLvl;
1373:
1374: // Get the subband at first resolution level
1375: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1376:
1377: // Find root element for LL subband
1378: while (sb.resLvl != 0) {
1379: sb = sb.subb_LL;
1380: }
1381:
1382: // Count total number of subbands
1383: for (int j = 0; j <= mrl; j++) {
1384: sb2 = sb;
1385: while (sb2 != null) {
1386: nqcc++;
1387: sb2 = (SubbandAn) sb2.nextSubband();
1388: }
1389: // Go up one resolution level
1390: sb = (SubbandAn) sb.getNextResLevel();
1391: }
1392: break;
1393: default:
1394: throw new Error("Internal JJ2000 error");
1395: }
1396:
1397: // Lqcc (marker segment length (in bytes))
1398: // Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc)
1399: int markSegLen = 3 + ((nComp < 257) ? 1 : 2)
1400: + ((isReversible) ? nqcc : 2 * nqcc);
1401: hbuf.writeShort(markSegLen);
1402:
1403: // Cqcc
1404: if (nComp < 257) {
1405: hbuf.write(compIdx);
1406: } else {
1407: hbuf.writeShort(compIdx);
1408: }
1409:
1410: // Sqcc (quantization style)
1411: hbuf.write(qstyle + (gb << SQCX_GB_SHIFT));
1412:
1413: // SPqcc
1414: switch (qstyle) {
1415: case SQCX_NO_QUANTIZATION:
1416: // Get resolution level 0 subband
1417: sb = sbRoot;
1418: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1419:
1420: // Output one exponent per subband
1421: for (int j = 0; j <= mrl; j++) {
1422: sb2 = sb;
1423: while (sb2 != null) {
1424: int tmp = (imgnr + sb2.anGainExp);
1425: hbuf.write(tmp << SQCX_EXP_SHIFT);
1426:
1427: sb2 = (SubbandAn) sb2.nextSubband();
1428: }
1429: // Go up one resolution level
1430: sb = (SubbandAn) sb.getNextResLevel();
1431: }
1432: break;
1433: case SQCX_SCALAR_DERIVED:
1434: // Get resolution level 0 subband
1435: sb = sbRoot;
1436: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1437:
1438: // Calculate subband step (normalized to unit
1439: // dynamic range)
1440: step = baseStep / (1 << sb.level);
1441:
1442: // Write exponent-mantissa, 16 bits
1443: hbuf.writeShort(StdQuantizer.convertToExpMantissa(step));
1444: break;
1445: case SQCX_SCALAR_EXPOUNDED:
1446: // Get resolution level 0 subband
1447: sb = sbRoot;
1448: mrl = sb.resLvl;
1449:
1450: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1451:
1452: for (int j = 0; j <= mrl; j++) {
1453: sb2 = sb;
1454: while (sb2 != null) {
1455: // Calculate subband step (normalized to unit
1456: // dynamic range)
1457: step = baseStep
1458: / (sb2.l2Norm * (1 << sb2.anGainExp));
1459:
1460: // Write exponent-mantissa, 16 bits
1461: hbuf.writeShort(StdQuantizer
1462: .convertToExpMantissa(step));
1463: sb2 = (SubbandAn) sb2.nextSubband();
1464: }
1465: // Go up one resolution level
1466: sb = (SubbandAn) sb.getNextResLevel();
1467: }
1468: break;
1469: default:
1470: throw new Error("Internal JJ2000 error");
1471: }
1472: }
1473:
1474: /**
1475: * Writes POC marker segment. POC is a functional marker segment
1476: * containing the bounds and progression order for any progression order
1477: * other than default in the codestream.
1478: *
1479: * @param mh Flag indicating whether the main header is to be written
1480: *
1481: * @param tileIdx Tile index
1482: * */
1483: protected void writePOC(boolean mh, int tileIdx) throws IOException {
1484: int markSegLen = 0; // Segment marker length
1485: int lenCompField; // Holds the size of any component field as
1486: // this size depends on the number of
1487: //components
1488: Progression[] prog = null; // Holds the progression(s)
1489: int npoc; // Number of progression order changes
1490:
1491: // Get the progression order changes, their number and checks
1492: // if it is ok
1493: if (mh) {
1494: prog = (Progression[]) (wp.getProgressionType()
1495: .getDefault());
1496: } else {
1497: prog = (Progression[]) (wp.getProgressionType()
1498: .getTileDef(tileIdx));
1499: }
1500:
1501: // Calculate the length of a component field (depends on the number of
1502: // components)
1503: lenCompField = (nComp < 257 ? 1 : 2);
1504:
1505: // POC marker
1506: hbuf.writeShort(POC);
1507:
1508: // Lpoc (marker segment length (in bytes))
1509: // Basic: Lpoc(2 bytes) + npoc * [ RSpoc(1) + CSpoc(1 or 2) + LYEpoc(2)
1510: // + REpoc(1) + CEpoc(1 or 2) + Ppoc(1) ]
1511: npoc = prog.length;
1512: markSegLen = 2 + npoc
1513: * (1 + lenCompField + 2 + 1 + lenCompField + 1);
1514: hbuf.writeShort(markSegLen);
1515:
1516: // Write each progression order change
1517: for (int i = 0; i < npoc; i++) {
1518: // RSpoc(i)
1519: hbuf.write(prog[i].rs);
1520: // CSpoc(i)
1521: if (lenCompField == 2) {
1522: hbuf.writeShort(prog[i].cs);
1523: } else {
1524: hbuf.write(prog[i].cs);
1525: }
1526: // LYEpoc(i)
1527: hbuf.writeShort(prog[i].lye);
1528: // REpoc(i)
1529: hbuf.write(prog[i].re);
1530: // CEpoc(i)
1531: if (lenCompField == 2) {
1532: hbuf.writeShort(prog[i].ce);
1533: } else {
1534: hbuf.write(prog[i].ce);
1535: }
1536: // Ppoc(i)
1537: hbuf.write(prog[i].type);
1538: }
1539: }
1540:
1541: /**
1542: * Write main header. JJ2000 main header corresponds to the following
1543: * sequence of marker
1544: * segments:<ol><li>SOC</li><li>SIZ</li><li>COD</li><li>COC (if
1545: * needed)</li><li>QCD</li><li>QCC (if needed)</li><li>POC (if
1546: * needed)</li></ol>
1547: * */
1548: public void encodeMainHeader() throws IOException {
1549: int i;
1550:
1551: // +---------------------------------+
1552: // | SOC marker segment |
1553: // +---------------------------------+
1554: writeSOC();
1555:
1556: // +---------------------------------+
1557: // | Image and tile SIZe (SIZ) |
1558: // +---------------------------------+
1559: writeSIZ();
1560:
1561: // +-------------------------------+
1562: // | COding style Default (COD) |
1563: // +-------------------------------+
1564: boolean isEresUsed = ((String) wp.getTerminateOnByte()
1565: .getDefault()).equals("predict");
1566: writeCOD(true, 0);
1567:
1568: // +---------------------------------+
1569: // | COding style Component (COC) |
1570: // +---------------------------------+
1571: for (i = 0; i < nComp; i++) {
1572: boolean isEresUsedinComp = ((String) wp
1573: .getTerminateOnByte().getCompDef(i))
1574: .equals("predict");
1575: if (wp.getFilters().isCompSpecified(i)
1576: || wp.getDecompositionLevel().isCompSpecified(i)
1577: || wp.getBypass().isCompSpecified(i)
1578: || wp.getResetMQ().isCompSpecified(i)
1579: || wp.getMethodForMQTermination()
1580: .isCompSpecified(i)
1581: || wp.getCodeSegSymbol().isCompSpecified(i)
1582: || wp.getCausalCXInfo().isCompSpecified(i)
1583: || wp.getPrecinctPartition().isCompSpecified(i)
1584: || wp.getCodeBlockSize().isCompSpecified(i)
1585: || (isEresUsed != isEresUsedinComp))
1586: // Some component non-default stuff => need COC
1587: writeCOC(true, 0, i);
1588: }
1589:
1590: // +-------------------------------+
1591: // | Quantization Default (QCD) |
1592: // +-------------------------------+
1593: writeMainQCD();
1594:
1595: // +-------------------------------+
1596: // | Quantization Component (QCC) |
1597: // +-------------------------------+
1598: // Write needed QCC markers
1599: for (i = 0; i < nComp; i++) {
1600: if (dwt.getNomRangeBits(i) != defimgn
1601: || wp.getQuantizationType().isCompSpecified(i)
1602: || wp.getQuantizationStep().isCompSpecified(i)
1603: || wp.getDecompositionLevel().isCompSpecified(i)
1604: || wp.getGuardBits().isCompSpecified(i)) {
1605: writeMainQCC(i);
1606: }
1607: }
1608:
1609: // +--------------------------+
1610: // | POC maker segment |
1611: // +--------------------------+
1612: Progression[] prog = (Progression[]) (wp.getProgressionType()
1613: .getDefault());
1614: if (prog.length > 1)
1615: writePOC(true, 0);
1616:
1617: // +--------------------------+
1618: // | Comment (COM) |
1619: // +--------------------------+
1620: writeCOM();
1621: }
1622:
1623: /**
1624: * Write a COM marker segment adding some comments to the codestream.
1625: *
1626: * <p> This marker is currently written in main header and indicates the
1627: * JJ2000 encoder's version that has created the codestream.
1628: * */
1629: private void writeCOM() throws IOException {
1630: // JJ2000 COM marker segment
1631: if (enJJ2KMarkSeg) {
1632: String str = "Created by: JJ2000 version "
1633: + JJ2KInfo.version;
1634: int markSegLen; // the marker segment length
1635:
1636: // COM marker
1637: hbuf.writeShort(COM);
1638:
1639: // Calculate length: Lcom(2) + Rcom (2) + string's length;
1640: markSegLen = 2 + 2 + str.length();
1641: hbuf.writeShort(markSegLen);
1642:
1643: // Rcom
1644: hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin) values)
1645:
1646: byte[] chars = str.getBytes();
1647: for (int i = 0; i < chars.length; i++) {
1648: hbuf.writeByte(chars[i]);
1649: }
1650: }
1651: // other COM marker segments
1652: if (otherCOMMarkSeg != null) {
1653: StringTokenizer stk = new StringTokenizer(otherCOMMarkSeg,
1654: "#");
1655: while (stk.hasMoreTokens()) {
1656: String str = stk.nextToken();
1657: int markSegLen; // the marker segment length
1658:
1659: // COM marker
1660: hbuf.writeShort(COM);
1661:
1662: // Calculate length: Lcom(2) + Rcom (2) + string's length;
1663: markSegLen = 2 + 2 + str.length();
1664: hbuf.writeShort(markSegLen);
1665:
1666: // Rcom
1667: hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin)
1668: // values)
1669:
1670: byte[] chars = str.getBytes();
1671: for (int i = 0; i < chars.length; i++) {
1672: hbuf.writeByte(chars[i]);
1673: }
1674: }
1675: }
1676: }
1677:
1678: /**
1679: * Writes the RGN marker segment in the tile header. It describes the
1680: * scaling value in each tile component
1681: *
1682: * <P>May be used in tile or main header. If used in main header, it
1683: * refers to a ROI of the whole image, regardless of tiling. When used in
1684: * tile header, only the particular tile is affected.
1685: *
1686: * @param tIdx The tile index
1687: *
1688: * @exception IOException If an I/O error occurs while reading from the
1689: * encoder header stream
1690: * */
1691: private void writeRGN(int tIdx) throws IOException {
1692: int i;
1693: int markSegLen; // the marker length
1694:
1695: // Write one RGN marker per component
1696: for (i = 0; i < nComp; i++) {
1697: // RGN marker
1698: hbuf.writeShort(RGN);
1699:
1700: // Calculate length (Lrgn)
1701: // Basic: Lrgn (2) + Srgn (1) + SPrgn + one byte
1702: // or two for component number
1703: markSegLen = 4 + ((nComp < 257) ? 1 : 2);
1704: hbuf.writeShort(markSegLen);
1705:
1706: // Write component (Crgn)
1707: if (nComp < 257)
1708: hbuf.writeByte(i);
1709: else
1710: hbuf.writeShort(i);
1711:
1712: // Write type of ROI (Srgn)
1713: hbuf.writeByte(SRGN_IMPLICIT);
1714:
1715: // Write ROI info (SPrgn)
1716: hbuf.writeByte(((Integer) (wp.getROIs().getTileCompVal(
1717: tIdx, i))).intValue());
1718: }
1719: }
1720:
1721: /**
1722: * Writes tile-part header. JJ2000 tile-part header corresponds to the
1723: * following sequence of marker segments:<ol> <li>SOT</li> <li>COD (if
1724: * needed)</li> <li>COC (if needed)</li> <li>QCD (if needed)</li> <li>QCC
1725: * (if needed)</li> <li>RGN (if needed)</li> <li>POC (if needed)</li>
1726: * <li>SOD</li> </ol>
1727: *
1728: * @param length The length of the current tile-part.
1729: *
1730: * @param tileIdx Index of the tile to write
1731: * */
1732: public void encodeTilePartHeader(int tileLength, int tileIdx)
1733: throws IOException {
1734:
1735: int tmp;
1736: Point numTiles = ralloc.getNumTiles(null);
1737: ralloc.setTile(tileIdx % numTiles.x, tileIdx / numTiles.x);
1738:
1739: // +--------------------------+
1740: // | SOT maker segment |
1741: // +--------------------------+
1742: // SOT marker
1743: hbuf.writeByte(SOT >> 8);
1744: hbuf.writeByte(SOT);
1745:
1746: // Lsot (10 bytes)
1747: hbuf.writeByte(0);
1748: hbuf.writeByte(10);
1749:
1750: // Isot
1751: if (tileIdx > 65534) {
1752: throw new IllegalArgumentException(
1753: "Trying to write a tile-part "
1754: + "header whose tile index is too"
1755: + " high");
1756: }
1757: hbuf.writeByte(tileIdx >> 8);
1758: hbuf.writeByte(tileIdx);
1759:
1760: // Psot
1761: tmp = tileLength;
1762: hbuf.writeByte(tmp >> 24);
1763: hbuf.writeByte(tmp >> 16);
1764: hbuf.writeByte(tmp >> 8);
1765: hbuf.writeByte(tmp);
1766:
1767: // TPsot
1768: hbuf.writeByte(0); // Only one tile-part currently supported !
1769:
1770: // TNsot
1771: hbuf.writeByte(1); // Only one tile-part currently supported !
1772:
1773: // +--------------------------+
1774: // | COD maker segment |
1775: // +--------------------------+
1776: boolean isEresUsed = ((String) wp.getMethodForMQTermination()
1777: .getDefault()).equals("predict");
1778: boolean isEresUsedInTile = ((String) wp
1779: .getMethodForMQTermination().getTileDef(tileIdx))
1780: .equals("predict");
1781: boolean tileCODwritten = false;
1782: if (wp.getFilters().isTileSpecified(tileIdx)
1783: || wp.getComponentTransformation().isTileSpecified(
1784: tileIdx)
1785: || wp.getDecompositionLevel().isTileSpecified(tileIdx)
1786: || wp.getBypass().isTileSpecified(tileIdx)
1787: || wp.getResetMQ().isTileSpecified(tileIdx)
1788: || wp.getTerminateOnByte().isTileSpecified(tileIdx)
1789: || wp.getCausalCXInfo().isTileSpecified(tileIdx)
1790: || wp.getPrecinctPartition().isTileSpecified(tileIdx)
1791: || wp.getSOP().isTileSpecified(tileIdx)
1792: || wp.getCodeSegSymbol().isTileSpecified(tileIdx)
1793: || wp.getProgressionType().isTileSpecified(tileIdx)
1794: || wp.getEPH().isTileSpecified(tileIdx)
1795: || wp.getCodeBlockSize().isTileSpecified(tileIdx)
1796: || (isEresUsed != isEresUsedInTile)) {
1797: writeCOD(false, tileIdx);
1798: tileCODwritten = true;
1799: }
1800:
1801: // +--------------------------+
1802: // | COC maker segment |
1803: // +--------------------------+
1804: for (int c = 0; c < nComp; c++) {
1805: boolean isEresUsedInTileComp = ((String) wp
1806: .getMethodForMQTermination().getTileCompVal(
1807: tileIdx, c)).equals("predict");
1808:
1809: if (wp.getFilters().isTileCompSpecified(tileIdx, c)
1810: || wp.getDecompositionLevel().isTileCompSpecified(
1811: tileIdx, c)
1812: || wp.getBypass().isTileCompSpecified(tileIdx, c)
1813: || wp.getResetMQ().isTileCompSpecified(tileIdx, c)
1814: || wp.getTerminateOnByte().isTileCompSpecified(
1815: tileIdx, c)
1816: || wp.getCausalCXInfo().isTileCompSpecified(
1817: tileIdx, c)
1818: || wp.getPrecinctPartition().isTileCompSpecified(
1819: tileIdx, c)
1820: || wp.getCodeSegSymbol().isTileCompSpecified(
1821: tileIdx, c)
1822: || wp.getCodeBlockSize().isTileCompSpecified(
1823: tileIdx, c)
1824: || (isEresUsedInTileComp != isEresUsed)) {
1825: writeCOC(false, tileIdx, c);
1826: } else if (tileCODwritten) {
1827: if (wp.getFilters().isCompSpecified(c)
1828: || wp.getDecompositionLevel()
1829: .isCompSpecified(c)
1830: || wp.getBypass().isCompSpecified(c)
1831: || wp.getResetMQ().isCompSpecified(c)
1832: || wp.getTerminateOnByte().isCompSpecified(c)
1833: || wp.getCodeSegSymbol().isCompSpecified(c)
1834: || wp.getCausalCXInfo().isCompSpecified(c)
1835: || wp.getPrecinctPartition().isCompSpecified(c)
1836: || wp.getCodeBlockSize().isCompSpecified(c)
1837: || (wp.getMethodForMQTermination()
1838: .isCompSpecified(c) && ((String) wp
1839: .getMethodForMQTermination()
1840: .getCompDef(c)).equals("predict"))) {
1841: writeCOC(false, tileIdx, c);
1842: }
1843: }
1844: }
1845:
1846: // +--------------------------+
1847: // | QCD maker segment |
1848: // +--------------------------+
1849: boolean tileQCDwritten = false;
1850: if (wp.getQuantizationType().isTileSpecified(tileIdx)
1851: || wp.getQuantizationStep().isTileSpecified(tileIdx)
1852: || wp.getDecompositionLevel().isTileSpecified(tileIdx)
1853: || wp.getGuardBits().isTileSpecified(tileIdx)) {
1854: writeTileQCD(tileIdx);
1855: tileQCDwritten = true;
1856: } else {
1857: deftilenr = defimgn;
1858: }
1859:
1860: // +--------------------------+
1861: // | QCC maker segment |
1862: // +--------------------------+
1863: for (int c = 0; c < nComp; c++) {
1864: if (dwt.getNomRangeBits(c) != deftilenr
1865: || wp.getQuantizationType().isTileCompSpecified(
1866: tileIdx, c)
1867: || wp.getQuantizationStep().isTileCompSpecified(
1868: tileIdx, c)
1869: || wp.getDecompositionLevel().isTileCompSpecified(
1870: tileIdx, c)
1871: || wp.getGuardBits()
1872: .isTileCompSpecified(tileIdx, c)) {
1873: writeTileQCC(tileIdx, c);
1874: } else if (tileQCDwritten) {
1875: if (wp.getQuantizationType().isCompSpecified(c)
1876: || wp.getQuantizationStep().isCompSpecified(c)
1877: || wp.getDecompositionLevel()
1878: .isCompSpecified(c)
1879: || wp.getGuardBits().isCompSpecified(c)) {
1880: writeTileQCC(tileIdx, c);
1881: }
1882: }
1883: }
1884:
1885: // +--------------------------+
1886: // | RGN maker segment |
1887: // +--------------------------+
1888: if (roiSc.useRoi() && (!roiSc.getBlockAligned()))
1889: writeRGN(tileIdx);
1890:
1891: // +--------------------------+
1892: // | POC maker segment |
1893: // +--------------------------+
1894: Progression[] prog;
1895: if (wp.getProgressionType().isTileSpecified(tileIdx)) {
1896: prog = (Progression[]) (wp.getProgressionType()
1897: .getTileDef(tileIdx));
1898: if (prog.length > 1)
1899: writePOC(false, tileIdx);
1900: }
1901:
1902: // +--------------------------+
1903: // | SOD maker |
1904: // +--------------------------+
1905: hbuf.writeByte(SOD >> 8);
1906: hbuf.writeByte(SOD);
1907: }
1908: }
|