0001: /*
0002: * $RCSfile: HeaderDecoder.java,v $
0003: * $Revision: 1.2 $
0004: * $Date: 2006/09/28 00:55:20 $
0005: * $State: Exp $
0006: *
0007: * Class: HeaderDecoder
0008: *
0009: * Description: Reads main and tile-part 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.reader;
0045:
0046: import java.awt.Point;
0047:
0048: import jj2000.j2k.quantization.dequantizer.*;
0049: import jj2000.j2k.wavelet.synthesis.*;
0050: import jj2000.j2k.entropy.decoder.*;
0051: import jj2000.j2k.quantization.*;
0052: import jj2000.j2k.codestream.*;
0053: import jj2000.j2k.wavelet.*;
0054: import jj2000.j2k.entropy.*;
0055: import jj2000.j2k.decoder.*;
0056: import jj2000.j2k.image.*;
0057: import jj2000.j2k.util.*;
0058: import jj2000.j2k.roi.*;
0059: import jj2000.j2k.io.*;
0060: import jj2000.j2k.*;
0061:
0062: import java.io.*;
0063: import java.util.*;
0064:
0065: //import colorspace.*;
0066: //import icc.*;
0067:
0068: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReadParamJava;
0069:
0070: /**
0071: * This class reads Main and Tile-part headers from the codestream. It is
0072: * created by the run() method of the Decoder instance.
0073: *
0074: * <p>A marker segment includes a marker and eventually marker segment
0075: * parameters. It is designed by the three letters code of the marker
0076: * associated with the marker segment. JPEG 2000 part 1 defines 6 types of
0077: * markers:
0078: *
0079: * <ul>
0080: * <li> Delimiting : SOC,SOT (read in FileBitstreamReaderAgent),SOD,EOC
0081: * (read in FileBitstreamReaderAgent).</li> <li> Fixed information: SIZ.</li>
0082: *
0083: * <li> Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream:
0084: * SOP,EPH.</li>
0085: *
0086: * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li>
0087: *
0088: * <li> Informational: CRG,COM.</li>
0089: * </ul>
0090: *
0091: * <p>The main header is read when the constructor is called whereas tile-part
0092: * headers are read when the FileBitstreamReaderAgent instance is created. The
0093: * reading is done in 2 passes:
0094: *
0095: * <ul>
0096: * <li>All marker segments are buffered and their corresponding flag is
0097: * activated (extractMainMarkSeg and extractTilePartMarkSeg methods).</li>
0098: *
0099: * <li>Buffered marker segment are analyzed in a logical way and
0100: * specifications are stored in appropriate member of DecoderSpecs instance
0101: * (readFoundMainMarkSeg and readFoundTilePartMarkSeg methods).</li>
0102: * </ul>
0103: *
0104: * <p>Whenever a marker segment is not recognized a warning message is
0105: * displayed and its length parameter is used to skip it.
0106: *
0107: * @see DecoderSpecs
0108: * @see Decoder
0109: * @see FileBitstreamReaderAgent
0110: * */
0111: public class HeaderDecoder implements ProgressionType, Markers,
0112: StdEntropyCoderOptions {
0113:
0114: /** The prefix for header decoder options: 'H' */
0115: public final static char OPT_PREFIX = 'H';
0116:
0117: /** The list of parameters that is accepted for quantization. Options
0118: * for quantization start with 'Q'. */
0119: private final static String[][] pinfo = null;
0120:
0121: /** The reference to the HeaderInfo instance holding the information found
0122: * in headers */
0123: private HeaderInfo hi;
0124:
0125: /** Current header information in a string */
0126: private String hdStr = "";
0127:
0128: /** The J2KImageReadParamJava instance of the decoder */
0129: private J2KImageReadParamJava j2krparam;
0130:
0131: /** The number of tiles within the image */
0132: private int nTiles;
0133:
0134: /** The number of tile parts per tile */
0135: public int[] nTileParts;
0136:
0137: /** Used to store which markers have been already read, by using flag
0138: * bits. The different markers are marked with XXX_FOUND flags, such as
0139: * SIZ_FOUND */
0140: private int nfMarkSeg = 0;
0141:
0142: /** Counts number of COC markers found in the header */
0143: private int nCOCMarkSeg = 0;
0144:
0145: /** Counts number of QCC markers found in the header */
0146: private int nQCCMarkSeg = 0;
0147:
0148: /** Counts number of COM markers found in the header */
0149: private int nCOMMarkSeg = 0;
0150:
0151: /** Counts number of RGN markers found in the header */
0152: private int nRGNMarkSeg = 0;
0153:
0154: /** Counts number of PPM markers found in the header */
0155: private int nPPMMarkSeg = 0;
0156:
0157: /** Counts number of PPT markers found in the header */
0158: private int[][] nPPTMarkSeg = null;
0159:
0160: /** Flag bit for SIZ marker segment found */
0161: private static final int SIZ_FOUND = 1;
0162:
0163: /** Flag bit for COD marker segment found */
0164: private static final int COD_FOUND = 1 << 1;
0165:
0166: /** Flag bit for COC marker segment found */
0167: private static final int COC_FOUND = 1 << 2;
0168:
0169: /** Flag bit for QCD marker segment found */
0170: private static final int QCD_FOUND = 1 << 3;
0171:
0172: /** Flag bit for TLM marker segment found */
0173: private static final int TLM_FOUND = 1 << 4;
0174:
0175: /** Flag bit for PLM marker segment found */
0176: private static final int PLM_FOUND = 1 << 5;
0177:
0178: /** Flag bit for SOT marker segment found */
0179: private static final int SOT_FOUND = 1 << 6;
0180:
0181: /** Flag bit for PLT marker segment found */
0182: private static final int PLT_FOUND = 1 << 7;
0183:
0184: /** Flag bit for QCC marker segment found */
0185: private static final int QCC_FOUND = 1 << 8;
0186:
0187: /** Flag bit for RGN marker segment found */
0188: private static final int RGN_FOUND = 1 << 9;
0189:
0190: /** Flag bit for POC marker segment found */
0191: private static final int POC_FOUND = 1 << 10;
0192:
0193: /** Flag bit for COM marker segment found */
0194: private static final int COM_FOUND = 1 << 11;
0195:
0196: /** Flag bit for SOD marker segment found */
0197: public static final int SOD_FOUND = 1 << 13;
0198:
0199: /** Flag bit for SOD marker segment found */
0200: public static final int PPM_FOUND = 1 << 14;
0201:
0202: /** Flag bit for SOD marker segment found */
0203: public static final int PPT_FOUND = 1 << 15;
0204:
0205: /** Flag bit for CRG marker segment found */
0206: public static final int CRG_FOUND = 1 << 16;
0207:
0208: /** The reset mask for new tiles */
0209: private static final int TILE_RESET = ~(PLM_FOUND | SIZ_FOUND | RGN_FOUND);
0210:
0211: /** HashTable used to store marker segment byte buffers */
0212: private Hashtable ht = null;
0213:
0214: /** The number of components in the image */
0215: private int nComp;
0216:
0217: /** The horizontal code-block partition origin */
0218: private int cb0x = -1;
0219:
0220: /** The vertical code-block partition origin */
0221: private int cb0y = -1;
0222:
0223: /** The decoder specifications */
0224: private DecoderSpecs decSpec;
0225:
0226: /** Is the precinct partition used */
0227: boolean precinctPartitionIsUsed;
0228:
0229: /** The offset of the main header in the input stream */
0230: public int mainHeadOff;
0231:
0232: /** Vector containing info as to which tile each tilepart belong */
0233: public Vector tileOfTileParts;
0234:
0235: /** Array containing the Nppm and Ippm fields of the PPM marker segments*/
0236: private byte[][] pPMMarkerData;
0237:
0238: /** Array containing the Ippm fields of the PPT marker segments */
0239: private byte[][][][] tilePartPkdPktHeaders;
0240:
0241: /** The packed packet headers if the PPM or PPT markers are used */
0242: private ByteArrayOutputStream[] pkdPktHeaders;
0243:
0244: /**
0245: * Return the maximum height among all components
0246: *
0247: * @return Maximum component height
0248: * */
0249: public int getMaxCompImgHeight() {
0250: return hi.siz.getMaxCompHeight();
0251: }
0252:
0253: /**
0254: * Return the maximum width among all components
0255: *
0256: * @return Maximum component width
0257: * */
0258: public int getMaxCompImgWidth() {
0259: return hi.siz.getMaxCompWidth();
0260: }
0261:
0262: /**
0263: * Returns the image width in the reference grid.
0264: *
0265: * @return The image width in the reference grid
0266: * */
0267: public final int getImgWidth() {
0268: return hi.siz.xsiz - hi.siz.x0siz;
0269: }
0270:
0271: /**
0272: * Returns the image height in the reference grid.
0273: *
0274: * @return The image height in the reference grid
0275: * */
0276: public final int getImgHeight() {
0277: return hi.siz.ysiz - hi.siz.y0siz;
0278: }
0279:
0280: /**
0281: * Return the horizontal upper-left coordinate of the image in the
0282: * reference grid.
0283: *
0284: * @return The horizontal coordinate of the image origin.
0285: * */
0286: public final int getImgULX() {
0287: return hi.siz.x0siz;
0288: }
0289:
0290: /**
0291: * Return the vertical upper-left coordinate of the image in the reference
0292: * grid.
0293: *
0294: * @return The vertical coordinate of the image origin.
0295: * */
0296: public final int getImgULY() {
0297: return hi.siz.y0siz;
0298: }
0299:
0300: /**
0301: * Returns the nominal width of the tiles in the reference grid.
0302: *
0303: * @return The nominal tile width, in the reference grid.
0304: * */
0305: public final int getNomTileWidth() {
0306: return hi.siz.xtsiz;
0307: }
0308:
0309: /**
0310: * Returns the nominal width of the tiles in the reference grid.
0311: *
0312: * @return The nominal tile width, in the reference grid.
0313: * */
0314: public final int getNomTileHeight() {
0315: return hi.siz.ytsiz;
0316: }
0317:
0318: /**
0319: * Returns the tiling origin, referred to as '(Px,Py)' in the 'ImgData'
0320: * interface.
0321: *
0322: * @param co If not null this object is used to return the information. If
0323: * null a new one is created and returned.
0324: *
0325: * @return The coordinate of the tiling origin, in the canvas system, on
0326: * the reference grid.
0327: *
0328: * @see jj2000.j2k.image.ImgData
0329: * */
0330: public final Point getTilingOrigin(Point co) {
0331: if (co != null) {
0332: co.x = hi.siz.xt0siz;
0333: co.y = hi.siz.yt0siz;
0334: return co;
0335: } else {
0336: return new Point(hi.siz.xt0siz, hi.siz.yt0siz);
0337: }
0338: }
0339:
0340: /**
0341: * Returns true if the original data of the specified component was
0342: * signed. If the data was not signed a level shift has to be applied at
0343: * the end of the decompression chain.
0344: *
0345: * @param c The index of the component
0346: *
0347: * @return True if the original image component was signed.
0348: * */
0349: public final boolean isOriginalSigned(int c) {
0350: return hi.siz.isOrigSigned(c);
0351: }
0352:
0353: /**
0354: * Returns the original bitdepth of the specified component.
0355: *
0356: * @param c The index of the component
0357: *
0358: * @return The bitdepth of the component
0359: * */
0360: public final int getOriginalBitDepth(int c) {
0361: return hi.siz.getOrigBitDepth(c);
0362: }
0363:
0364: /**
0365: * Returns the number of components in the image.
0366: *
0367: * @return The number of components in the image.
0368: * */
0369: public final int getNumComps() {
0370: return nComp;
0371: }
0372:
0373: /**
0374: * Returns the component sub-sampling factor, with respect to the
0375: * reference grid, along the horizontal direction for the specified
0376: * component.
0377: *
0378: * @param c The index of the component
0379: *
0380: * @return The component sub-sampling factor X-wise.
0381: * */
0382: public final int getCompSubsX(int c) {
0383: return hi.siz.xrsiz[c];
0384: }
0385:
0386: /**
0387: * Returns the component sub-sampling factor, with respect to the
0388: * reference grid, along the vertical direction for the specified
0389: * component.
0390: *
0391: * @param c The index of the component
0392: *
0393: * @return The component sub-sampling factor Y-wise.
0394: * */
0395: public final int getCompSubsY(int c) {
0396: return hi.siz.yrsiz[c];
0397: }
0398:
0399: /**
0400: * Returns the dequantizer parameters. Dequantizer parameters normally are
0401: * the quantization step sizes, see DequantizerParams.
0402: *
0403: * @param src The source of data for the dequantizer.
0404: *
0405: * @param rb The number of range bits for each component. Must be
0406: * the number of range bits of the mixed components.
0407: *
0408: * @param decSpec2 The DecoderSpecs instance after any image manipulation.
0409: *
0410: * @return The dequantizer
0411: * */
0412: public final Dequantizer createDequantizer(CBlkQuantDataSrcDec src,
0413: int rb[], DecoderSpecs decSpec2) {
0414: return new StdDequantizer(src, rb, decSpec2);
0415: }
0416:
0417: /**
0418: * Returns the horizontal code-block partition origin.Allowable values are
0419: * 0 and 1, nothing else.
0420: * */
0421: public final int getCbULX() {
0422: return cb0x;
0423: }
0424:
0425: /**
0426: * Returns the vertical code-block partition origin. Allowable values are
0427: * 0 and 1, nothing else.
0428: * */
0429: public final int getCbULY() {
0430: return cb0y;
0431: }
0432:
0433: /**
0434: * Returns the precinct partition width for the specified tile-component
0435: * and resolution level.
0436: *
0437: * @param c the component index
0438: *
0439: * @param t the tile index
0440: *
0441: * @param rl the resolution level
0442: *
0443: * @return The precinct partition width for the specified tile-component
0444: * and resolution level
0445: * */
0446: public final int getPPX(int t, int c, int rl) {
0447: return decSpec.pss.getPPX(t, c, rl);
0448: }
0449:
0450: /**
0451: * Returns the precinct partition height for the specified component, tile
0452: * and resolution level.
0453: *
0454: * @param c the component
0455: *
0456: * @param t the tile index
0457: *
0458: * @param rl the resolution level
0459: *
0460: * @return The precinct partition height for the specified component,
0461: * tile and resolution level
0462: * */
0463: public final int getPPY(int t, int c, int rl) {
0464: return decSpec.pss.getPPY(t, c, rl);
0465: }
0466:
0467: /**
0468: * Returns the boolean used to know if the precinct partition is used
0469: **/
0470: public final boolean precinctPartitionUsed() {
0471: return precinctPartitionIsUsed;
0472: }
0473:
0474: /**
0475: * Reads a wavelet filter from the codestream and returns the filter
0476: * object that implements it.
0477: *
0478: * @param ehs The encoded header stream from where to read the info
0479: *
0480: * @param filtIdx Int array of one element to return the type of the
0481: * wavelet filter.
0482: * */
0483: private SynWTFilter readFilter(DataInputStream ehs, int[] filtIdx)
0484: throws IOException {
0485: int kid; // the filter id
0486:
0487: kid = filtIdx[0] = ehs.readUnsignedByte();
0488: if (kid >= (1 << 7)) {
0489: throw new NotImplementedError(
0490: "Custom filters not supported");
0491: }
0492: // Return filter based on ID
0493: switch (kid) {
0494: case FilterTypes.W9X7:
0495: return new SynWTFilterFloatLift9x7();
0496: case FilterTypes.W5X3:
0497: return new SynWTFilterIntLift5x3();
0498: default:
0499: throw new CorruptedCodestreamException(
0500: "Specified wavelet filter " + "not"
0501: + " JPEG 2000 part I " + "compliant");
0502: }
0503: }
0504:
0505: /**
0506: * Checks that the marker segment length is correct.
0507: *
0508: * @param ehs The encoded header stream
0509: *
0510: * @param str The string identifying the marker, such as "SIZ marker"
0511: *
0512: * @exception IOException If an I/O error occurs
0513: * */
0514: public void checkMarkerLength(DataInputStream ehs, String str)
0515: throws IOException {
0516: if (ehs.available() != 0) {
0517: FacilityManager.getMsgLogger().printmsg(MsgLogger.WARNING,
0518: str + " length was short, attempting to resync.");
0519: }
0520: }
0521:
0522: /**
0523: * Reads the SIZ marker segment and realigns the codestream at the point
0524: * where the next marker segment should be found.
0525: *
0526: * <p>SIZ is a fixed information marker segment containing informations
0527: * about image and tile sizes. It is required in the main header
0528: * immediately after SOC.</p>
0529: *
0530: * @param ehs The encoded header stream
0531: *
0532: * @exception IOException If an I/O error occurs while reading from the
0533: * encoded header stream
0534: * */
0535: private void readSIZ(DataInputStream ehs) throws IOException {
0536: HeaderInfo.SIZ ms = hi.getNewSIZ();
0537: hi.siz = ms;
0538:
0539: // Read the length of SIZ marker segment (Lsiz)
0540: ms.lsiz = ehs.readUnsignedShort();
0541:
0542: // Read the capability of the codestream (Rsiz)
0543: ms.rsiz = ehs.readUnsignedShort();
0544: if (ms.rsiz > 2) {
0545: throw new Error(
0546: "Codestream capabiities not JPEG 2000 - Part I"
0547: + " compliant");
0548: }
0549:
0550: // Read image size
0551: ms.xsiz = ehs.readInt();
0552: ms.ysiz = ehs.readInt();
0553: if (ms.xsiz <= 0 || ms.ysiz <= 0) {
0554: throw new IOException(
0555: "JJ2000 does not support images whose "
0556: + "width and/or height not in the "
0557: + "range: 1 -- (2^31)-1");
0558: }
0559:
0560: // Read image offset
0561: ms.x0siz = ehs.readInt();
0562: ms.y0siz = ehs.readInt();
0563: if (ms.x0siz < 0 || ms.y0siz < 0) {
0564: throw new IOException(
0565: "JJ2000 does not support images offset "
0566: + "not in the range: 0 -- (2^31)-1");
0567: }
0568:
0569: // Read size of tile
0570: ms.xtsiz = ehs.readInt();
0571: ms.ytsiz = ehs.readInt();
0572: if (ms.xtsiz <= 0 || ms.ytsiz <= 0) {
0573: throw new IOException(
0574: "JJ2000 does not support tiles whose "
0575: + "width and/or height are not in "
0576: + "the range: 1 -- (2^31)-1");
0577: }
0578:
0579: // Read upper-left tile offset
0580: ms.xt0siz = ehs.readInt();
0581: ms.yt0siz = ehs.readInt();
0582: if (ms.xt0siz < 0 || ms.yt0siz < 0) {
0583: throw new IOException(
0584: "JJ2000 does not support tiles whose "
0585: + "offset is not in "
0586: + "the range: 0 -- (2^31)-1");
0587: }
0588:
0589: // Read number of components and initialize related arrays
0590: nComp = ms.csiz = ehs.readUnsignedShort();
0591: if (nComp < 1 || nComp > 16384) {
0592: throw new IllegalArgumentException(
0593: "Number of component out of " + "range 1--16384: "
0594: + nComp);
0595: }
0596:
0597: ms.ssiz = new int[nComp];
0598: ms.xrsiz = new int[nComp];
0599: ms.yrsiz = new int[nComp];
0600:
0601: // Read bit-depth and down-sampling factors of each component
0602: for (int i = 0; i < nComp; i++) {
0603: ms.ssiz[i] = ehs.readUnsignedByte();
0604: ms.xrsiz[i] = ehs.readUnsignedByte();
0605: ms.yrsiz[i] = ehs.readUnsignedByte();
0606: }
0607:
0608: // Check marker length
0609: checkMarkerLength(ehs, "SIZ marker");
0610:
0611: // Create needed ModuleSpec
0612: nTiles = ms.getNumTiles();
0613:
0614: // Finish initialization of decSpec
0615: decSpec = new DecoderSpecs(nTiles, nComp);
0616: }
0617:
0618: /**
0619: * Reads a CRG marker segment and checks its length. CRG is an
0620: * informational marker segment that allows specific registration of
0621: * components with respect to each other.
0622: *
0623: * @param ehs The encoded header stream
0624: * */
0625: private void readCRG(DataInputStream ehs) throws IOException {
0626: HeaderInfo.CRG ms = hi.getNewCRG();
0627: hi.crg = ms;
0628:
0629: ms.lcrg = ehs.readUnsignedShort();
0630: ms.xcrg = new int[nComp];
0631: ms.ycrg = new int[nComp];
0632:
0633: FacilityManager
0634: .getMsgLogger()
0635: .printmsg(
0636: MsgLogger.WARNING,
0637: "Information in CRG marker segment "
0638: + "not taken into account. This may affect the display "
0639: + "of the decoded image.");
0640: for (int c = 0; c < nComp; c++) {
0641: ms.xcrg[c] = ehs.readUnsignedShort();
0642: ms.ycrg[c] = ehs.readUnsignedShort();
0643: }
0644:
0645: // Check marker length
0646: checkMarkerLength(ehs, "CRG marker");
0647: }
0648:
0649: /**
0650: * Reads a COM marker segments and realigns the bit stream at the point
0651: * where the next marker segment should be found. COM is an informational
0652: * marker segment that allows to include unstructured data in the main and
0653: * tile-part headers.
0654: *
0655: * @param ehs The encoded header stream
0656: *
0657: * @param mainh Flag indicating whether or not this marker segment is read
0658: * from the main header.
0659: *
0660: * @param tileIdx The index of the current tile
0661: *
0662: * @param comIdx Occurence of this COM marker in eith main or tile-part
0663: * header
0664: *
0665: * @exception IOException If an I/O error occurs while reading from the
0666: * encoded header stream
0667: * */
0668: private void readCOM(DataInputStream ehs, boolean mainh,
0669: int tileIdx, int comIdx) throws IOException {
0670: HeaderInfo.COM ms = hi.getNewCOM();
0671:
0672: // Read length of COM field
0673: ms.lcom = ehs.readUnsignedShort();
0674:
0675: // Read the registration value of the COM marker segment
0676: ms.rcom = ehs.readUnsignedShort();
0677: switch (ms.rcom) {
0678: case RCOM_GEN_USE:
0679: ms.ccom = new byte[ms.lcom - 4];
0680: for (int i = 0; i < ms.lcom - 4; i++) {
0681: ms.ccom[i] = ehs.readByte();
0682: }
0683: break;
0684: default:
0685: // --- Unknown or unsupported markers ---
0686: // (skip them and see if we can get way with it)
0687: FacilityManager
0688: .getMsgLogger()
0689: .printmsg(
0690: MsgLogger.WARNING,
0691: "COM marker registered as 0x"
0692: + Integer.toHexString(ms.rcom)
0693: + " unknown, ignoring (this might crash the "
0694: + "decoder or decode a quality degraded or even "
0695: + "useless image)");
0696: ehs.skipBytes(ms.lcom - 4); //Ignore this field for the moment
0697: break;
0698: }
0699:
0700: if (mainh) {
0701: hi.com.put("main_" + comIdx, ms);
0702: } else {
0703: hi.com.put("t" + tileIdx + "_" + comIdx, ms);
0704: }
0705:
0706: // Check marker length
0707: checkMarkerLength(ehs, "COM marker");
0708: }
0709:
0710: /**
0711: * Reads a QCD marker segment and realigns the codestream at the point
0712: * where the next marker should be found. QCD is a functional marker
0713: * segment that describes the quantization default.
0714: *
0715: * @param ehs The encoded stream.
0716: *
0717: * @param mainh Flag indicating whether or not this marker segment is read
0718: * from the main header.
0719: *
0720: * @param tileIdx The index of the current tile
0721: *
0722: * @param tpIdx Tile-part index
0723: *
0724: * @exception IOException If an I/O error occurs while reading from the
0725: * encoded header stream.
0726: * */
0727: private void readQCD(DataInputStream ehs, boolean mainh,
0728: int tileIdx, int tpIdx) throws IOException {
0729: StdDequantizerParams qParms;
0730: int guardBits;
0731: int[][] exp;
0732: float[][] nStep = null;
0733: HeaderInfo.QCD ms = hi.getNewQCD();
0734:
0735: // Lqcd (length of QCD field)
0736: ms.lqcd = ehs.readUnsignedShort();
0737:
0738: // Sqcd (quantization style)
0739: ms.sqcd = ehs.readUnsignedByte();
0740:
0741: guardBits = ms.getNumGuardBits();
0742: int qType = ms.getQuantType();
0743:
0744: if (mainh) {
0745: hi.qcd.put("main", ms);
0746: // If the main header is being read set default value of
0747: // dequantization spec
0748: switch (qType) {
0749: case SQCX_NO_QUANTIZATION:
0750: decSpec.qts.setDefault("reversible");
0751: break;
0752: case SQCX_SCALAR_DERIVED:
0753: decSpec.qts.setDefault("derived");
0754: break;
0755: case SQCX_SCALAR_EXPOUNDED:
0756: decSpec.qts.setDefault("expounded");
0757: break;
0758: default:
0759: throw new CorruptedCodestreamException("Unknown or "
0760: + "unsupported " + "quantization style "
0761: + "in Sqcd field, QCD " + "marker main header");
0762: }
0763: } else {
0764: hi.qcd.put("t" + tileIdx, ms);
0765: // If the tile header is being read set default value of
0766: // dequantization spec for tile
0767: switch (qType) {
0768: case SQCX_NO_QUANTIZATION:
0769: decSpec.qts.setTileDef(tileIdx, "reversible");
0770: break;
0771: case SQCX_SCALAR_DERIVED:
0772: decSpec.qts.setTileDef(tileIdx, "derived");
0773: break;
0774: case SQCX_SCALAR_EXPOUNDED:
0775: decSpec.qts.setTileDef(tileIdx, "expounded");
0776: break;
0777: default:
0778: throw new CorruptedCodestreamException("Unknown or "
0779: + "unsupported " + "quantization style "
0780: + "in Sqcd field, QCD " + "marker, tile header");
0781: }
0782: }
0783:
0784: qParms = new StdDequantizerParams();
0785:
0786: if (qType == SQCX_NO_QUANTIZATION) {
0787: int maxrl = (mainh ? ((Integer) decSpec.dls.getDefault())
0788: .intValue() : ((Integer) decSpec.dls
0789: .getTileDef(tileIdx)).intValue());
0790: int i, j, rl;
0791: int minb, maxb, hpd;
0792: int tmp;
0793:
0794: exp = qParms.exp = new int[maxrl + 1][];
0795: ms.spqcd = new int[maxrl + 1][4];
0796:
0797: for (rl = 0; rl <= maxrl; rl++) { // Loop on resolution levels
0798: // Find the number of subbands in the resolution level
0799: if (rl == 0) { // Only the LL subband
0800: minb = 0;
0801: maxb = 1;
0802: } else {
0803: // Dyadic decomposition
0804: hpd = 1;
0805:
0806: // Adapt hpd to resolution level
0807: if (hpd > maxrl - rl) {
0808: hpd -= maxrl - rl;
0809: } else {
0810: hpd = 1;
0811: }
0812: // Determine max and min subband index
0813: minb = 1 << ((hpd - 1) << 1); // minb = 4^(hpd-1)
0814: maxb = 1 << (hpd << 1); // maxb = 4^hpd
0815: }
0816: // Allocate array for subbands in resolution level
0817: exp[rl] = new int[maxb];
0818:
0819: for (j = minb; j < maxb; j++) {
0820: tmp = ms.spqcd[rl][j] = ehs.readUnsignedByte();
0821: exp[rl][j] = (tmp >> SQCX_EXP_SHIFT)
0822: & SQCX_EXP_MASK;
0823: }
0824: }// end for rl
0825: } else {
0826: int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0
0827: : (mainh ? ((Integer) decSpec.dls.getDefault())
0828: .intValue() : ((Integer) decSpec.dls
0829: .getTileDef(tileIdx)).intValue());
0830: int i, j, rl;
0831: int minb, maxb, hpd;
0832: int tmp;
0833:
0834: exp = qParms.exp = new int[maxrl + 1][];
0835: nStep = qParms.nStep = new float[maxrl + 1][];
0836: ms.spqcd = new int[maxrl + 1][4];
0837:
0838: for (rl = 0; rl <= maxrl; rl++) { // Loop on resolution levels
0839: // Find the number of subbands in the resolution level
0840: if (rl == 0) { // Only the LL subband
0841: minb = 0;
0842: maxb = 1;
0843: } else {
0844: // Dyadic decomposition
0845: hpd = 1;
0846:
0847: // Adapt hpd to resolution level
0848: if (hpd > maxrl - rl) {
0849: hpd -= maxrl - rl;
0850: } else {
0851: hpd = 1;
0852: }
0853: // Determine max and min subband index
0854: minb = 1 << ((hpd - 1) << 1); // minb = 4^(hpd-1)
0855: maxb = 1 << (hpd << 1); // maxb = 4^hpd
0856: }
0857: // Allocate array for subbands in resolution level
0858: exp[rl] = new int[maxb];
0859: nStep[rl] = new float[maxb];
0860:
0861: for (j = minb; j < maxb; j++) {
0862: tmp = ms.spqcd[rl][j] = ehs.readUnsignedShort();
0863: exp[rl][j] = (tmp >> 11) & 0x1f;
0864: // NOTE: the formula below does not support more than 5
0865: // bits for the exponent, otherwise (-1<<exp) might
0866: // overflow (the - is used to be able to represent 2**31)
0867: nStep[rl][j] = (-1f - ((float) (tmp & 0x07ff))
0868: / (1 << 11))
0869: / (-1 << exp[rl][j]);
0870: }
0871: }// end for rl
0872: } // end if (qType != SQCX_NO_QUANTIZATION)
0873:
0874: // Fill qsss, gbs
0875: if (mainh) {
0876: decSpec.qsss.setDefault(qParms);
0877: decSpec.gbs.setDefault(new Integer(guardBits));
0878: } else {
0879: decSpec.qsss.setTileDef(tileIdx, qParms);
0880: decSpec.gbs.setTileDef(tileIdx, new Integer(guardBits));
0881: }
0882:
0883: // Check marker length
0884: checkMarkerLength(ehs, "QCD marker");
0885: }
0886:
0887: /**
0888: * Reads a QCC marker segment and realigns the codestream at the point
0889: * where the next marker should be found. QCC is a functional marker
0890: * segment that describes the quantization of one component.
0891: *
0892: * @param ehs The encoded stream.
0893: *
0894: * @param mainh Flag indicating whether or not this marker segment is read
0895: * from the main header.
0896: *
0897: * @param tileIdx The index of the current tile
0898: *
0899: * @param tpIdx Tile-part index
0900: *
0901: * @exception IOException If an I/O error occurs while reading from the
0902: * encoded header stream.
0903: * */
0904: private void readQCC(DataInputStream ehs, boolean mainh,
0905: int tileIdx, int tpIdx) throws IOException {
0906: int cComp; // current component
0907: int tmp;
0908: StdDequantizerParams qParms;
0909: int[][] expC;
0910: float[][] nStepC = null;
0911: HeaderInfo.QCC ms = hi.getNewQCC();
0912:
0913: // Lqcc (length of QCC field)
0914: ms.lqcc = ehs.readUnsignedShort();
0915:
0916: // Cqcc
0917: if (nComp < 257) {
0918: cComp = ms.cqcc = ehs.readUnsignedByte();
0919: } else {
0920: cComp = ms.cqcc = ehs.readUnsignedShort();
0921: }
0922: if (cComp >= nComp) {
0923: throw new CorruptedCodestreamException("Invalid component "
0924: + "index in QCC marker");
0925: }
0926:
0927: // Sqcc (quantization style)
0928: ms.sqcc = ehs.readUnsignedByte();
0929: int guardBits = ms.getNumGuardBits();
0930: int qType = ms.getQuantType();
0931:
0932: if (mainh) {
0933: hi.qcc.put("main_c" + cComp, ms);
0934: // If main header is being read, set default for component in all
0935: // tiles
0936: switch (qType) {
0937: case SQCX_NO_QUANTIZATION:
0938: decSpec.qts.setCompDef(cComp, "reversible");
0939: break;
0940: case SQCX_SCALAR_DERIVED:
0941: decSpec.qts.setCompDef(cComp, "derived");
0942: break;
0943: case SQCX_SCALAR_EXPOUNDED:
0944: decSpec.qts.setCompDef(cComp, "expounded");
0945: break;
0946: default:
0947: throw new CorruptedCodestreamException("Unknown or "
0948: + "unsupported " + "quantization style "
0949: + "in Sqcd field, QCD " + "marker, main header");
0950: }
0951: } else {
0952: hi.qcc.put("t" + tileIdx + "_c" + cComp, ms);
0953: // If tile header is being read, set value for component in
0954: // this tiles
0955: switch (qType) {
0956: case SQCX_NO_QUANTIZATION:
0957: decSpec.qts
0958: .setTileCompVal(tileIdx, cComp, "reversible");
0959: break;
0960: case SQCX_SCALAR_DERIVED:
0961: decSpec.qts.setTileCompVal(tileIdx, cComp, "derived");
0962: break;
0963: case SQCX_SCALAR_EXPOUNDED:
0964: decSpec.qts.setTileCompVal(tileIdx, cComp, "expounded");
0965: break;
0966: default:
0967: throw new CorruptedCodestreamException("Unknown or "
0968: + "unsupported " + "quantization style "
0969: + "in Sqcd field, QCD " + "marker, main header");
0970: }
0971: }
0972:
0973: // Decode all dequantizer params
0974: qParms = new StdDequantizerParams();
0975:
0976: if (qType == SQCX_NO_QUANTIZATION) {
0977: int maxrl = (mainh ? ((Integer) decSpec.dls
0978: .getCompDef(cComp)).intValue()
0979: : ((Integer) decSpec.dls.getTileCompVal(tileIdx,
0980: cComp)).intValue());
0981: int i, j, rl;
0982: int minb, maxb, hpd;
0983:
0984: expC = qParms.exp = new int[maxrl + 1][];
0985: ms.spqcc = new int[maxrl + 1][4];
0986:
0987: for (rl = 0; rl <= maxrl; rl++) { // Loop on resolution levels
0988: // Find the number of subbands in the resolution level
0989: if (rl == 0) { // Only the LL subband
0990: minb = 0;
0991: maxb = 1;
0992: } else {
0993: // Dyadic decomposition
0994: hpd = 1;
0995:
0996: // Adapt hpd to resolution level
0997: if (hpd > maxrl - rl) {
0998: hpd -= maxrl - rl;
0999: } else {
1000: hpd = 1;
1001: }
1002: // Determine max and min subband index
1003: minb = 1 << ((hpd - 1) << 1); // minb = 4^(hpd-1)
1004: maxb = 1 << (hpd << 1); // maxb = 4^hpd
1005: }
1006: // Allocate array for subbands in resolution level
1007: expC[rl] = new int[maxb];
1008:
1009: for (j = minb; j < maxb; j++) {
1010: tmp = ms.spqcc[rl][j] = ehs.readUnsignedByte();
1011: expC[rl][j] = (tmp >> SQCX_EXP_SHIFT)
1012: & SQCX_EXP_MASK;
1013: }
1014: }// end for rl
1015: } else {
1016: int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0
1017: : (mainh ? ((Integer) decSpec.dls.getCompDef(cComp))
1018: .intValue()
1019: : ((Integer) decSpec.dls.getTileCompVal(
1020: tileIdx, cComp)).intValue());
1021: int i, j, rl;
1022: int minb, maxb, hpd;
1023:
1024: nStepC = qParms.nStep = new float[maxrl + 1][];
1025: expC = qParms.exp = new int[maxrl + 1][];
1026: ms.spqcc = new int[maxrl + 1][4];
1027:
1028: for (rl = 0; rl <= maxrl; rl++) { // Loop on resolution levels
1029: // Find the number of subbands in the resolution level
1030: if (rl == 0) { // Only the LL subband
1031: minb = 0;
1032: maxb = 1;
1033: } else {
1034: // Dyadic decomposition
1035: hpd = 1;
1036:
1037: // Adapt hpd to resolution level
1038: if (hpd > maxrl - rl) {
1039: hpd -= maxrl - rl;
1040: } else {
1041: hpd = 1;
1042: }
1043: // Determine max and min subband index
1044: minb = 1 << ((hpd - 1) << 1); // minb = 4^(hpd-1)
1045: maxb = 1 << (hpd << 1); // maxb = 4^hpd
1046: }
1047: // Allocate array for subbands in resolution level
1048: expC[rl] = new int[maxb];
1049: nStepC[rl] = new float[maxb];
1050:
1051: for (j = minb; j < maxb; j++) {
1052: tmp = ms.spqcc[rl][j] = ehs.readUnsignedShort();
1053: expC[rl][j] = (tmp >> 11) & 0x1f;
1054: // NOTE: the formula below does not support more than 5
1055: // bits for the exponent, otherwise (-1<<exp) might
1056: // overflow (the - is used to be able to represent 2**31)
1057: nStepC[rl][j] = (-1f - ((float) (tmp & 0x07ff))
1058: / (1 << 11))
1059: / (-1 << expC[rl][j]);
1060: }
1061: }// end for rl
1062: } // end if (qType != SQCX_NO_QUANTIZATION)
1063:
1064: // Fill qsss, gbs
1065: if (mainh) {
1066: decSpec.qsss.setCompDef(cComp, qParms);
1067: decSpec.gbs.setCompDef(cComp, new Integer(guardBits));
1068: } else {
1069: decSpec.qsss.setTileCompVal(tileIdx, cComp, qParms);
1070: decSpec.gbs.setTileCompVal(tileIdx, cComp, new Integer(
1071: guardBits));
1072: }
1073:
1074: // Check marker length
1075: checkMarkerLength(ehs, "QCC marker");
1076: }
1077:
1078: /**
1079: * Reads a COD marker segment and realigns the codestream where the next
1080: * marker should be found.
1081: *
1082: * @param ehs The encoder header stream.
1083: *
1084: * @param mainh Flag indicating whether or not this marker segment is read
1085: * from the main header.
1086: *
1087: * @param tileIdx The index of the current tile
1088: *
1089: * @param tpIdx Tile-part index
1090: *
1091: * @exception IOException If an I/O error occurs while reading from the
1092: * encoder header stream
1093: * */
1094: private void readCOD(DataInputStream ehs, boolean mainh,
1095: int tileIdx, int tpIdx) throws IOException {
1096: int cstyle; // The block style
1097: SynWTFilter hfilters[], vfilters[];
1098: int l;
1099: Integer cblk[];
1100: String errMsg;
1101: boolean sopUsed = false;
1102: boolean ephUsed = false;
1103: HeaderInfo.COD ms = hi.getNewCOD();
1104:
1105: // Lcod (marker length)
1106: ms.lcod = ehs.readUnsignedShort();
1107:
1108: // Scod (block style)
1109: // We only support wavelet transformed data
1110: cstyle = ms.scod = ehs.readUnsignedByte();
1111:
1112: if ((cstyle & SCOX_PRECINCT_PARTITION) != 0) {
1113: precinctPartitionIsUsed = true;
1114: // Remove flag
1115: cstyle &= ~(SCOX_PRECINCT_PARTITION);
1116: } else {
1117: precinctPartitionIsUsed = false;
1118: }
1119:
1120: // SOP markers
1121: if (mainh) {
1122: hi.cod.put("main", ms);
1123:
1124: if ((cstyle & SCOX_USE_SOP) != 0) {
1125: // SOP markers are used
1126: decSpec.sops.setDefault(new Boolean("true"));
1127: sopUsed = true;
1128: // Remove flag
1129: cstyle &= ~(SCOX_USE_SOP);
1130: } else {
1131: // SOP markers are not used
1132: decSpec.sops.setDefault(new Boolean("false"));
1133: }
1134: } else {
1135: hi.cod.put("t" + tileIdx, ms);
1136:
1137: if ((cstyle & SCOX_USE_SOP) != 0) {
1138: // SOP markers are used
1139: decSpec.sops.setTileDef(tileIdx, new Boolean("true"));
1140: sopUsed = true;
1141: // Remove flag
1142: cstyle &= ~(SCOX_USE_SOP);
1143: } else {
1144: // SOP markers are not used
1145: decSpec.sops.setTileDef(tileIdx, new Boolean("false"));
1146: }
1147: }
1148:
1149: // EPH markers
1150: if (mainh) {
1151: if ((cstyle & SCOX_USE_EPH) != 0) {
1152: // EPH markers are used
1153: decSpec.ephs.setDefault(new Boolean("true"));
1154: ephUsed = true;
1155: // Remove flag
1156: cstyle &= ~(SCOX_USE_EPH);
1157: } else {
1158: // EPH markers are not used
1159: decSpec.ephs.setDefault(new Boolean("false"));
1160: }
1161: } else {
1162: if ((cstyle & SCOX_USE_EPH) != 0) {
1163: // EPH markers are used
1164: decSpec.ephs.setTileDef(tileIdx, new Boolean("true"));
1165: ephUsed = true;
1166: // Remove flag
1167: cstyle &= ~(SCOX_USE_EPH);
1168: } else {
1169: // EPH markers are not used
1170: decSpec.ephs.setTileDef(tileIdx, new Boolean("false"));
1171: }
1172: }
1173:
1174: // Code-block partition origin
1175: if ((cstyle & (SCOX_HOR_CB_PART | SCOX_VER_CB_PART)) != 0) {
1176: FacilityManager
1177: .getMsgLogger()
1178: .printmsg(
1179: MsgLogger.WARNING,
1180: "Code-block partition origin "
1181: + "different from (0,0). This is defined in JPEG 2000"
1182: + " part 2 and may not be supported by all JPEG "
1183: + "2000 decoders.");
1184: }
1185: if ((cstyle & SCOX_HOR_CB_PART) != 0) {
1186: if (cb0x != -1 && cb0x == 0) {
1187: throw new IllegalArgumentException(
1188: "Code-block partition "
1189: + "origin redefined in new"
1190: + " COD marker segment. Not"
1191: + " supported by JJ2000");
1192: }
1193: cb0x = 1;
1194: cstyle &= ~(SCOX_HOR_CB_PART);
1195: } else {
1196: if (cb0x != -1 && cb0x == 1) {
1197: throw new IllegalArgumentException(
1198: "Code-block partition "
1199: + "origin redefined in new"
1200: + " COD marker segment. Not"
1201: + " supported by JJ2000");
1202: }
1203: cb0x = 0;
1204: }
1205: if ((cstyle & SCOX_VER_CB_PART) != 0) {
1206: if (cb0y != -1 && cb0y == 0) {
1207: throw new IllegalArgumentException(
1208: "Code-block partition "
1209: + "origin redefined in new"
1210: + " COD marker segment. Not"
1211: + " supported by JJ2000");
1212: }
1213: cb0y = 1;
1214: cstyle &= ~(SCOX_VER_CB_PART);
1215: } else {
1216: if (cb0y != -1 && cb0y == 1) {
1217: throw new IllegalArgumentException(
1218: "Code-block partition "
1219: + "origin redefined in new"
1220: + " COD marker segment. Not"
1221: + " supported by JJ2000");
1222: }
1223: cb0y = 0;
1224: }
1225:
1226: // SGcod
1227: // Read the progressive order
1228: ms.sgcod_po = ehs.readUnsignedByte();
1229:
1230: // Read the number of layers
1231: ms.sgcod_nl = ehs.readUnsignedShort();
1232: if (ms.sgcod_nl <= 0 || ms.sgcod_nl > 65535) {
1233: throw new CorruptedCodestreamException(
1234: "Number of layers out of " + "range: 1--65535");
1235: }
1236:
1237: // Multiple component transform
1238: ms.sgcod_mct = ehs.readUnsignedByte();
1239:
1240: // SPcod
1241: // decomposition levels
1242: int mrl = ms.spcod_ndl = ehs.readUnsignedByte();
1243: if (mrl > 32) {
1244: throw new CorruptedCodestreamException(
1245: "Number of decomposition "
1246: + "levels out of range: " + "0--32");
1247: }
1248:
1249: // Read the code-blocks dimensions
1250: cblk = new Integer[2];
1251: ms.spcod_cw = ehs.readUnsignedByte();
1252: cblk[0] = new Integer(1 << (ms.spcod_cw + 2));
1253: if (cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM
1254: || cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM) {
1255: errMsg = "Non-valid code-block width in SPcod field, "
1256: + "COD marker";
1257: throw new CorruptedCodestreamException(errMsg);
1258: }
1259: ms.spcod_ch = ehs.readUnsignedByte();
1260: cblk[1] = new Integer(1 << (ms.spcod_ch + 2));
1261: if (cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM
1262: || cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM) {
1263: errMsg = "Non-valid code-block height in SPcod field, "
1264: + "COD marker";
1265: throw new CorruptedCodestreamException(errMsg);
1266: }
1267: if ((cblk[0].intValue() * cblk[1].intValue()) > StdEntropyCoderOptions.MAX_CB_AREA) {
1268: errMsg = "Non-valid code-block area in SPcod field, "
1269: + "COD marker";
1270: throw new CorruptedCodestreamException(errMsg);
1271: }
1272: if (mainh) {
1273: decSpec.cblks.setDefault(cblk);
1274: } else {
1275: decSpec.cblks.setTileDef(tileIdx, cblk);
1276: }
1277:
1278: // Style of the code-block coding passes
1279: int ecOptions = ms.spcod_cs = ehs.readUnsignedByte();
1280: if ((ecOptions & ~(OPT_BYPASS | OPT_RESET_MQ | OPT_TERM_PASS
1281: | OPT_VERT_STR_CAUSAL | OPT_PRED_TERM | OPT_SEG_SYMBOLS)) != 0) {
1282: throw new CorruptedCodestreamException(
1283: "Unknown \"code-block "
1284: + "style\" in SPcod field, "
1285: + "COD marker: 0x"
1286: + Integer.toHexString(ecOptions));
1287: }
1288:
1289: // Read wavelet filter for tile or image
1290: hfilters = new SynWTFilter[1];
1291: vfilters = new SynWTFilter[1];
1292: hfilters[0] = readFilter(ehs, ms.spcod_t);
1293: vfilters[0] = hfilters[0];
1294:
1295: // Fill the filter spec
1296: // If this is the main header, set the default value, if it is the
1297: // tile header, set default for this tile
1298: SynWTFilter[][] hvfilters = new SynWTFilter[2][];
1299: hvfilters[0] = hfilters;
1300: hvfilters[1] = vfilters;
1301:
1302: // Get precinct partition sizes
1303: Vector v[] = new Vector[2];
1304: v[0] = new Vector();
1305: v[1] = new Vector();
1306: int val = PRECINCT_PARTITION_DEF_SIZE;
1307: if (!precinctPartitionIsUsed) {
1308: Integer w, h;
1309: w = new Integer(1 << (val & 0x000F));
1310: v[0].addElement(w);
1311: h = new Integer(1 << (((val & 0x00F0) >> 4)));
1312: v[1].addElement(h);
1313: } else {
1314: ms.spcod_ps = new int[mrl + 1];
1315: for (int rl = mrl; rl >= 0; rl--) {
1316: Integer w, h;
1317: val = ms.spcod_ps[mrl - rl] = ehs.readUnsignedByte();
1318: w = new Integer(1 << (val & 0x000F));
1319: v[0].insertElementAt(w, 0);
1320: h = new Integer(1 << (((val & 0x00F0) >> 4)));
1321: v[1].insertElementAt(h, 0);
1322: }
1323: }
1324: if (mainh) {
1325: decSpec.pss.setDefault(v);
1326: } else {
1327: decSpec.pss.setTileDef(tileIdx, v);
1328: }
1329: precinctPartitionIsUsed = true;
1330:
1331: // Check marker length
1332: checkMarkerLength(ehs, "COD marker");
1333:
1334: // Store specifications in decSpec
1335: if (mainh) {
1336: decSpec.wfs.setDefault(hvfilters);
1337: decSpec.dls.setDefault(new Integer(mrl));
1338: decSpec.ecopts.setDefault(new Integer(ecOptions));
1339: decSpec.cts.setDefault(new Integer(ms.sgcod_mct));
1340: decSpec.nls.setDefault(new Integer(ms.sgcod_nl));
1341: decSpec.pos.setDefault(new Integer(ms.sgcod_po));
1342: } else {
1343: decSpec.wfs.setTileDef(tileIdx, hvfilters);
1344: decSpec.dls.setTileDef(tileIdx, new Integer(mrl));
1345: decSpec.ecopts.setTileDef(tileIdx, new Integer(ecOptions));
1346: decSpec.cts.setTileDef(tileIdx, new Integer(ms.sgcod_mct));
1347: decSpec.nls.setTileDef(tileIdx, new Integer(ms.sgcod_nl));
1348: decSpec.pos.setTileDef(tileIdx, new Integer(ms.sgcod_po));
1349: }
1350: }
1351:
1352: /**
1353: * Reads the COC marker segment and realigns the codestream where the next
1354: * marker should be found.
1355: *
1356: * @param ehs The encoder header stream.
1357: *
1358: * @param mainh Flag indicating whether or not this marker segment is read
1359: * from the main header.
1360: *
1361: * @param tileIdx The index of the current tile
1362: *
1363: * @param tpIdx Tile-part index
1364: *
1365: * @exception IOException If an I/O error occurs while reading from the
1366: * encoder header stream
1367: * */
1368: private void readCOC(DataInputStream ehs, boolean mainh,
1369: int tileIdx, int tpIdx) throws IOException {
1370: int cComp; // current component
1371: SynWTFilter hfilters[], vfilters[];
1372: int tmp, l;
1373: int ecOptions;
1374: Integer cblk[];
1375: String errMsg;
1376: HeaderInfo.COC ms = hi.getNewCOC();
1377:
1378: // Lcoc (marker length)
1379: ms.lcoc = ehs.readUnsignedShort();
1380:
1381: // Ccoc
1382: if (nComp < 257) {
1383: cComp = ms.ccoc = ehs.readUnsignedByte();
1384: } else {
1385: cComp = ms.ccoc = ehs.readUnsignedShort();
1386: }
1387: if (cComp >= nComp) {
1388: throw new CorruptedCodestreamException(
1389: "Invalid component index " + "in QCC marker");
1390: }
1391:
1392: // Scoc (block style)
1393: int cstyle = ms.scoc = ehs.readUnsignedByte();
1394: if ((cstyle & SCOX_PRECINCT_PARTITION) != 0) {
1395: precinctPartitionIsUsed = true;
1396: // Remove flag
1397: cstyle &= ~(SCOX_PRECINCT_PARTITION);
1398: } else {
1399: precinctPartitionIsUsed = false;
1400: }
1401:
1402: // SPcoc
1403:
1404: // decomposition levels
1405: int mrl = ms.spcoc_ndl = ehs.readUnsignedByte();
1406:
1407: // Read the code-blocks dimensions
1408: cblk = new Integer[2];
1409: ms.spcoc_cw = ehs.readUnsignedByte();
1410: cblk[0] = new Integer(1 << (ms.spcoc_cw + 2));
1411: if (cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM
1412: || cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM) {
1413: errMsg = "Non-valid code-block width in SPcod field, "
1414: + "COC marker";
1415: throw new CorruptedCodestreamException(errMsg);
1416: }
1417: ms.spcoc_ch = ehs.readUnsignedByte();
1418: cblk[1] = new Integer(1 << (ms.spcoc_ch + 2));
1419: if (cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM
1420: || cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM) {
1421: errMsg = "Non-valid code-block height in SPcod field, "
1422: + "COC marker";
1423: throw new CorruptedCodestreamException(errMsg);
1424: }
1425: if ((cblk[0].intValue() * cblk[1].intValue()) > StdEntropyCoderOptions.MAX_CB_AREA) {
1426: errMsg = "Non-valid code-block area in SPcod field, "
1427: + "COC marker";
1428: throw new CorruptedCodestreamException(errMsg);
1429: }
1430: if (mainh) {
1431: decSpec.cblks.setCompDef(cComp, cblk);
1432: } else {
1433: decSpec.cblks.setTileCompVal(tileIdx, cComp, cblk);
1434: }
1435:
1436: // Read entropy block mode options
1437: // NOTE: currently OPT_SEG_SYMBOLS is not included here
1438: ecOptions = ms.spcoc_cs = ehs.readUnsignedByte();
1439: if ((ecOptions & ~(OPT_BYPASS | OPT_RESET_MQ | OPT_TERM_PASS
1440: | OPT_VERT_STR_CAUSAL | OPT_PRED_TERM | OPT_SEG_SYMBOLS)) != 0) {
1441: throw new CorruptedCodestreamException(
1442: "Unknown \"code-block "
1443: + "context\" in SPcoc field, "
1444: + "COC marker: 0x"
1445: + Integer.toHexString(ecOptions));
1446: }
1447:
1448: // Read wavelet filter for tile or image
1449: hfilters = new SynWTFilter[1];
1450: vfilters = new SynWTFilter[1];
1451: hfilters[0] = readFilter(ehs, ms.spcoc_t);
1452: vfilters[0] = hfilters[0];
1453:
1454: // Fill the filter spec
1455: // If this is the main header, set the default value, if it is the
1456: // tile header, set default for this tile
1457: SynWTFilter[][] hvfilters = new SynWTFilter[2][];
1458: hvfilters[0] = hfilters;
1459: hvfilters[1] = vfilters;
1460:
1461: // Get precinct partition sizes
1462: Vector v[] = new Vector[2];
1463: v[0] = new Vector();
1464: v[1] = new Vector();
1465: int val = PRECINCT_PARTITION_DEF_SIZE;
1466: if (!precinctPartitionIsUsed) {
1467: Integer w, h;
1468: w = new Integer(1 << (val & 0x000F));
1469: v[0].addElement(w);
1470: h = new Integer(1 << (((val & 0x00F0) >> 4)));
1471: v[1].addElement(h);
1472: } else {
1473: ms.spcoc_ps = new int[mrl + 1];
1474: for (int rl = mrl; rl >= 0; rl--) {
1475: Integer w, h;
1476: val = ms.spcoc_ps[rl] = ehs.readUnsignedByte();
1477: w = new Integer(1 << (val & 0x000F));
1478: v[0].insertElementAt(w, 0);
1479: h = new Integer(1 << (((val & 0x00F0) >> 4)));
1480: v[1].insertElementAt(h, 0);
1481: }
1482: }
1483: if (mainh) {
1484: decSpec.pss.setCompDef(cComp, v);
1485: } else {
1486: decSpec.pss.setTileCompVal(tileIdx, cComp, v);
1487: }
1488: precinctPartitionIsUsed = true;
1489:
1490: // Check marker length
1491: checkMarkerLength(ehs, "COD marker");
1492:
1493: if (mainh) {
1494: hi.coc.put("main_c" + cComp, ms);
1495: decSpec.wfs.setCompDef(cComp, hvfilters);
1496: decSpec.dls.setCompDef(cComp, new Integer(mrl));
1497: decSpec.ecopts.setCompDef(cComp, new Integer(ecOptions));
1498: } else {
1499: hi.coc.put("t" + tileIdx + "_c" + cComp, ms);
1500: decSpec.wfs.setTileCompVal(tileIdx, cComp, hvfilters);
1501: decSpec.dls
1502: .setTileCompVal(tileIdx, cComp, new Integer(mrl));
1503: decSpec.ecopts.setTileCompVal(tileIdx, cComp, new Integer(
1504: ecOptions));
1505: }
1506: }
1507:
1508: /**
1509: * Reads the POC marker segment and realigns the codestream where the next
1510: * marker should be found.
1511: *
1512: * @param ehs The encoder header stream.
1513: *
1514: * @param mainh Flag indicating whether or not this marker segment is read
1515: * from the main header.
1516: *
1517: * @param t The index of the current tile
1518: *
1519: * @param tpIdx Tile-part index
1520: *
1521: * @exception IOException If an I/O error occurs while reading from the
1522: * encoder header stream
1523: * */
1524: private void readPOC(DataInputStream ehs, boolean mainh, int t,
1525: int tpIdx) throws IOException {
1526:
1527: boolean useShort = (nComp >= 256) ? true : false;
1528: int tmp;
1529: int nOldChg = 0;
1530: HeaderInfo.POC ms;
1531: if (mainh || hi.poc.get("t" + t) == null) {
1532: ms = hi.getNewPOC();
1533: } else {
1534: ms = (HeaderInfo.POC) hi.poc.get("t" + t);
1535: nOldChg = ms.rspoc.length;
1536: }
1537:
1538: // Lpoc
1539: ms.lpoc = ehs.readUnsignedShort();
1540:
1541: // Compute the number of new progression changes
1542: // newChg = (lpoc - Lpoc(2)) / (RSpoc(1) + CSpoc(2) +
1543: // LYEpoc(2) + REpoc(1) + CEpoc(2) + Ppoc (1) )
1544: int newChg = (ms.lpoc - 2) / (5 + (useShort ? 4 : 2));
1545: int ntotChg = nOldChg + newChg;
1546:
1547: int[][] change;
1548: if (nOldChg != 0) {
1549: // Creates new arrays
1550: change = new int[ntotChg][6];
1551: int[] tmprspoc = new int[ntotChg];
1552: int[] tmpcspoc = new int[ntotChg];
1553: int[] tmplyepoc = new int[ntotChg];
1554: int[] tmprepoc = new int[ntotChg];
1555: int[] tmpcepoc = new int[ntotChg];
1556: int[] tmpppoc = new int[ntotChg];
1557:
1558: // Copy old values
1559: int[][] prevChg = (int[][]) decSpec.pcs.getTileDef(t);
1560: for (int chg = 0; chg < nOldChg; chg++) {
1561: change[chg] = prevChg[chg];
1562: tmprspoc[chg] = ms.rspoc[chg];
1563: tmpcspoc[chg] = ms.cspoc[chg];
1564: tmplyepoc[chg] = ms.lyepoc[chg];
1565: tmprepoc[chg] = ms.repoc[chg];
1566: tmpcepoc[chg] = ms.cepoc[chg];
1567: tmpppoc[chg] = ms.ppoc[chg];
1568: }
1569: ms.rspoc = tmprspoc;
1570: ms.cspoc = tmpcspoc;
1571: ms.lyepoc = tmplyepoc;
1572: ms.repoc = tmprepoc;
1573: ms.cepoc = tmpcepoc;
1574: ms.ppoc = tmpppoc;
1575: } else {
1576: change = new int[newChg][6];
1577: ms.rspoc = new int[newChg];
1578: ms.cspoc = new int[newChg];
1579: ms.lyepoc = new int[newChg];
1580: ms.repoc = new int[newChg];
1581: ms.cepoc = new int[newChg];
1582: ms.ppoc = new int[newChg];
1583: }
1584:
1585: for (int chg = nOldChg; chg < ntotChg; chg++) {
1586: // RSpoc
1587: change[chg][0] = ms.rspoc[chg] = ehs.readUnsignedByte();
1588:
1589: // CSpoc
1590: if (useShort) {
1591: change[chg][1] = ms.cspoc[chg] = ehs
1592: .readUnsignedShort();
1593: } else {
1594: change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedByte();
1595: }
1596:
1597: // LYEpoc
1598: change[chg][2] = ms.lyepoc[chg] = ehs.readUnsignedShort();
1599: if (change[chg][2] < 1) {
1600: throw new CorruptedCodestreamException(
1601: "LYEpoc value must be greater than 1 in POC marker "
1602: + "segment of tile " + t
1603: + ", tile-part " + tpIdx);
1604: }
1605:
1606: // REpoc
1607: change[chg][3] = ms.repoc[chg] = ehs.readUnsignedByte();
1608: if (change[chg][3] <= change[chg][0]) {
1609: throw new CorruptedCodestreamException(
1610: "REpoc value must be greater than RSpoc in POC marker "
1611: + "segment of tile " + t
1612: + ", tile-part " + tpIdx);
1613: }
1614:
1615: // CEpoc
1616: if (useShort) {
1617: change[chg][4] = ms.cepoc[chg] = ehs
1618: .readUnsignedShort();
1619: } else {
1620: tmp = ms.cepoc[chg] = ehs.readUnsignedByte();
1621: if (tmp == 0) {
1622: change[chg][4] = 0;
1623: } else {
1624: change[chg][4] = tmp;
1625: }
1626: }
1627: if (change[chg][4] <= change[chg][1]) {
1628: throw new CorruptedCodestreamException(
1629: "CEpoc value must be greater than CSpoc in POC marker "
1630: + "segment of tile " + t
1631: + ", tile-part " + tpIdx);
1632: }
1633:
1634: // Ppoc
1635: change[chg][5] = ms.ppoc[chg] = ehs.readUnsignedByte();
1636: }
1637:
1638: // Check marker length
1639: checkMarkerLength(ehs, "POC marker");
1640:
1641: // Register specifications
1642: if (mainh) {
1643: hi.poc.put("main", ms);
1644: decSpec.pcs.setDefault(change);
1645: } else {
1646: hi.poc.put("t" + t, ms);
1647: decSpec.pcs.setTileDef(t, change);
1648: }
1649: }
1650:
1651: /**
1652: * Reads TLM marker segment and realigns the codestream where the next
1653: * marker should be found. Informations stored in these fields are
1654: * currently NOT taken into account.
1655: *
1656: * @param ehs The encoder header stream.
1657: *
1658: * @exception IOException If an I/O error occurs while reading from the
1659: * encoder header stream
1660: * */
1661: private void readTLM(DataInputStream ehs) throws IOException {
1662: int length;
1663:
1664: length = ehs.readUnsignedShort();
1665: //Ignore all informations contained
1666: ehs.skipBytes(length - 2);
1667:
1668: FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,
1669: "Skipping unsupported TLM marker");
1670: }
1671:
1672: /**
1673: * Reads PLM marker segment and realigns the codestream where the next
1674: * marker should be found. Informations stored in these fields are
1675: * currently not taken into account.
1676: *
1677: * @param ehs The encoder header stream.
1678: *
1679: * @exception IOException If an I/O error occurs while reading from the
1680: * encoder header stream
1681: * */
1682: private void readPLM(DataInputStream ehs) throws IOException {
1683: int length;
1684:
1685: length = ehs.readUnsignedShort();
1686: //Ignore all informations contained
1687: ehs.skipBytes(length - 2);
1688:
1689: FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,
1690: "Skipping unsupported PLM marker");
1691: }
1692:
1693: /**
1694: * Reads the PLT fields and realigns the codestream where the next marker
1695: * should be found. Informations stored in these fields are currently NOT
1696: * taken into account.
1697: *
1698: * @param ehs The encoder header stream.
1699: *
1700: * @exception IOException If an I/O error occurs while reading from the
1701: * encoder header stream
1702: * */
1703: private void readPLTFields(DataInputStream ehs) throws IOException {
1704: int length;
1705:
1706: length = ehs.readUnsignedShort();
1707: //Ignore all informations contained
1708: ehs.skipBytes(length - 2);
1709:
1710: FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,
1711: "Skipping unsupported PLT marker");
1712: }
1713:
1714: /**
1715: * Reads the RGN marker segment of the codestream header.
1716: *
1717: * <p>May be used in tile or main header. If used in main header, it
1718: * refers to the maxshift value of a component in all tiles. When used in
1719: * tile header, only the particular tile-component is affected.</p>
1720: *
1721: * @param ehs The encoder header stream.
1722: *
1723: * @param mainh Flag indicating whether or not this marker segment is read
1724: * from the main header.
1725: *
1726: * @param tileIdx The index of the current tile
1727: *
1728: * @param tpIdx Tile-part index
1729: *
1730: * @exception IOException If an I/O error occurs while reading from the
1731: * encoder header stream
1732: * */
1733: private void readRGN(DataInputStream ehs, boolean mainh,
1734: int tileIdx, int tpIdx) throws IOException {
1735: int comp; // ROI component
1736: int i; // loop variable
1737: int tempComp; // Component for
1738: HeaderInfo.RGN ms = hi.getNewRGN();
1739:
1740: // Lrgn (marker length)
1741: ms.lrgn = ehs.readUnsignedShort();
1742:
1743: // Read component
1744: ms.crgn = comp = (nComp < 257) ? ehs.readUnsignedByte() : ehs
1745: .readUnsignedShort();
1746: if (comp >= nComp) {
1747: throw new CorruptedCodestreamException("Invalid component "
1748: + "index in RGN marker" + comp);
1749: }
1750:
1751: // Read type of RGN.(Srgn)
1752: ms.srgn = ehs.readUnsignedByte();
1753:
1754: // Check that we can handle it.
1755: if (ms.srgn != SRGN_IMPLICIT)
1756: throw new CorruptedCodestreamException(
1757: "Unknown or unsupported "
1758: + "Srgn parameter in ROI " + "marker");
1759:
1760: if (decSpec.rois == null) { // No maxshift spec defined
1761: // Create needed ModuleSpec
1762: decSpec.rois = new MaxShiftSpec(nTiles, nComp,
1763: ModuleSpec.SPEC_TYPE_TILE_COMP, "null");
1764: }
1765:
1766: // SPrgn
1767: ms.sprgn = ehs.readUnsignedByte();
1768:
1769: if (mainh) {
1770: hi.rgn.put("main_c" + comp, ms);
1771: decSpec.rois.setCompDef(comp, new Integer(ms.sprgn));
1772: } else {
1773: hi.rgn.put("t" + tileIdx + "_c" + comp, ms);
1774: decSpec.rois.setTileCompVal(tileIdx, comp, new Integer(
1775: ms.sprgn));
1776: }
1777:
1778: // Check marker length
1779: checkMarkerLength(ehs, "RGN marker");
1780: }
1781:
1782: /**
1783: * Reads the PPM marker segment of the main header.
1784: *
1785: * @param ehs The encoder header stream.
1786: *
1787: * @exception IOException If an I/O error occurs while reading from the
1788: * encoder header stream
1789: * */
1790: private void readPPM(DataInputStream ehs) throws IOException {
1791: int curMarkSegLen;
1792: int i, indx, len, off;
1793: int remSegLen;
1794: byte[] b;
1795:
1796: // If first time readPPM method is called allocate arrays for packed
1797: // packet data
1798: if (pPMMarkerData == null) {
1799: pPMMarkerData = new byte[nPPMMarkSeg][];
1800: tileOfTileParts = new Vector();
1801: decSpec.pphs.setDefault(new Boolean(true));
1802: }
1803:
1804: // Lppm (marker length)
1805: curMarkSegLen = ehs.readUnsignedShort();
1806: remSegLen = curMarkSegLen - 3;
1807:
1808: // Zppm (index of PPM marker)
1809: indx = ehs.readUnsignedByte();
1810:
1811: // Read Nppm and Ippm data
1812: pPMMarkerData[indx] = new byte[remSegLen];
1813: ehs.read(pPMMarkerData[indx], 0, remSegLen);
1814:
1815: // Check marker length
1816: checkMarkerLength(ehs, "PPM marker");
1817: }
1818:
1819: /**
1820: * Teads the PPT marker segment of the main header.
1821: *
1822: * @param ehs The encoder header stream.
1823: *
1824: * @param tile The tile to which the current tile part belongs
1825: *
1826: * @param tpIdx Tile-part index
1827: *
1828: * @exception IOException If an I/O error occurs while reading from the
1829: * encoder header stream
1830: * */
1831: private void readPPT(DataInputStream ehs, int tile, int tpIdx)
1832: throws IOException {
1833: int curMarkSegLen;
1834: int indx, len = 0;
1835: byte[] temp;
1836:
1837: if (tilePartPkdPktHeaders == null) {
1838: tilePartPkdPktHeaders = new byte[nTiles][][][];
1839: }
1840:
1841: if (tilePartPkdPktHeaders[tile] == null) {
1842: tilePartPkdPktHeaders[tile] = new byte[nTileParts[tile]][][];
1843: }
1844:
1845: if (tilePartPkdPktHeaders[tile][tpIdx] == null) {
1846: tilePartPkdPktHeaders[tile][tpIdx] = new byte[nPPTMarkSeg[tile][tpIdx]][];
1847: }
1848:
1849: // Lppt (marker length)
1850: curMarkSegLen = ehs.readUnsignedShort();
1851:
1852: // Zppt (index of PPT marker)
1853: indx = ehs.readUnsignedByte();
1854:
1855: // Ippt (packed packet headers)
1856: temp = new byte[curMarkSegLen - 3];
1857: ehs.read(temp);
1858: tilePartPkdPktHeaders[tile][tpIdx][indx] = temp;
1859:
1860: // Check marker length
1861: checkMarkerLength(ehs, "PPT marker");
1862:
1863: decSpec.pphs.setTileDef(tile, new Boolean(true));
1864: }
1865:
1866: /**
1867: * This method extract a marker segment from the main header and stores it
1868: * into a byte buffer for the second pass. The marker segment is first
1869: * identified. Then its flag is activated. Finally, its content is
1870: * buffered into a byte array stored in an hashTable.
1871: *
1872: * <p>If the marker is not recognized, it prints a warning and skips it
1873: * according to its length.</p>
1874: *
1875: * <p>SIZ marker segment shall be the first encountered marker segment.</p>
1876: *
1877: * @param marker The marker segment to process
1878: *
1879: * @param ehs The encoded header stream
1880: * */
1881: private void extractMainMarkSeg(short marker, RandomAccessIO ehs)
1882: throws IOException {
1883: if (nfMarkSeg == 0) { // First non-delimiting marker of the header
1884: // JPEG 2000 part 1 specify that it must be SIZ
1885: if (marker != SIZ) {
1886: throw new CorruptedCodestreamException(
1887: "First marker after " + "SOC " + "must be SIZ "
1888: + Integer.toHexString(marker));
1889: }
1890: }
1891:
1892: String htKey = ""; // Name used as a key for the hash-table
1893: if (ht == null) {
1894: ht = new Hashtable();
1895: }
1896:
1897: switch (marker) {
1898: case SIZ:
1899: if ((nfMarkSeg & SIZ_FOUND) != 0) {
1900: throw new CorruptedCodestreamException(
1901: "More than one SIZ marker "
1902: + "segment found in main " + "header");
1903: }
1904: nfMarkSeg |= SIZ_FOUND;
1905: htKey = "SIZ";
1906: break;
1907: case SOD:
1908: throw new CorruptedCodestreamException(
1909: "SOD found in main header");
1910: case EOC:
1911: throw new CorruptedCodestreamException(
1912: "EOC found in main header");
1913: case SOT:
1914: if ((nfMarkSeg & SOT_FOUND) != 0) {
1915: throw new CorruptedCodestreamException(
1916: "More than one SOT " + "marker "
1917: + "found right after " + "main "
1918: + "or tile header");
1919: }
1920: nfMarkSeg |= SOT_FOUND;
1921: return;
1922: case COD:
1923: if ((nfMarkSeg & COD_FOUND) != 0) {
1924: throw new CorruptedCodestreamException(
1925: "More than one COD " + "marker "
1926: + "found in main header");
1927: }
1928: nfMarkSeg |= COD_FOUND;
1929: htKey = "COD";
1930: break;
1931: case COC:
1932: nfMarkSeg |= COC_FOUND;
1933: htKey = "COC" + (nCOCMarkSeg++);
1934: break;
1935: case QCD:
1936: if ((nfMarkSeg & QCD_FOUND) != 0) {
1937: throw new CorruptedCodestreamException(
1938: "More than one QCD " + "marker "
1939: + "found in main header");
1940: }
1941: nfMarkSeg |= QCD_FOUND;
1942: htKey = "QCD";
1943: break;
1944: case QCC:
1945: nfMarkSeg |= QCC_FOUND;
1946: htKey = "QCC" + (nQCCMarkSeg++);
1947: break;
1948: case RGN:
1949: nfMarkSeg |= RGN_FOUND;
1950: htKey = "RGN" + (nRGNMarkSeg++);
1951: break;
1952: case COM:
1953: nfMarkSeg |= COM_FOUND;
1954: htKey = "COM" + (nCOMMarkSeg++);
1955: break;
1956: case CRG:
1957: if ((nfMarkSeg & CRG_FOUND) != 0) {
1958: throw new CorruptedCodestreamException(
1959: "More than one CRG " + "marker "
1960: + "found in main header");
1961: }
1962: nfMarkSeg |= CRG_FOUND;
1963: htKey = "CRG";
1964: break;
1965: case PPM:
1966: nfMarkSeg |= PPM_FOUND;
1967: htKey = "PPM" + (nPPMMarkSeg++);
1968: break;
1969: case TLM:
1970: if ((nfMarkSeg & TLM_FOUND) != 0) {
1971: FacilityManager.getMsgLogger().printmsg(
1972: MsgLogger.INFO,
1973: "More than one TLM " + "marker "
1974: + "found in main header");
1975: /** XXX It is legal to have multiple TLM segments.
1976: throw new CorruptedCodestreamException("More than one TLM "+
1977: "marker "+
1978: "found in main header");
1979: */
1980: }
1981: nfMarkSeg |= TLM_FOUND;
1982: break;
1983: case PLM:
1984: if ((nfMarkSeg & PLM_FOUND) != 0) {
1985: throw new CorruptedCodestreamException(
1986: "More than one PLM " + "marker "
1987: + "found in main header");
1988: }
1989: FacilityManager.getMsgLogger().printmsg(
1990: MsgLogger.WARNING,
1991: "PLM marker segment found but "
1992: + "not used by by JJ2000 decoder.");
1993: nfMarkSeg |= PLM_FOUND;
1994: htKey = "PLM";
1995: break;
1996: case POC:
1997: if ((nfMarkSeg & POC_FOUND) != 0) {
1998: throw new CorruptedCodestreamException(
1999: "More than one POC " + "marker segment found "
2000: + "in main header");
2001: }
2002: nfMarkSeg |= POC_FOUND;
2003: htKey = "POC";
2004: break;
2005: case PLT:
2006: throw new CorruptedCodestreamException(
2007: "PLT found in main header");
2008: case PPT:
2009: throw new CorruptedCodestreamException(
2010: "PPT found in main header");
2011: default:
2012: htKey = "UNKNOWN";
2013: FacilityManager.getMsgLogger().printmsg(
2014: MsgLogger.WARNING,
2015: "Non recognized marker segment (0x"
2016: + Integer.toHexString(marker)
2017: + ") in main header!");
2018: break;
2019: }
2020:
2021: if (marker < 0xffffff30 || marker > 0xffffff3f) {
2022: // Read marker segment length and create corresponding byte buffer
2023: int markSegLen = ehs.readUnsignedShort();
2024: byte[] buf = new byte[markSegLen];
2025:
2026: // Copy data (after re-insertion of the marker segment length);
2027: buf[0] = (byte) ((markSegLen >> 8) & 0xFF);
2028: buf[1] = (byte) (markSegLen & 0xFF);
2029: ehs.readFully(buf, 2, markSegLen - 2);
2030:
2031: if (!htKey.equals("UNKNOWN")) {
2032: // Store array in hashTable
2033: ht.put(htKey, buf);
2034: }
2035: }
2036: }
2037:
2038: /**
2039: * This method extracts a marker segment in a tile-part header and stores
2040: * it into a byte buffer for the second pass. The marker is first
2041: * recognized, then its flag is activated and, finally, its content is
2042: * buffered in an element of byte arrays accessible thanks to a hashTable.
2043: * If a marker segment is not recognized, it prints a warning and skip it
2044: * according to its length.
2045: *
2046: * @param marker The marker to process
2047: *
2048: * @param ehs The encoded header stream
2049: *
2050: * @param tileIdx The index of the current tile
2051: *
2052: * @param tilePartIdx The index of the current tile part
2053: * */
2054: public void extractTilePartMarkSeg(short marker,
2055: RandomAccessIO ehs, int tileIdx, int tilePartIdx)
2056: throws IOException {
2057:
2058: String htKey = ""; // Name used as a hash-table key
2059: if (ht == null) {
2060: ht = new Hashtable();
2061: }
2062:
2063: switch (marker) {
2064: case SOT:
2065: throw new CorruptedCodestreamException("Second SOT marker "
2066: + "segment found in tile-" + "part header");
2067: case SIZ:
2068: throw new CorruptedCodestreamException(
2069: "SIZ found in tile-part" + " header");
2070: case EOC:
2071: throw new CorruptedCodestreamException(
2072: "EOC found in tile-part" + " header");
2073: case TLM:
2074: throw new CorruptedCodestreamException(
2075: "TLM found in tile-part" + " header");
2076: case PPM:
2077: throw new CorruptedCodestreamException(
2078: "PPM found in tile-part" + " header");
2079: case COD:
2080: if ((nfMarkSeg & COD_FOUND) != 0) {
2081: throw new CorruptedCodestreamException(
2082: "More than one COD " + "marker "
2083: + "found in tile-part" + " header");
2084: }
2085: nfMarkSeg |= COD_FOUND;
2086: htKey = "COD";
2087: break;
2088: case COC:
2089: nfMarkSeg |= COC_FOUND;
2090: htKey = "COC" + (nCOCMarkSeg++);
2091: break;
2092: case QCD:
2093: if ((nfMarkSeg & QCD_FOUND) != 0) {
2094: throw new CorruptedCodestreamException(
2095: "More than one QCD " + "marker "
2096: + "found in tile-part" + " header");
2097: }
2098: nfMarkSeg |= QCD_FOUND;
2099: htKey = "QCD";
2100: break;
2101: case QCC:
2102: nfMarkSeg |= QCC_FOUND;
2103: htKey = "QCC" + (nQCCMarkSeg++);
2104: break;
2105: case RGN:
2106: nfMarkSeg |= RGN_FOUND;
2107: htKey = "RGN" + (nRGNMarkSeg++);
2108: break;
2109: case COM:
2110: nfMarkSeg |= COM_FOUND;
2111: htKey = "COM" + (nCOMMarkSeg++);
2112: break;
2113: case CRG:
2114: throw new CorruptedCodestreamException(
2115: "CRG marker found in " + "tile-part header");
2116: case PPT:
2117: nfMarkSeg |= PPT_FOUND;
2118: if (nPPTMarkSeg == null) {
2119: nPPTMarkSeg = new int[nTiles][];
2120: }
2121: if (nPPTMarkSeg[tileIdx] == null) {
2122: nPPTMarkSeg[tileIdx] = new int[nTileParts[tileIdx]];
2123: }
2124: htKey = "PPT" + (nPPTMarkSeg[tileIdx][tilePartIdx]++);
2125: break;
2126: case SOD:
2127: nfMarkSeg |= SOD_FOUND;
2128: return;
2129: case POC:
2130: if ((nfMarkSeg & POC_FOUND) != 0)
2131: throw new CorruptedCodestreamException(
2132: "More than one POC " + "marker segment found "
2133: + "in tile-part" + " header");
2134: nfMarkSeg |= POC_FOUND;
2135: htKey = "POC";
2136: break;
2137: case PLT:
2138: if ((nfMarkSeg & PLM_FOUND) != 0) {
2139: throw new CorruptedCodestreamException(
2140: "PLT marker found even" + "though PLM marker "
2141: + "found in main header");
2142: }
2143: FacilityManager.getMsgLogger().printmsg(
2144: MsgLogger.WARNING,
2145: "PLT marker segment found but "
2146: + "not used by JJ2000 decoder.");
2147: htKey = "UNKNOWN";
2148: break;
2149: default:
2150: htKey = "UNKNOWN";
2151: FacilityManager.getMsgLogger().printmsg(
2152: MsgLogger.WARNING,
2153: "Non recognized marker segment (0x"
2154: + Integer.toHexString(marker)
2155: + ") in tile-part header" + " of tile "
2156: + tileIdx + " !");
2157: break;
2158: }
2159:
2160: // Read marker segment length and create corresponding byte buffer
2161: int markSegLen = ehs.readUnsignedShort();
2162: byte[] buf = new byte[markSegLen];
2163:
2164: // Copy data (after re-insertion of marker segment length);
2165: buf[0] = (byte) ((markSegLen >> 8) & 0xFF);
2166: buf[1] = (byte) (markSegLen & 0xFF);
2167: ehs.readFully(buf, 2, markSegLen - 2);
2168:
2169: if (!htKey.equals("UNKNOWN")) {
2170: // Store array in hashTable
2171: ht.put(htKey, buf);
2172: }
2173: }
2174:
2175: /**
2176: * Retrieves and reads all marker segments found in the main header during
2177: * the first pass.
2178: * */
2179: private void readFoundMainMarkSeg() throws IOException {
2180: DataInputStream dis;
2181: ByteArrayInputStream bais;
2182:
2183: // SIZ marker segment
2184: if ((nfMarkSeg & SIZ_FOUND) != 0) {
2185: bais = new ByteArrayInputStream((byte[]) (ht.get("SIZ")));
2186: readSIZ(new DataInputStream(bais));
2187: }
2188:
2189: // COM marker segments
2190: if ((nfMarkSeg & COM_FOUND) != 0) {
2191: for (int i = 0; i < nCOMMarkSeg; i++) {
2192: bais = new ByteArrayInputStream((byte[]) (ht.get("COM"
2193: + i)));
2194: readCOM(new DataInputStream(bais), true, 0, i);
2195: }
2196: }
2197:
2198: // CRG marker segment
2199: if ((nfMarkSeg & CRG_FOUND) != 0) {
2200: bais = new ByteArrayInputStream((byte[]) (ht.get("CRG")));
2201: readCRG(new DataInputStream(bais));
2202: }
2203:
2204: // COD marker segment
2205: if ((nfMarkSeg & COD_FOUND) != 0) {
2206: bais = new ByteArrayInputStream((byte[]) (ht.get("COD")));
2207: readCOD(new DataInputStream(bais), true, 0, 0);
2208: }
2209:
2210: // COC marker segments
2211: if ((nfMarkSeg & COC_FOUND) != 0) {
2212: for (int i = 0; i < nCOCMarkSeg; i++) {
2213: bais = new ByteArrayInputStream((byte[]) (ht.get("COC"
2214: + i)));
2215: readCOC(new DataInputStream(bais), true, 0, 0);
2216: }
2217: }
2218:
2219: // RGN marker segment
2220: if ((nfMarkSeg & RGN_FOUND) != 0) {
2221: for (int i = 0; i < nRGNMarkSeg; i++) {
2222: bais = new ByteArrayInputStream((byte[]) (ht.get("RGN"
2223: + i)));
2224: readRGN(new DataInputStream(bais), true, 0, 0);
2225: }
2226: }
2227:
2228: // QCD marker segment
2229: if ((nfMarkSeg & QCD_FOUND) != 0) {
2230: bais = new ByteArrayInputStream((byte[]) (ht.get("QCD")));
2231: readQCD(new DataInputStream(bais), true, 0, 0);
2232: }
2233:
2234: // QCC marker segments
2235: if ((nfMarkSeg & QCC_FOUND) != 0) {
2236: for (int i = 0; i < nQCCMarkSeg; i++) {
2237: bais = new ByteArrayInputStream((byte[]) (ht.get("QCC"
2238: + i)));
2239: readQCC(new DataInputStream(bais), true, 0, 0);
2240: }
2241: }
2242:
2243: // POC marker segment
2244: if ((nfMarkSeg & POC_FOUND) != 0) {
2245: bais = new ByteArrayInputStream((byte[]) (ht.get("POC")));
2246: readPOC(new DataInputStream(bais), true, 0, 0);
2247: }
2248:
2249: // PPM marker segments
2250: if ((nfMarkSeg & PPM_FOUND) != 0) {
2251: for (int i = 0; i < nPPMMarkSeg; i++) {
2252: bais = new ByteArrayInputStream((byte[]) (ht.get("PPM"
2253: + i)));
2254: readPPM(new DataInputStream(bais));
2255: }
2256: }
2257:
2258: // Reset the hashtable
2259: ht = null;
2260: }
2261:
2262: /**
2263: * Return the DecoderSpecs instance filled when reading the headers
2264: *
2265: * @retrieves and reads all marker segments previously found in the
2266: * tile-part header.
2267: *
2268: * @param tileIdx The index of the current tile
2269: *
2270: * @param tpIdx Index of the current tile-part
2271: * */
2272: public void readFoundTilePartMarkSeg(int tileIdx, int tpIdx)
2273: throws IOException {
2274:
2275: DataInputStream dis;
2276: ByteArrayInputStream bais;
2277:
2278: // COD marker segment
2279: if ((nfMarkSeg & COD_FOUND) != 0) {
2280: bais = new ByteArrayInputStream((byte[]) (ht.get("COD")));
2281: readCOD(new DataInputStream(bais), false, tileIdx, tpIdx);
2282: }
2283:
2284: // COC marker segments
2285: if ((nfMarkSeg & COC_FOUND) != 0) {
2286: for (int i = 0; i < nCOCMarkSeg; i++) {
2287: bais = new ByteArrayInputStream((byte[]) (ht.get("COC"
2288: + i)));
2289: readCOC(new DataInputStream(bais), false, tileIdx,
2290: tpIdx);
2291: }
2292: }
2293:
2294: // RGN marker segment
2295: if ((nfMarkSeg & RGN_FOUND) != 0) {
2296: for (int i = 0; i < nRGNMarkSeg; i++) {
2297: bais = new ByteArrayInputStream((byte[]) (ht.get("RGN"
2298: + i)));
2299: readRGN(new DataInputStream(bais), false, tileIdx,
2300: tpIdx);
2301: }
2302: }
2303:
2304: // QCD marker segment
2305: if ((nfMarkSeg & QCD_FOUND) != 0) {
2306: bais = new ByteArrayInputStream((byte[]) (ht.get("QCD")));
2307: readQCD(new DataInputStream(bais), false, tileIdx, tpIdx);
2308: }
2309:
2310: // QCC marker segments
2311: if ((nfMarkSeg & QCC_FOUND) != 0) {
2312: for (int i = 0; i < nQCCMarkSeg; i++) {
2313: bais = new ByteArrayInputStream((byte[]) (ht.get("QCC"
2314: + i)));
2315: readQCC(new DataInputStream(bais), false, tileIdx,
2316: tpIdx);
2317: }
2318: }
2319: // POC marker segment
2320: if ((nfMarkSeg & POC_FOUND) != 0) {
2321: bais = new ByteArrayInputStream((byte[]) (ht.get("POC")));
2322: readPOC(new DataInputStream(bais), false, tileIdx, tpIdx);
2323: }
2324:
2325: // COM marker segments
2326: if ((nfMarkSeg & COM_FOUND) != 0) {
2327: for (int i = 0; i < nCOMMarkSeg; i++) {
2328: bais = new ByteArrayInputStream((byte[]) (ht.get("COM"
2329: + i)));
2330: readCOM(new DataInputStream(bais), false, tileIdx, i);
2331: }
2332: }
2333:
2334: // PPT marker segments
2335: if ((nfMarkSeg & PPT_FOUND) != 0) {
2336: for (int i = 0; i < nPPTMarkSeg[tileIdx][tpIdx]; i++) {
2337: bais = new ByteArrayInputStream((byte[]) (ht.get("PPT"
2338: + i)));
2339: readPPT(new DataInputStream(bais), tileIdx, tpIdx);
2340: }
2341: }
2342:
2343: // Reset ht
2344: ht = null;
2345: }
2346:
2347: /**
2348: * Return the DecoderSpecs instance filled when reading the headers
2349: *
2350: * @return The DecoderSpecs of the decoder
2351: * */
2352: public DecoderSpecs getDecoderSpecs() {
2353: return decSpec;
2354: }
2355:
2356: /**
2357: * Creates a HeaderDecoder instance and read in two passes the main header
2358: * of the codestream. The first and last marker segments shall be
2359: * respectively SOC and SOT.
2360: *
2361: * @param ehs The encoded header stream where marker segment are
2362: * extracted.
2363: *
2364: * @param j2krparam The parameter list of the decoder
2365: *
2366: * @param hi The HeaderInfo holding information found in marker segments
2367: *
2368: * @exception IOException If an I/O error occurs while reading from the
2369: * encoded header stream.
2370: *
2371: * @exception EOFException If the end of the encoded header stream is
2372: * reached before getting all the data.
2373: *
2374: * @exception CorruptedCodestreamException If invalid data is found in the
2375: * codestream main header.
2376: * */
2377: public HeaderDecoder(RandomAccessIO ehs,
2378: J2KImageReadParamJava j2krparam, HeaderInfo hi)
2379: throws IOException {
2380:
2381: this .hi = hi;
2382: this .j2krparam = j2krparam;
2383: mainHeadOff = ehs.getPos();
2384: if (((short) ehs.readShort()) != Markers.SOC) {
2385: throw new CorruptedCodestreamException(
2386: "SOC marker segment not " + " found at the "
2387: + "beginning of the " + "codestream.");
2388: }
2389:
2390: // First Pass: Decode and store main header information until the SOT
2391: // marker segment is found
2392: nfMarkSeg = 0;
2393: do {
2394: extractMainMarkSeg(ehs.readShort(), ehs);
2395: } while ((nfMarkSeg & SOT_FOUND) == 0); //Stop when SOT is found
2396: ehs.seek(ehs.getPos() - 2); // Realign codestream on SOT marker
2397:
2398: // Second pass: Read each marker segment previously found
2399: readFoundMainMarkSeg();
2400: }
2401:
2402: /**
2403: * Creates and returns the entropy decoder corresponding to the
2404: * information read from the codestream header and with the special
2405: * additional parameters from the parameter list.
2406: *
2407: * @param src The bit stream reader agent where to get code-block data
2408: * from.
2409: *
2410: * @param j2krparam The parameter list containing parameters applicable to the
2411: * entropy decoder (other parameters can also be present).
2412: *
2413: * @return The entropy decoder
2414: * */
2415: public EntropyDecoder createEntropyDecoder(CodedCBlkDataSrcDec src,
2416: J2KImageReadParamJava j2krparam) {
2417: // Get error detection option
2418: // boolean doer = j2krparam.getCer();;
2419: boolean doer = true;
2420: // Get verbose error detection option
2421: //boolean verber = j2krparam.getVerbose();
2422: boolean verber = false;
2423:
2424: // Get maximum number of bit planes from m quit condition
2425: // int mMax = j2krparam.getMQuit();
2426: int mMax = -1;
2427: return new StdEntropyDecoder(src, decSpec, doer, verber, mMax);
2428: }
2429:
2430: /**
2431: * Creates and returns the EnumeratedColorSpaceMapper
2432: * corresponding to the information read from the JP2 image file
2433: * via the ColorSpace parameter.
2434: *
2435: * @param src The bit stream reader agent where to get code-block
2436: * data from.
2437: * @param csMap provides color space information from the image file
2438: *
2439: * @return The color space mapping object
2440: * @exception IOException image access exception
2441: * @exception ICCProfileException if image contains a bad icc profile
2442: * @exception ColorSpaceException if image contains a bad colorspace box
2443: **/
2444: /*
2445: public BlkImgDataSrc createColorSpaceMapper(BlkImgDataSrc src,
2446: ColorSpace csMap)
2447: throws IOException, ICCProfileException, ColorSpaceException {
2448: return ColorSpaceMapper.createInstance(src,csMap);
2449: }
2450: */
2451: /**
2452: * Creates and returns the ChannelDefinitonMapper which maps the
2453: * input channels to the channel definition for the appropriate
2454: * colorspace.
2455: *
2456: * @param src The bit stream reader agent where to get code-block
2457: * data from.
2458: * @param csMap provides color space information from the image file
2459: *
2460: * @return The channel definition mapping object
2461: * @exception IOException image access exception
2462: * @exception ColorSpaceException if image contains a bad colorspace box
2463: **/
2464: /*
2465: public BlkImgDataSrc createChannelDefinitionMapper(BlkImgDataSrc src,
2466: ColorSpace csMap)
2467: throws IOException, ColorSpaceException {
2468: return ChannelDefinitionMapper.createInstance(src,csMap);
2469: }
2470: */
2471: /**
2472: * Creates and returns the PalettizedColorSpaceMapper which uses
2473: * the input samples as indicies into a sample palette to
2474: * construct the output.
2475: *
2476: * @param src The bit stream reader agent where to get code-block
2477: * data from.
2478: * @param csMap provides color space information from the image file
2479: *
2480: * @return a PalettizedColorSpaceMapper instance
2481: * @exception IOException image access exception
2482: * @exception ColorSpaceException if image contains a bad colorspace box
2483: **/
2484: /*
2485: public BlkImgDataSrc createPalettizedColorSpaceMapper(BlkImgDataSrc src,
2486: ColorSpace csMap)
2487: throws IOException, ColorSpaceException {
2488: return PalettizedColorSpaceMapper.createInstance(src, csMap); }
2489: */
2490: /**
2491: * Creates and returns the Resampler which converts the input
2492: * source to one in which all channels have the same number of
2493: * samples. This is required for colorspace conversions.
2494: *
2495: * @param src The bit stream reader agent where to get code-block
2496: * data from.
2497: * @param csMap provides color space information from the image file
2498: *
2499: * @return The resampled BlkImgDataSrc
2500: * @exception IOException image access exception
2501: * @exception ColorSpaceException if image contains a bad colorspace box
2502: **/
2503: /*
2504: public BlkImgDataSrc createResampler(BlkImgDataSrc src,
2505: ColorSpace csMap)
2506: throws IOException, ColorSpaceException {
2507: return Resampler.createInstance(src, csMap); }
2508: */
2509: /**
2510: * Creates and returns the ROIDeScaler corresponding to the information
2511: * read from the codestream header and with the special additional
2512: * parameters from the parameter list.
2513: *
2514: * @param src The bit stream reader agent where to get code-block data
2515: * from.
2516: *
2517: * @param pl The parameter list containing parameters applicable to the
2518: * entropy decoder (other parameters can also be present).
2519: *
2520: * @return The ROI descaler
2521: * */
2522: public ROIDeScaler createROIDeScaler(CBlkQuantDataSrcDec src,
2523: J2KImageReadParamJava j2krparam, DecoderSpecs decSpec2) {
2524: return ROIDeScaler.createInstance(src, j2krparam, decSpec2);
2525: }
2526:
2527: /**
2528: * Method that resets members indicating which markers have already been
2529: * found
2530: * */
2531: public void resetHeaderMarkers() {
2532: // The found status of PLM remains since only PLM OR PLT allowed
2533: // Same goes for PPM and PPT
2534: nfMarkSeg = nfMarkSeg & (PLM_FOUND | PPM_FOUND);
2535: nCOCMarkSeg = 0;
2536: nQCCMarkSeg = 0;
2537: nCOMMarkSeg = 0;
2538: nRGNMarkSeg = 0;
2539: }
2540:
2541: /**
2542: * Print information about the current header.
2543: *
2544: * @return Information in a String
2545: * */
2546: public String toString() {
2547: return hdStr;
2548: }
2549:
2550: /**
2551: * Returns the parameters that are used in this class. It returns a 2D
2552: * String array. Each of the 1D arrays is for a different option, and they
2553: * have 3 elements. The first element is the option name, the second one
2554: * is the synopsis and the third one is a long description of what the
2555: * parameter is. The synopsis or description may be 'null', in which case
2556: * it is assumed that there is no synopsis or description of the option,
2557: * respectively.
2558: *
2559: * @return the options name, their synopsis and their explanation.
2560: * */
2561: public static String[][] getParameterInfo() {
2562: return pinfo;
2563: }
2564:
2565: /**
2566: * Return the number of tiles in the image
2567: *
2568: * @return The number of tiles
2569: * */
2570: public int getNumTiles() {
2571: return nTiles;
2572: }
2573:
2574: /**
2575: * Return the packed packet headers for a given tile.
2576: *
2577: * @return An input stream containing the packed packet headers for a
2578: * particular tile
2579: *
2580: * @exception IOException If an I/O error occurs while reading from the
2581: * encoder header stream
2582: * */
2583: public ByteArrayInputStream getPackedPktHead(int tile)
2584: throws IOException {
2585:
2586: if (pkdPktHeaders == null) {
2587: int i, t;
2588: pkdPktHeaders = new ByteArrayOutputStream[nTiles];
2589: for (i = nTiles - 1; i >= 0; i--) {
2590: pkdPktHeaders[i] = new ByteArrayOutputStream();
2591: }
2592: if (nPPMMarkSeg != 0) {
2593: // If this is first time packed packet headers are requested,
2594: // create packed packet headers from Nppm and Ippm fields
2595: int nppm;
2596: int nTileParts = tileOfTileParts.size();
2597: byte[] temp;
2598: ByteArrayInputStream pph;
2599: ByteArrayOutputStream allNppmIppm = new ByteArrayOutputStream();
2600:
2601: // Concatenate all Nppm and Ippm fields
2602: for (i = 0; i < nPPMMarkSeg; i++) {
2603: allNppmIppm.write(pPMMarkerData[i]);
2604: }
2605: pph = new ByteArrayInputStream(allNppmIppm
2606: .toByteArray());
2607:
2608: // Read all packed packet headers and concatenate for each
2609: // tile part
2610: for (i = 0; i < nTileParts; i++) {
2611: t = ((Integer) tileOfTileParts.elementAt(i))
2612: .intValue();
2613: // get Nppm value
2614: nppm = (pph.read() << 24) | (pph.read() << 16)
2615: | (pph.read() << 8) | (pph.read());
2616:
2617: temp = new byte[nppm];
2618: // get ippm field
2619: pph.read(temp);
2620: pkdPktHeaders[t].write(temp);
2621: }
2622: } else {
2623: int tp;
2624: // Write all packed packet headers to pkdPktHeaders
2625: for (t = nTiles - 1; t >= 0; t--) {
2626: for (tp = 0; tp < nTileParts[t]; tp++) {
2627: for (i = 0; i < nPPTMarkSeg[t][tp]; i++) {
2628: pkdPktHeaders[t]
2629: .write(tilePartPkdPktHeaders[t][tp][i]);
2630: }
2631: }
2632: }
2633: }
2634: }
2635:
2636: return new ByteArrayInputStream(pkdPktHeaders[tile]
2637: .toByteArray());
2638: }
2639:
2640: /**
2641: * Sets the tile of each tile part in order. This information is needed
2642: * for identifying which packet header belongs to which tile when using
2643: * the PPM marker.
2644: *
2645: * @param tile The tile number that the present tile part belongs to.
2646: * */
2647: public void setTileOfTileParts(int tile) {
2648: if (nPPMMarkSeg != 0) {
2649: tileOfTileParts.addElement(new Integer(tile));
2650: }
2651: }
2652:
2653: /**
2654: * Returns the number of found marker segments in the current header.
2655: *
2656: * @return The number of marker segments found in the current header.
2657: * */
2658: public int getNumFoundMarkSeg() {
2659: return nfMarkSeg;
2660: }
2661:
2662: }
|