/* * #%L * Fork of JAI Image I/O Tools. * %% * Copyright (C) 2008 - 2015 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * #L% */ /* * $RCSfile: HeaderDecoder.java,v $ * $Revision: 1.2 $ * $Date: 2006/09/28 00:55:20 $ * $State: Exp $ * * Class: HeaderDecoder * * Description: Reads main and tile-part headers. * * * COPYRIGHT: * * This software module was originally developed by Raphaël Grosbois and * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research * Centre France S.A) in the course of development of the JPEG2000 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This * software module is an implementation of a part of the JPEG 2000 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio * Systems AB and Canon Research Centre France S.A (collectively JJ2000 * Partners) agree not to assert against ISO/IEC and users of the JPEG * 2000 Standard (Users) any of their rights under the copyright, not * including other intellectual property rights, for this software module * with respect to the usage by ISO/IEC and Users of this software module * or modifications thereof for use in hardware or software products * claiming conformance to the JPEG 2000 Standard. Those intending to use * this software module in hardware or software products are advised that * their use may infringe existing patents. The original developers of * this software module, JJ2000 Partners and ISO/IEC assume no liability * for use of this software module or modifications thereof. No license * or right to this software module is granted for non JPEG 2000 Standard * conforming products. JJ2000 Partners have full right to use this * software module for his/her own purpose, assign or donate this * software module to any third party and to inhibit third parties from * using this software module for non JPEG 2000 Standard conforming * products. This copyright notice must be included in all copies or * derivative works of this software module. * * Copyright (c) 1999/2000 JJ2000 Partners. * */ package jj2000.j2k.codestream.reader; import java.awt.Point; import jj2000.j2k.quantization.dequantizer.*; import jj2000.j2k.wavelet.synthesis.*; import jj2000.j2k.entropy.decoder.*; import jj2000.j2k.quantization.*; import jj2000.j2k.codestream.*; import jj2000.j2k.wavelet.*; import jj2000.j2k.entropy.*; import jj2000.j2k.decoder.*; import jj2000.j2k.image.*; import jj2000.j2k.util.*; import jj2000.j2k.roi.*; import jj2000.j2k.io.*; import jj2000.j2k.*; import java.io.*; import java.util.*; //import colorspace.*; //import icc.*; import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReadParamJava; /** * This class reads Main and Tile-part headers from the codestream. It is * created by the run() method of the Decoder instance. * * <p>A marker segment includes a marker and eventually marker segment * parameters. It is designed by the three letters code of the marker * associated with the marker segment. JPEG 2000 part 1 defines 6 types of * markers: * * <ul> * <li> Delimiting : SOC,SOT (read in FileBitstreamReaderAgent),SOD,EOC * (read in FileBitstreamReaderAgent).</li> <li> Fixed information: SIZ.</li> * * <li> Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream: * SOP,EPH.</li> * * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li> * * <li> Informational: CRG,COM.</li> * </ul> * * <p>The main header is read when the constructor is called whereas tile-part * headers are read when the FileBitstreamReaderAgent instance is created. The * reading is done in 2 passes: * * <ul> * <li>All marker segments are buffered and their corresponding flag is * activated (extractMainMarkSeg and extractTilePartMarkSeg methods).</li> * * <li>Buffered marker segment are analyzed in a logical way and * specifications are stored in appropriate member of DecoderSpecs instance * (readFoundMainMarkSeg and readFoundTilePartMarkSeg methods).</li> * </ul> * * <p>Whenever a marker segment is not recognized a warning message is * displayed and its length parameter is used to skip it. * * @see DecoderSpecs * @see FileBitstreamReaderAgent * */ public class HeaderDecoder implements ProgressionType, Markers, StdEntropyCoderOptions { /** The prefix for header decoder options: 'H' */ public final static char OPT_PREFIX = 'H'; /** The list of parameters that is accepted for quantization. Options * for quantization start with 'Q'. */ private final static String [][] pinfo = null; /** The reference to the HeaderInfo instance holding the information found * in headers */ private HeaderInfo hi; /** Current header information in a string */ private String hdStr = ""; /** The J2KImageReadParamJava instance of the decoder */ private J2KImageReadParamJava j2krparam; /** The number of tiles within the image */ private int nTiles; /** The number of tile parts per tile */ public int[] nTileParts; /** Used to store which markers have been already read, by using flag * bits. The different markers are marked with XXX_FOUND flags, such as * SIZ_FOUND */ private int nfMarkSeg = 0; /** Counts number of COC markers found in the header */ private int nCOCMarkSeg = 0; /** Counts number of QCC markers found in the header */ private int nQCCMarkSeg = 0; /** Counts number of COM markers found in the header */ private int nCOMMarkSeg = 0; /** Counts number of RGN markers found in the header */ private int nRGNMarkSeg = 0; /** Counts number of PPM markers found in the header */ private int nPPMMarkSeg = 0; /** Counts number of PPT markers found in the header */ private int[][] nPPTMarkSeg = null; /** Flag bit for SIZ marker segment found */ private static final int SIZ_FOUND = 1; /** Flag bit for COD marker segment found */ private static final int COD_FOUND = 1<<1; /** Flag bit for COC marker segment found */ private static final int COC_FOUND = 1<<2; /** Flag bit for QCD marker segment found */ private static final int QCD_FOUND = 1<<3; /** Flag bit for TLM marker segment found */ private static final int TLM_FOUND = 1<<4; /** Flag bit for PLM marker segment found */ private static final int PLM_FOUND = 1<<5; /** Flag bit for SOT marker segment found */ private static final int SOT_FOUND = 1<<6; /** Flag bit for PLT marker segment found */ private static final int PLT_FOUND = 1<<7; /** Flag bit for QCC marker segment found */ private static final int QCC_FOUND = 1<<8; /** Flag bit for RGN marker segment found */ private static final int RGN_FOUND = 1<<9; /** Flag bit for POC marker segment found */ private static final int POC_FOUND = 1<<10; /** Flag bit for COM marker segment found */ private static final int COM_FOUND = 1<<11; /** Flag bit for SOD marker segment found */ public static final int SOD_FOUND = 1<<13; /** Flag bit for SOD marker segment found */ public static final int PPM_FOUND = 1<<14; /** Flag bit for SOD marker segment found */ public static final int PPT_FOUND = 1<<15; /** Flag bit for CRG marker segment found */ public static final int CRG_FOUND = 1<<16; /** The reset mask for new tiles */ private static final int TILE_RESET = ~(PLM_FOUND|SIZ_FOUND|RGN_FOUND); /** HashTable used to store marker segment byte buffers */ private Hashtable ht = null; /** The number of components in the image */ private int nComp; /** The horizontal code-block partition origin */ private int cb0x = -1; /** The vertical code-block partition origin */ private int cb0y = -1; /** The decoder specifications */ private DecoderSpecs decSpec; /** Is the precinct partition used */ boolean precinctPartitionIsUsed; /** The offset of the main header in the input stream */ public int mainHeadOff; /** Vector containing info as to which tile each tilepart belong */ public Vector tileOfTileParts; /** Array containing the Nppm and Ippm fields of the PPM marker segments*/ private byte[][] pPMMarkerData; /** Array containing the Ippm fields of the PPT marker segments */ private byte[][][][] tilePartPkdPktHeaders; /** The packed packet headers if the PPM or PPT markers are used */ private ByteArrayOutputStream[] pkdPktHeaders; /** * Return the maximum height among all components * * @return Maximum component height * */ public int getMaxCompImgHeight() { return hi.siz.getMaxCompHeight(); } /** * Return the maximum width among all components * * @return Maximum component width * */ public int getMaxCompImgWidth() { return hi.siz.getMaxCompWidth(); } /** * Returns the image width in the reference grid. * * @return The image width in the reference grid * */ public final int getImgWidth() { return hi.siz.xsiz-hi.siz.x0siz; } /** * Returns the image height in the reference grid. * * @return The image height in the reference grid * */ public final int getImgHeight() { return hi.siz.ysiz-hi.siz.y0siz; } /** * Return the horizontal upper-left coordinate of the image in the * reference grid. * * @return The horizontal coordinate of the image origin. * */ public final int getImgULX() { return hi.siz.x0siz; } /** * Return the vertical upper-left coordinate of the image in the reference * grid. * * @return The vertical coordinate of the image origin. * */ public final int getImgULY() { return hi.siz.y0siz; } /** * Returns the nominal width of the tiles in the reference grid. * * @return The nominal tile width, in the reference grid. * */ public final int getNomTileWidth() { return hi.siz.xtsiz; } /** * Returns the nominal width of the tiles in the reference grid. * * @return The nominal tile width, in the reference grid. * */ public final int getNomTileHeight() { return hi.siz.ytsiz; } /** * Returns the tiling origin, referred to as '(Px,Py)' in the 'ImgData' * interface. * * @param co If not null this object is used to return the information. If * null a new one is created and returned. * * @return The coordinate of the tiling origin, in the canvas system, on * the reference grid. * * @see jj2000.j2k.image.ImgData * */ public final Point getTilingOrigin(Point co) { if (co != null) { co.x = hi.siz.xt0siz; co.y = hi.siz.yt0siz; return co; } else { return new Point(hi.siz.xt0siz,hi.siz.yt0siz); } } /** * Returns true if the original data of the specified component was * signed. If the data was not signed a level shift has to be applied at * the end of the decompression chain. * * @param c The index of the component * * @return True if the original image component was signed. * */ public final boolean isOriginalSigned(int c) { return hi.siz.isOrigSigned(c); } /** * Returns the original bitdepth of the specified component. * * @param c The index of the component * * @return The bitdepth of the component * */ public final int getOriginalBitDepth(int c) { return hi.siz.getOrigBitDepth(c); } /** * Returns the number of components in the image. * * @return The number of components in the image. * */ public final int getNumComps() { return nComp; } /** * Returns the component sub-sampling factor, with respect to the * reference grid, along the horizontal direction for the specified * component. * * @param c The index of the component * * @return The component sub-sampling factor X-wise. * */ public final int getCompSubsX(int c) { return hi.siz.xrsiz[c]; } /** * Returns the component sub-sampling factor, with respect to the * reference grid, along the vertical direction for the specified * component. * * @param c The index of the component * * @return The component sub-sampling factor Y-wise. * */ public final int getCompSubsY(int c) { return hi.siz.yrsiz[c]; } /** * Returns the dequantizer parameters. Dequantizer parameters normally are * the quantization step sizes, see DequantizerParams. * * @param src The source of data for the dequantizer. * * @param rb The number of range bits for each component. Must be * the number of range bits of the mixed components. * * @param decSpec2 The DecoderSpecs instance after any image manipulation. * * @return The dequantizer * */ public final Dequantizer createDequantizer(CBlkQuantDataSrcDec src, int rb[], DecoderSpecs decSpec2) { return new StdDequantizer(src,rb,decSpec2); } /** * Returns the horizontal code-block partition origin.Allowable values are * 0 and 1, nothing else. * */ public final int getCbULX() { return cb0x; } /** * Returns the vertical code-block partition origin. Allowable values are * 0 and 1, nothing else. * */ public final int getCbULY() { return cb0y; } /** * Returns the precinct partition width for the specified tile-component * and resolution level. * * @param c the component index * * @param t the tile index * * @param rl the resolution level * * @return The precinct partition width for the specified tile-component * and resolution level * */ public final int getPPX(int t,int c,int rl) { return decSpec.pss.getPPX(t,c,rl); } /** * Returns the precinct partition height for the specified component, tile * and resolution level. * * @param c the component * * @param t the tile index * * @param rl the resolution level * * @return The precinct partition height for the specified component, * tile and resolution level * */ public final int getPPY(int t, int c, int rl) { return decSpec.pss.getPPY(t, c, rl); } /** * Returns the boolean used to know if the precinct partition is used **/ public final boolean precinctPartitionUsed() { return precinctPartitionIsUsed; } /** * Reads a wavelet filter from the codestream and returns the filter * object that implements it. * * @param ehs The encoded header stream from where to read the info * * @param filtIdx Int array of one element to return the type of the * wavelet filter. * */ private SynWTFilter readFilter(DataInputStream ehs,int[] filtIdx) throws IOException { int kid; // the filter id kid = filtIdx[0] = ehs.readUnsignedByte(); if (kid >= (1<<7)) { throw new NotImplementedError("Custom filters not supported"); } // Return filter based on ID switch (kid) { case FilterTypes.W9X7: return new SynWTFilterFloatLift9x7(); case FilterTypes.W5X3: return new SynWTFilterIntLift5x3(); default: throw new CorruptedCodestreamException("Specified wavelet filter "+ "not"+ " JPEG 2000 part I "+ "compliant"); } } /** * Checks that the marker segment length is correct. * * @param ehs The encoded header stream * * @param str The string identifying the marker, such as "SIZ marker" * * @exception IOException If an I/O error occurs * */ public void checkMarkerLength(DataInputStream ehs, String str) throws IOException { if (ehs.available()!=0) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING, str+" length was short, attempting to resync."); } } /** * Reads the SIZ marker segment and realigns the codestream at the point * where the next marker segment should be found. * * <p>SIZ is a fixed information marker segment containing informations * about image and tile sizes. It is required in the main header * immediately after SOC.</p> * * @param ehs The encoded header stream * * @exception IOException If an I/O error occurs while reading from the * encoded header stream * */ private void readSIZ (DataInputStream ehs) throws IOException { HeaderInfo.SIZ ms = hi.getNewSIZ(); hi.siz = ms; // Read the length of SIZ marker segment (Lsiz) ms.lsiz = ehs.readUnsignedShort(); // Read the capability of the codestream (Rsiz) ms.rsiz = ehs.readUnsignedShort(); if (ms.rsiz > 2) { throw new Error("Codestream capabiities not JPEG 2000 - Part I"+ " compliant"); } // Read image size ms.xsiz = ehs.readInt(); ms.ysiz = ehs.readInt(); if ( ms.xsiz<=0 || ms.ysiz<=0 ) { throw new IOException("JJ2000 does not support images whose "+ "width and/or height not in the "+ "range: 1 -- (2^31)-1"); } // Read image offset ms.x0siz = ehs.readInt(); ms.y0siz = ehs.readInt(); if ( ms.x0siz<0 || ms.y0siz<0 ) { throw new IOException("JJ2000 does not support images offset "+ "not in the range: 0 -- (2^31)-1"); } // Read size of tile ms.xtsiz = ehs.readInt(); ms.ytsiz = ehs.readInt(); if ( ms.xtsiz<=0 || ms.ytsiz<=0 ) { throw new IOException("JJ2000 does not support tiles whose "+ "width and/or height are not in "+ "the range: 1 -- (2^31)-1"); } // Read upper-left tile offset ms.xt0siz = ehs.readInt(); ms.yt0siz = ehs.readInt(); if ( ms.xt0siz<0 || ms.yt0siz<0 ){ throw new IOException("JJ2000 does not support tiles whose "+ "offset is not in "+ "the range: 0 -- (2^31)-1"); } // Read number of components and initialize related arrays nComp = ms.csiz = ehs.readUnsignedShort(); if (nComp<1 || nComp>16384) { throw new IllegalArgumentException("Number of component out of "+ "range 1--16384: "+nComp); } ms.ssiz = new int[nComp]; ms.xrsiz = new int[nComp]; ms.yrsiz = new int[nComp]; // Read bit-depth and down-sampling factors of each component for(int i = 0; i<nComp; i++) { ms.ssiz[i] = ehs.readUnsignedByte(); ms.xrsiz[i] = ehs.readUnsignedByte(); ms.yrsiz[i] = ehs.readUnsignedByte(); } // Check marker length checkMarkerLength(ehs,"SIZ marker"); // Create needed ModuleSpec nTiles = ms.getNumTiles(); // Finish initialization of decSpec decSpec = new DecoderSpecs(nTiles,nComp); } /** * Reads a CRG marker segment and checks its length. CRG is an * informational marker segment that allows specific registration of * components with respect to each other. * * @param ehs The encoded header stream * */ private void readCRG (DataInputStream ehs) throws IOException { HeaderInfo.CRG ms = hi.getNewCRG(); hi.crg = ms; ms.lcrg = ehs.readUnsignedShort(); ms.xcrg = new int[nComp]; ms.ycrg = new int[nComp]; FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Information in CRG marker segment "+ "not taken into account. This may affect the display "+ "of the decoded image."); for(int c=0; c<nComp; c++) { ms.xcrg[c] = ehs.readUnsignedShort(); ms.ycrg[c] = ehs.readUnsignedShort(); } // Check marker length checkMarkerLength(ehs,"CRG marker"); } /** * Reads a COM marker segments and realigns the bit stream at the point * where the next marker segment should be found. COM is an informational * marker segment that allows to include unstructured data in the main and * tile-part headers. * * @param ehs The encoded header stream * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param comIdx Occurence of this COM marker in eith main or tile-part * header * * @exception IOException If an I/O error occurs while reading from the * encoded header stream * */ private void readCOM (DataInputStream ehs, boolean mainh, int tileIdx, int comIdx) throws IOException { HeaderInfo.COM ms = hi.getNewCOM(); // Read length of COM field ms.lcom = ehs.readUnsignedShort(); // Read the registration value of the COM marker segment ms.rcom = ehs.readUnsignedShort(); switch(ms.rcom) { case RCOM_GEN_USE: ms.ccom = new byte[ms.lcom-4]; for(int i=0; i<ms.lcom-4; i++) { ms.ccom[i] = ehs.readByte(); } break; default: // --- Unknown or unsupported markers --- // (skip them and see if we can get way with it) FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING, "COM marker registered as 0x"+Integer. toHexString(ms.rcom)+ " unknown, ignoring (this might crash the "+ "decoder or decode a quality degraded or even "+ "useless image)"); ehs.skipBytes(ms.lcom-4); //Ignore this field for the moment break; } if (mainh) { hi.com.put("main_"+comIdx,ms); } else { hi.com.put("t"+tileIdx+"_"+comIdx,ms); } // Check marker length checkMarkerLength(ehs,"COM marker"); } /** * Reads a QCD marker segment and realigns the codestream at the point * where the next marker should be found. QCD is a functional marker * segment that describes the quantization default. * * @param ehs The encoded stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoded header stream. * */ private void readQCD (DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { StdDequantizerParams qParms; int guardBits; int[][] exp; float[][] nStep = null; HeaderInfo.QCD ms = hi.getNewQCD(); // Lqcd (length of QCD field) ms.lqcd = ehs.readUnsignedShort(); // Sqcd (quantization style) ms.sqcd = ehs.readUnsignedByte(); guardBits = ms.getNumGuardBits(); int qType = ms.getQuantType(); if(mainh){ hi.qcd.put("main",ms); // If the main header is being read set default value of // dequantization spec switch (qType) { case SQCX_NO_QUANTIZATION: decSpec.qts.setDefault("reversible"); break; case SQCX_SCALAR_DERIVED: decSpec.qts.setDefault("derived"); break; case SQCX_SCALAR_EXPOUNDED: decSpec.qts.setDefault("expounded"); break; default: throw new CorruptedCodestreamException("Unknown or "+ "unsupported "+ "quantization style "+ "in Sqcd field, QCD "+ "marker main header"); } } else { hi.qcd.put("t"+tileIdx,ms); // If the tile header is being read set default value of // dequantization spec for tile switch (qType) { case SQCX_NO_QUANTIZATION: decSpec.qts.setTileDef(tileIdx, "reversible"); break; case SQCX_SCALAR_DERIVED: decSpec.qts.setTileDef(tileIdx, "derived"); break; case SQCX_SCALAR_EXPOUNDED: decSpec.qts.setTileDef(tileIdx, "expounded"); break; default: throw new CorruptedCodestreamException("Unknown or "+ "unsupported "+ "quantization style "+ "in Sqcd field, QCD "+ "marker, tile header"); } } qParms = new StdDequantizerParams(); if(qType == SQCX_NO_QUANTIZATION) { int maxrl = ( mainh ? ((Integer)decSpec.dls.getDefault()).intValue() : ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue()); int i,j,rl; int minb,maxb,hpd; int tmp; exp = qParms.exp = new int[maxrl+1][]; ms.spqcd = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level exp[rl] = new int[maxb]; for(j=minb; j<maxb; j++) { tmp = ms.spqcd[rl][j] = ehs.readUnsignedByte(); exp[rl][j] = (tmp>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK; } }// end for rl } else { int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 : ( mainh ? ((Integer)decSpec.dls.getDefault()).intValue() : ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue()); int i,j,rl; int minb,maxb,hpd; int tmp; exp = qParms.exp = new int[maxrl+1][]; nStep = qParms.nStep = new float[maxrl+1][]; ms.spqcd = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level exp[rl] = new int[maxb]; nStep[rl] = new float[maxb]; for(j=minb; j<maxb; j++) { tmp = ms.spqcd[rl][j] = ehs.readUnsignedShort(); exp[rl][j] = (tmp>>11) & 0x1f; // NOTE: the formula below does not support more than 5 // bits for the exponent, otherwise (-1<<exp) might // overflow (the - is used to be able to represent 2**31) nStep[rl][j] = (-1f-((float)(tmp & 0x07ff))/(1<<11))/ (-1<<exp[rl][j]); } }// end for rl } // end if (qType != SQCX_NO_QUANTIZATION) // Fill qsss, gbs if(mainh){ decSpec.qsss.setDefault(qParms); decSpec.gbs.setDefault(new Integer(guardBits)); } else{ decSpec.qsss.setTileDef(tileIdx,qParms); decSpec.gbs.setTileDef(tileIdx,new Integer(guardBits)); } // Check marker length checkMarkerLength(ehs,"QCD marker"); } /** * Reads a QCC marker segment and realigns the codestream at the point * where the next marker should be found. QCC is a functional marker * segment that describes the quantization of one component. * * @param ehs The encoded stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoded header stream. * */ private void readQCC (DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { int cComp; // current component int tmp; StdDequantizerParams qParms; int[][] expC; float[][] nStepC = null; HeaderInfo.QCC ms = hi.getNewQCC(); // Lqcc (length of QCC field) ms.lqcc = ehs.readUnsignedShort(); // Cqcc if (nComp < 257) { cComp = ms.cqcc = ehs.readUnsignedByte(); } else { cComp = ms.cqcc = ehs.readUnsignedShort(); } if (cComp >= nComp) { throw new CorruptedCodestreamException("Invalid component "+ "index in QCC marker"); } // Sqcc (quantization style) ms.sqcc = ehs.readUnsignedByte(); int guardBits = ms.getNumGuardBits(); int qType = ms.getQuantType(); if(mainh) { hi.qcc.put("main_c"+cComp,ms); // If main header is being read, set default for component in all // tiles switch (qType) { case SQCX_NO_QUANTIZATION: decSpec.qts.setCompDef(cComp,"reversible"); break; case SQCX_SCALAR_DERIVED: decSpec.qts.setCompDef(cComp,"derived"); break; case SQCX_SCALAR_EXPOUNDED: decSpec.qts.setCompDef(cComp,"expounded"); break; default: throw new CorruptedCodestreamException("Unknown or "+ "unsupported "+ "quantization style "+ "in Sqcd field, QCD "+ "marker, main header"); } } else { hi.qcc.put("t"+tileIdx+"_c"+cComp,ms); // If tile header is being read, set value for component in // this tiles switch (qType) { case SQCX_NO_QUANTIZATION: decSpec.qts.setTileCompVal(tileIdx, cComp,"reversible"); break; case SQCX_SCALAR_DERIVED: decSpec.qts.setTileCompVal(tileIdx, cComp,"derived"); break; case SQCX_SCALAR_EXPOUNDED: decSpec.qts.setTileCompVal(tileIdx, cComp,"expounded"); break; default: throw new CorruptedCodestreamException("Unknown or "+ "unsupported "+ "quantization style "+ "in Sqcd field, QCD "+ "marker, main header"); } } // Decode all dequantizer params qParms = new StdDequantizerParams(); if (qType == SQCX_NO_QUANTIZATION) { int maxrl = ( mainh ? ((Integer)decSpec.dls.getCompDef(cComp)).intValue() : ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)). intValue()); int i,j,rl; int minb,maxb,hpd; expC = qParms.exp = new int[maxrl+1][]; ms.spqcc = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level expC[rl] = new int[maxb]; for(j=minb; j<maxb; j++) { tmp = ms.spqcc[rl][j] = ehs.readUnsignedByte(); expC[rl][j] = (tmp>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK; } }// end for rl } else { int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 : ( mainh ? ((Integer)decSpec.dls.getCompDef(cComp)).intValue() : ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)). intValue()); int i,j,rl; int minb,maxb,hpd; nStepC = qParms.nStep = new float[maxrl+1][]; expC = qParms.exp = new int[maxrl+1][]; ms.spqcc = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level expC[rl] = new int[maxb]; nStepC[rl] = new float[maxb]; for(j=minb; j<maxb; j++) { tmp = ms.spqcc[rl][j] = ehs.readUnsignedShort(); expC[rl][j] = (tmp>>11) & 0x1f; // NOTE: the formula below does not support more than 5 // bits for the exponent, otherwise (-1<<exp) might // overflow (the - is used to be able to represent 2**31) nStepC[rl][j] = (-1f-((float)(tmp & 0x07ff))/(1<<11))/ (-1<<expC[rl][j]); } }// end for rl } // end if (qType != SQCX_NO_QUANTIZATION) // Fill qsss, gbs if(mainh){ decSpec.qsss.setCompDef(cComp,qParms); decSpec.gbs.setCompDef(cComp,new Integer(guardBits)); } else{ decSpec.qsss.setTileCompVal(tileIdx,cComp,qParms); decSpec.gbs.setTileCompVal(tileIdx,cComp,new Integer(guardBits)); } // Check marker length checkMarkerLength(ehs,"QCC marker"); } /** * Reads a COD marker segment and realigns the codestream where the next * marker should be found. * * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readCOD (DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { int cstyle; // The block style SynWTFilter hfilters[],vfilters[]; int l; Integer cblk[]; String errMsg; boolean sopUsed = false; boolean ephUsed = false; HeaderInfo.COD ms = hi.getNewCOD(); // Lcod (marker length) ms.lcod = ehs.readUnsignedShort(); // Scod (block style) // We only support wavelet transformed data cstyle = ms.scod = ehs.readUnsignedByte(); if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){ precinctPartitionIsUsed = true; // Remove flag cstyle &= ~(SCOX_PRECINCT_PARTITION); } else { precinctPartitionIsUsed = false; } // SOP markers if (mainh) { hi.cod.put("main",ms); if( (cstyle&SCOX_USE_SOP) != 0 ){ // SOP markers are used decSpec.sops.setDefault(new Boolean("true")); sopUsed = true; // Remove flag cstyle &= ~(SCOX_USE_SOP); } else { // SOP markers are not used decSpec.sops.setDefault(new Boolean("false")); } } else { hi.cod.put("t"+tileIdx,ms); if( (cstyle&SCOX_USE_SOP) != 0 ){ // SOP markers are used decSpec.sops.setTileDef(tileIdx, new Boolean("true")); sopUsed = true; // Remove flag cstyle &= ~(SCOX_USE_SOP); } else { // SOP markers are not used decSpec.sops.setTileDef(tileIdx, new Boolean("false")); } } // EPH markers if (mainh) { if( (cstyle&SCOX_USE_EPH) != 0 ){ // EPH markers are used decSpec.ephs.setDefault(new Boolean("true")); ephUsed = true; // Remove flag cstyle &= ~(SCOX_USE_EPH); } else { // EPH markers are not used decSpec.ephs.setDefault(new Boolean("false")); } } else { if( (cstyle&SCOX_USE_EPH) != 0 ){ // EPH markers are used decSpec.ephs.setTileDef(tileIdx, new Boolean("true")); ephUsed = true; // Remove flag cstyle &= ~(SCOX_USE_EPH); } else { // EPH markers are not used decSpec.ephs.setTileDef(tileIdx, new Boolean("false")); } } // Code-block partition origin if( (cstyle&(SCOX_HOR_CB_PART|SCOX_VER_CB_PART)) != 0) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Code-block partition origin "+ "different from (0,0). This is defined in JPEG 2000"+ " part 2 and may not be supported by all JPEG "+ "2000 decoders."); } if( (cstyle&SCOX_HOR_CB_PART)!= 0) { if(cb0x!=-1 && cb0x==0) { throw new IllegalArgumentException("Code-block partition "+ "origin redefined in new"+ " COD marker segment. Not"+ " supported by JJ2000"); } cb0x = 1; cstyle &= ~(SCOX_HOR_CB_PART); } else { if(cb0x!=-1 && cb0x==1) { throw new IllegalArgumentException("Code-block partition "+ "origin redefined in new"+ " COD marker segment. Not"+ " supported by JJ2000"); } cb0x = 0; } if( (cstyle&SCOX_VER_CB_PART)!= 0) { if(cb0y!=-1 && cb0y==0) { throw new IllegalArgumentException("Code-block partition "+ "origin redefined in new"+ " COD marker segment. Not"+ " supported by JJ2000"); } cb0y = 1; cstyle &= ~(SCOX_VER_CB_PART); } else { if(cb0y!=-1 && cb0y==1) { throw new IllegalArgumentException("Code-block partition "+ "origin redefined in new"+ " COD marker segment. Not"+ " supported by JJ2000"); } cb0y = 0; } // SGcod // Read the progressive order ms.sgcod_po = ehs.readUnsignedByte(); // Read the number of layers ms.sgcod_nl = ehs.readUnsignedShort(); if (ms.sgcod_nl<=0 || ms.sgcod_nl>65535 ) { throw new CorruptedCodestreamException("Number of layers out of "+ "range: 1--65535"); } // Multiple component transform ms.sgcod_mct = ehs.readUnsignedByte(); // SPcod // decomposition levels int mrl = ms.spcod_ndl = ehs.readUnsignedByte(); if( mrl>32 ){ throw new CorruptedCodestreamException("Number of decomposition "+ "levels out of range: "+ "0--32"); } // Read the code-blocks dimensions cblk = new Integer[2]; ms.spcod_cw = ehs.readUnsignedByte(); cblk[0] = new Integer(1<<(ms.spcod_cw+2)); if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block width in SPcod field, "+ "COD marker"; throw new CorruptedCodestreamException(errMsg); } ms.spcod_ch = ehs.readUnsignedByte(); cblk[1] = new Integer(1<<(ms.spcod_ch+2)); if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block height in SPcod field, "+ "COD marker"; throw new CorruptedCodestreamException(errMsg); } if ( (cblk[0].intValue()*cblk[1].intValue()) > StdEntropyCoderOptions.MAX_CB_AREA ) { errMsg = "Non-valid code-block area in SPcod field, "+ "COD marker"; throw new CorruptedCodestreamException(errMsg); } if ( mainh ) { decSpec.cblks.setDefault(cblk); } else { decSpec.cblks.setTileDef(tileIdx, cblk); } // Style of the code-block coding passes int ecOptions = ms.spcod_cs = ehs.readUnsignedByte(); if ((ecOptions & ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS| OPT_VERT_STR_CAUSAL|OPT_PRED_TERM | OPT_SEG_SYMBOLS)) != 0){ throw new CorruptedCodestreamException("Unknown \"code-block "+ "style\" in SPcod field, "+ "COD marker: 0x"+ Integer. toHexString(ecOptions)); } // Read wavelet filter for tile or image hfilters = new SynWTFilter[1]; vfilters = new SynWTFilter[1]; hfilters[0] = readFilter(ehs,ms.spcod_t); vfilters[0] = hfilters[0]; // Fill the filter spec // If this is the main header, set the default value, if it is the // tile header, set default for this tile SynWTFilter[][] hvfilters = new SynWTFilter[2][]; hvfilters[0]=hfilters; hvfilters[1]=vfilters; // Get precinct partition sizes Vector v[] = new Vector[2]; v[0] = new Vector(); v[1] = new Vector(); int val = PRECINCT_PARTITION_DEF_SIZE; if ( !precinctPartitionIsUsed ) { Integer w, h; w = new Integer(1<<(val & 0x000F)); v[0].addElement(w); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].addElement(h); } else { ms.spcod_ps = new int[mrl+1]; for (int rl=mrl ;rl>=0 ;rl--) { Integer w, h; val = ms.spcod_ps[mrl-rl] = ehs.readUnsignedByte(); w = new Integer(1<<(val & 0x000F)); v[0].insertElementAt(w,0); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].insertElementAt(h,0); } } if (mainh) { decSpec.pss.setDefault(v); } else { decSpec.pss.setTileDef(tileIdx, v); } precinctPartitionIsUsed = true; // Check marker length checkMarkerLength(ehs,"COD marker"); // Store specifications in decSpec if(mainh){ decSpec.wfs.setDefault(hvfilters); decSpec.dls.setDefault(new Integer(mrl)); decSpec.ecopts.setDefault(new Integer(ecOptions)); decSpec.cts.setDefault(new Integer(ms.sgcod_mct)); decSpec.nls.setDefault(new Integer(ms.sgcod_nl)); decSpec.pos.setDefault(new Integer(ms.sgcod_po)); } else{ decSpec.wfs.setTileDef(tileIdx, hvfilters); decSpec.dls.setTileDef(tileIdx,new Integer(mrl)); decSpec.ecopts.setTileDef(tileIdx,new Integer(ecOptions)); decSpec.cts.setTileDef(tileIdx,new Integer(ms.sgcod_mct)); decSpec.nls.setTileDef(tileIdx,new Integer(ms.sgcod_nl)); decSpec.pos.setTileDef(tileIdx,new Integer(ms.sgcod_po)); } } /** * Reads the COC marker segment and realigns the codestream where the next * marker should be found. * * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readCOC (DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { int cComp; // current component SynWTFilter hfilters[],vfilters[]; int tmp,l; int ecOptions; Integer cblk[]; String errMsg; HeaderInfo.COC ms = hi.getNewCOC(); // Lcoc (marker length) ms.lcoc = ehs.readUnsignedShort(); // Ccoc if (nComp < 257) { cComp = ms.ccoc = ehs.readUnsignedByte(); } else { cComp = ms.ccoc = ehs.readUnsignedShort(); } if (cComp >= nComp) { throw new CorruptedCodestreamException("Invalid component index "+ "in QCC marker"); } // Scoc (block style) int cstyle = ms.scoc = ehs.readUnsignedByte(); if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){ precinctPartitionIsUsed = true; // Remove flag cstyle &= ~(SCOX_PRECINCT_PARTITION); } else { precinctPartitionIsUsed = false; } // SPcoc // decomposition levels int mrl = ms.spcoc_ndl = ehs.readUnsignedByte(); // Read the code-blocks dimensions cblk = new Integer[2]; ms.spcoc_cw = ehs.readUnsignedByte(); cblk[0] = new Integer(1<<(ms.spcoc_cw+2)); if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block width in SPcod field, "+ "COC marker"; throw new CorruptedCodestreamException(errMsg); } ms.spcoc_ch = ehs.readUnsignedByte(); cblk[1] = new Integer(1<<(ms.spcoc_ch+2)); if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block height in SPcod field, "+ "COC marker"; throw new CorruptedCodestreamException(errMsg); } if ( (cblk[0].intValue()*cblk[1].intValue()) > StdEntropyCoderOptions.MAX_CB_AREA ) { errMsg = "Non-valid code-block area in SPcod field, "+ "COC marker"; throw new CorruptedCodestreamException(errMsg); } if ( mainh ) { decSpec.cblks.setCompDef(cComp,cblk); } else { decSpec.cblks.setTileCompVal(tileIdx,cComp,cblk); } // Read entropy block mode options // NOTE: currently OPT_SEG_SYMBOLS is not included here ecOptions = ms.spcoc_cs = ehs.readUnsignedByte(); if ((ecOptions & ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS| OPT_VERT_STR_CAUSAL|OPT_PRED_TERM|OPT_SEG_SYMBOLS)) != 0){ throw new CorruptedCodestreamException("Unknown \"code-block "+ "context\" in SPcoc field, "+ "COC marker: 0x"+ Integer. toHexString(ecOptions)); } // Read wavelet filter for tile or image hfilters = new SynWTFilter[1]; vfilters = new SynWTFilter[1]; hfilters[0] = readFilter(ehs,ms.spcoc_t); vfilters[0] = hfilters[0]; // Fill the filter spec // If this is the main header, set the default value, if it is the // tile header, set default for this tile SynWTFilter[][] hvfilters = new SynWTFilter[2][]; hvfilters[0]=hfilters; hvfilters[1]=vfilters; // Get precinct partition sizes Vector v[] = new Vector[2]; v[0] = new Vector(); v[1] = new Vector(); int val = PRECINCT_PARTITION_DEF_SIZE; if ( !precinctPartitionIsUsed ) { Integer w, h; w = new Integer(1<<(val & 0x000F)); v[0].addElement(w); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].addElement(h); } else { ms.spcoc_ps = new int[mrl+1]; for ( int rl=mrl ; rl>=0 ; rl-- ) { Integer w, h; val = ms.spcoc_ps[rl] = ehs.readUnsignedByte(); w = new Integer(1<<(val & 0x000F)); v[0].insertElementAt(w,0); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].insertElementAt(h,0); } } if (mainh) { decSpec.pss.setCompDef(cComp,v); } else { decSpec.pss.setTileCompVal(tileIdx,cComp,v); } precinctPartitionIsUsed = true; // Check marker length checkMarkerLength(ehs,"COD marker"); if(mainh){ hi.coc.put("main_c"+cComp,ms); decSpec.wfs.setCompDef(cComp,hvfilters); decSpec.dls.setCompDef(cComp,new Integer(mrl)); decSpec.ecopts.setCompDef(cComp,new Integer(ecOptions)); } else { hi.coc.put("t"+tileIdx+"_c"+cComp,ms); decSpec.wfs.setTileCompVal(tileIdx,cComp,hvfilters); decSpec.dls.setTileCompVal(tileIdx,cComp,new Integer(mrl)); decSpec.ecopts.setTileCompVal(tileIdx,cComp, new Integer(ecOptions)); } } /** * Reads the POC marker segment and realigns the codestream where the next * marker should be found. * * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param t The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPOC(DataInputStream ehs,boolean mainh,int t,int tpIdx) throws IOException { boolean useShort = (nComp>=256) ? true : false; int tmp; int nOldChg = 0; HeaderInfo.POC ms; if(mainh || hi.poc.get("t"+t)==null) { ms = hi.getNewPOC(); } else { ms = (HeaderInfo.POC)hi.poc.get("t"+t); nOldChg = ms.rspoc.length; } // Lpoc ms.lpoc = ehs.readUnsignedShort(); // Compute the number of new progression changes // newChg = (lpoc - Lpoc(2)) / (RSpoc(1) + CSpoc(2) + // LYEpoc(2) + REpoc(1) + CEpoc(2) + Ppoc (1) ) int newChg = (ms.lpoc-2)/(5+ (useShort?4:2)); int ntotChg = nOldChg+newChg; int[][] change; if(nOldChg!=0) { // Creates new arrays change = new int[ntotChg][6]; int[] tmprspoc = new int[ntotChg]; int[] tmpcspoc = new int[ntotChg]; int[] tmplyepoc = new int[ntotChg]; int[] tmprepoc = new int[ntotChg]; int[] tmpcepoc = new int[ntotChg]; int[] tmpppoc = new int[ntotChg]; // Copy old values int[][] prevChg = (int[][])decSpec.pcs.getTileDef(t); for(int chg=0; chg<nOldChg; chg++) { change[chg] = prevChg[chg]; tmprspoc[chg] = ms.rspoc[chg]; tmpcspoc[chg] = ms.cspoc[chg]; tmplyepoc[chg] = ms.lyepoc[chg]; tmprepoc[chg] = ms.repoc[chg]; tmpcepoc[chg] = ms.cepoc[chg]; tmpppoc[chg] = ms.ppoc[chg]; } ms.rspoc = tmprspoc; ms.cspoc = tmpcspoc; ms.lyepoc = tmplyepoc; ms.repoc = tmprepoc; ms.cepoc = tmpcepoc; ms.ppoc = tmpppoc; } else { change = new int[newChg][6]; ms.rspoc = new int[newChg]; ms.cspoc = new int[newChg]; ms.lyepoc = new int[newChg]; ms.repoc = new int[newChg]; ms.cepoc = new int[newChg]; ms.ppoc = new int[newChg]; } for(int chg=nOldChg; chg<ntotChg; chg++) { // RSpoc change[chg][0] = ms.rspoc[chg] = ehs.readUnsignedByte(); // CSpoc if(useShort) { change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedShort(); } else { change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedByte(); } // LYEpoc change[chg][2] = ms.lyepoc[chg] = ehs.readUnsignedShort(); if(change[chg][2]<1) { throw new CorruptedCodestreamException ("LYEpoc value must be greater than 1 in POC marker "+ "segment of tile "+t+", tile-part "+tpIdx); } // REpoc change[chg][3] = ms.repoc[chg] = ehs.readUnsignedByte(); if(change[chg][3]<=change[chg][0]) { throw new CorruptedCodestreamException ("REpoc value must be greater than RSpoc in POC marker "+ "segment of tile "+t+", tile-part "+tpIdx); } // CEpoc if(useShort) { change[chg][4] = ms.cepoc[chg] = ehs.readUnsignedShort(); } else { tmp = ms.cepoc[chg] = ehs.readUnsignedByte(); if(tmp==0) { change[chg][4] = 0; } else { change[chg][4] = tmp; } } if(change[chg][4]<=change[chg][1]) { throw new CorruptedCodestreamException ("CEpoc value must be greater than CSpoc in POC marker "+ "segment of tile "+t+", tile-part "+tpIdx); } // Ppoc change[chg][5] = ms.ppoc[chg] = ehs.readUnsignedByte(); } // Check marker length checkMarkerLength(ehs,"POC marker"); // Register specifications if(mainh) { hi.poc.put("main",ms); decSpec.pcs.setDefault(change); } else { hi.poc.put("t"+t,ms); decSpec.pcs.setTileDef(t,change); } } /** * Reads TLM marker segment and realigns the codestream where the next * marker should be found. Informations stored in these fields are * currently NOT taken into account. * * @param ehs The encoder header stream. * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readTLM(DataInputStream ehs) throws IOException { int length; length = ehs.readUnsignedShort(); //Ignore all informations contained ehs.skipBytes(length-2); FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,"Skipping unsupported TLM marker"); } /** * Reads PLM marker segment and realigns the codestream where the next * marker should be found. Informations stored in these fields are * currently not taken into account. * * @param ehs The encoder header stream. * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPLM(DataInputStream ehs) throws IOException{ int length; length = ehs.readUnsignedShort(); //Ignore all informations contained ehs.skipBytes(length-2); FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,"Skipping unsupported PLM marker"); } /** * Reads the PLT fields and realigns the codestream where the next marker * should be found. Informations stored in these fields are currently NOT * taken into account. * * @param ehs The encoder header stream. * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPLTFields(DataInputStream ehs) throws IOException{ int length; length = ehs.readUnsignedShort(); //Ignore all informations contained ehs.skipBytes(length-2); FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,"Skipping unsupported PLT marker"); } /** * Reads the RGN marker segment of the codestream header. * * <p>May be used in tile or main header. If used in main header, it * refers to the maxshift value of a component in all tiles. When used in * tile header, only the particular tile-component is affected.</p> * * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readRGN(DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { int comp; // ROI component int i; // loop variable int tempComp; // Component for HeaderInfo.RGN ms = hi.getNewRGN(); // Lrgn (marker length) ms.lrgn = ehs.readUnsignedShort(); // Read component ms.crgn = comp = (nComp < 257) ? ehs.readUnsignedByte(): ehs.readUnsignedShort(); if (comp >= nComp) { throw new CorruptedCodestreamException("Invalid component "+ "index in RGN marker"+ comp); } // Read type of RGN.(Srgn) ms.srgn = ehs.readUnsignedByte(); // Check that we can handle it. if(ms.srgn != SRGN_IMPLICIT) throw new CorruptedCodestreamException("Unknown or unsupported "+ "Srgn parameter in ROI "+ "marker"); if(decSpec.rois==null) { // No maxshift spec defined // Create needed ModuleSpec decSpec.rois=new MaxShiftSpec(nTiles,nComp, ModuleSpec.SPEC_TYPE_TILE_COMP, "null"); } // SPrgn ms.sprgn = ehs.readUnsignedByte(); if(mainh) { hi.rgn.put("main_c"+comp,ms); decSpec.rois.setCompDef(comp, new Integer(ms.sprgn)); } else { hi.rgn.put("t"+tileIdx+"_c"+comp,ms); decSpec.rois.setTileCompVal(tileIdx,comp,new Integer(ms.sprgn)); } // Check marker length checkMarkerLength(ehs,"RGN marker"); } /** * Reads the PPM marker segment of the main header. * * @param ehs The encoder header stream. * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPPM(DataInputStream ehs) throws IOException { int curMarkSegLen; int i,indx,len,off; int remSegLen; byte[] b; // If first time readPPM method is called allocate arrays for packed // packet data if(pPMMarkerData==null) { pPMMarkerData = new byte[nPPMMarkSeg][]; tileOfTileParts = new Vector(); decSpec.pphs.setDefault(new Boolean(true)); } // Lppm (marker length) curMarkSegLen = ehs.readUnsignedShort(); remSegLen = curMarkSegLen - 3; // Zppm (index of PPM marker) indx = ehs.readUnsignedByte(); // Read Nppm and Ippm data pPMMarkerData[indx] = new byte[remSegLen]; ehs.read(pPMMarkerData[indx],0,remSegLen); // Check marker length checkMarkerLength(ehs,"PPM marker"); } /** * Teads the PPT marker segment of the main header. * * @param ehs The encoder header stream. * * @param tile The tile to which the current tile part belongs * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPPT(DataInputStream ehs,int tile,int tpIdx) throws IOException { int curMarkSegLen; int indx,len=0; byte[] temp; if(tilePartPkdPktHeaders == null){ tilePartPkdPktHeaders = new byte[nTiles][][][]; } if(tilePartPkdPktHeaders[tile] == null){ tilePartPkdPktHeaders[tile] = new byte[nTileParts[tile]][][]; } if(tilePartPkdPktHeaders[tile][tpIdx] == null){ tilePartPkdPktHeaders[tile][tpIdx] = new byte[nPPTMarkSeg[tile][tpIdx]][]; } // Lppt (marker length) curMarkSegLen = ehs.readUnsignedShort(); // Zppt (index of PPT marker) indx = ehs.readUnsignedByte(); // Ippt (packed packet headers) temp = new byte[curMarkSegLen-3]; ehs.read(temp); tilePartPkdPktHeaders[tile][tpIdx][indx]=temp; // Check marker length checkMarkerLength(ehs,"PPT marker"); decSpec.pphs.setTileDef(tile, new Boolean(true)); } /** * This method extract a marker segment from the main header and stores it * into a byte buffer for the second pass. The marker segment is first * identified. Then its flag is activated. Finally, its content is * buffered into a byte array stored in an hashTable. * * <p>If the marker is not recognized, it prints a warning and skips it * according to its length.</p> * * <p>SIZ marker segment shall be the first encountered marker segment.</p> * * @param marker The marker segment to process * * @param ehs The encoded header stream * */ private void extractMainMarkSeg(short marker,RandomAccessIO ehs) throws IOException { if(nfMarkSeg == 0) { // First non-delimiting marker of the header // JPEG 2000 part 1 specify that it must be SIZ if(marker != SIZ) { throw new CorruptedCodestreamException("First marker after "+ "SOC "+ "must be SIZ "+ Integer. toHexString(marker)); } } String htKey=""; // Name used as a key for the hash-table if(ht==null) { ht = new Hashtable(); } switch(marker){ case SIZ: if ((nfMarkSeg & SIZ_FOUND) != 0) { throw new CorruptedCodestreamException("More than one SIZ marker "+ "segment found in main "+ "header"); } nfMarkSeg |= SIZ_FOUND; htKey = "SIZ"; break; case SOD: throw new CorruptedCodestreamException("SOD found in main header"); case EOC: throw new CorruptedCodestreamException("EOC found in main header"); case SOT: if ((nfMarkSeg & SOT_FOUND) != 0) { throw new CorruptedCodestreamException("More than one SOT "+ "marker "+ "found right after "+ "main "+ "or tile header"); } nfMarkSeg |= SOT_FOUND; return; case COD: if((nfMarkSeg & COD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one COD "+ "marker "+ "found in main header"); } nfMarkSeg |= COD_FOUND; htKey = "COD"; break; case COC: nfMarkSeg |= COC_FOUND; htKey = "COC"+(nCOCMarkSeg++); break; case QCD: if((nfMarkSeg & QCD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one QCD "+ "marker "+ "found in main header"); } nfMarkSeg |= QCD_FOUND; htKey = "QCD"; break; case QCC: nfMarkSeg |= QCC_FOUND; htKey = "QCC"+(nQCCMarkSeg++); break; case RGN: nfMarkSeg |= RGN_FOUND; htKey = "RGN"+(nRGNMarkSeg++); break; case COM: nfMarkSeg |= COM_FOUND; htKey = "COM"+(nCOMMarkSeg++); break; case CRG: if((nfMarkSeg & CRG_FOUND) != 0) { throw new CorruptedCodestreamException("More than one CRG "+ "marker "+ "found in main header"); } nfMarkSeg |= CRG_FOUND; htKey = "CRG"; break; case PPM: nfMarkSeg |= PPM_FOUND; htKey = "PPM"+(nPPMMarkSeg++); break; case TLM: if((nfMarkSeg & TLM_FOUND) != 0) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO, "More than one TLM "+ "marker "+ "found in main header"); /** XXX It is legal to have multiple TLM segments. throw new CorruptedCodestreamException("More than one TLM "+ "marker "+ "found in main header"); */ } nfMarkSeg |= TLM_FOUND; break; case PLM: if((nfMarkSeg & PLM_FOUND) != 0) { throw new CorruptedCodestreamException("More than one PLM "+ "marker "+ "found in main header"); } FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"PLM marker segment found but "+ "not used by by JJ2000 decoder."); nfMarkSeg |= PLM_FOUND; htKey = "PLM"; break; case POC: if( (nfMarkSeg&POC_FOUND)!=0) { throw new CorruptedCodestreamException("More than one POC "+ "marker segment found "+ "in main header"); } nfMarkSeg |= POC_FOUND; htKey = "POC"; break; case PLT: throw new CorruptedCodestreamException("PLT found in main header"); case PPT: throw new CorruptedCodestreamException("PPT found in main header"); default: htKey = "UNKNOWN"; FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+ Integer.toHexString(marker)+") in main header!"); break; } if(marker < 0xffffff30 || marker > 0xffffff3f){ // Read marker segment length and create corresponding byte buffer int markSegLen = ehs.readUnsignedShort(); byte[] buf = new byte[markSegLen]; // Copy data (after re-insertion of the marker segment length); buf[0]= (byte)((markSegLen>>8) & 0xFF); buf[1]= (byte)(markSegLen & 0xFF); ehs.readFully(buf,2,markSegLen-2); if(!htKey.equals("UNKNOWN")) { // Store array in hashTable ht.put(htKey,buf); } } } /** * This method extracts a marker segment in a tile-part header and stores * it into a byte buffer for the second pass. The marker is first * recognized, then its flag is activated and, finally, its content is * buffered in an element of byte arrays accessible thanks to a hashTable. * If a marker segment is not recognized, it prints a warning and skip it * according to its length. * * @param marker The marker to process * * @param ehs The encoded header stream * * @param tileIdx The index of the current tile * * @param tilePartIdx The index of the current tile part * */ public void extractTilePartMarkSeg(short marker, RandomAccessIO ehs, int tileIdx, int tilePartIdx) throws IOException { String htKey=""; // Name used as a hash-table key if(ht==null) { ht = new Hashtable(); } switch(marker) { case SOT: throw new CorruptedCodestreamException("Second SOT marker "+ "segment found in tile-"+ "part header"); case SIZ: throw new CorruptedCodestreamException("SIZ found in tile-part"+ " header"); case EOC: throw new CorruptedCodestreamException("EOC found in tile-part"+ " header"); case TLM: throw new CorruptedCodestreamException("TLM found in tile-part"+ " header"); case PPM: throw new CorruptedCodestreamException("PPM found in tile-part"+ " header"); case COD: if((nfMarkSeg & COD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one COD "+ "marker "+ "found in tile-part"+ " header"); } nfMarkSeg |= COD_FOUND; htKey = "COD"; break; case COC: nfMarkSeg |= COC_FOUND; htKey = "COC"+(nCOCMarkSeg++); break; case QCD: if((nfMarkSeg & QCD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one QCD "+ "marker "+ "found in tile-part"+ " header"); } nfMarkSeg |= QCD_FOUND; htKey = "QCD"; break; case QCC: nfMarkSeg |= QCC_FOUND; htKey = "QCC"+(nQCCMarkSeg++); break; case RGN: nfMarkSeg |= RGN_FOUND; htKey = "RGN"+(nRGNMarkSeg++); break; case COM: nfMarkSeg |= COM_FOUND; htKey = "COM"+(nCOMMarkSeg++); break; case CRG: throw new CorruptedCodestreamException("CRG marker found in "+ "tile-part header"); case PPT: nfMarkSeg |= PPT_FOUND; if(nPPTMarkSeg == null){ nPPTMarkSeg = new int[nTiles][]; } if(nPPTMarkSeg[tileIdx] == null){ nPPTMarkSeg[tileIdx] = new int[nTileParts[tileIdx]]; } htKey = "PPT"+(nPPTMarkSeg[tileIdx][tilePartIdx]++); break; case SOD: nfMarkSeg |= SOD_FOUND; return; case POC: if( (nfMarkSeg&POC_FOUND) != 0) throw new CorruptedCodestreamException("More than one POC "+ "marker segment found "+ "in tile-part"+ " header"); nfMarkSeg |= POC_FOUND; htKey = "POC"; break; case PLT: if((nfMarkSeg & PLM_FOUND) != 0) { throw new CorruptedCodestreamException("PLT marker found even"+ "though PLM marker "+ "found in main header"); } FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"PLT marker segment found but "+ "not used by JJ2000 decoder."); htKey = "UNKNOWN"; break; default: htKey = "UNKNOWN"; FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+ Integer.toHexString(marker)+") in tile-part header"+ " of tile "+tileIdx+" !"); break; } // Read marker segment length and create corresponding byte buffer int markSegLen = ehs.readUnsignedShort(); byte[] buf = new byte[markSegLen]; // Copy data (after re-insertion of marker segment length); buf[0]= (byte)((markSegLen>>8) & 0xFF); buf[1]= (byte)(markSegLen & 0xFF); ehs.readFully(buf,2,markSegLen-2); if(!htKey.equals("UNKNOWN")) { // Store array in hashTable ht.put(htKey,buf); } } /** * Retrieves and reads all marker segments found in the main header during * the first pass. * */ private void readFoundMainMarkSeg() throws IOException { DataInputStream dis; ByteArrayInputStream bais; // SIZ marker segment if((nfMarkSeg&SIZ_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("SIZ"))); readSIZ(new DataInputStream(bais)); } // COM marker segments if((nfMarkSeg&COM_FOUND) != 0) { for(int i=0; i<nCOMMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("COM"+i))); readCOM(new DataInputStream(bais),true,0,i); } } // CRG marker segment if((nfMarkSeg&CRG_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("CRG"))); readCRG(new DataInputStream(bais)); } // COD marker segment if((nfMarkSeg&COD_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("COD"))); readCOD(new DataInputStream(bais),true,0,0); } // COC marker segments if((nfMarkSeg&COC_FOUND) != 0) { for(int i=0; i<nCOCMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("COC"+i))); readCOC(new DataInputStream(bais),true,0,0); } } // RGN marker segment if((nfMarkSeg&RGN_FOUND) != 0) { for(int i=0; i<nRGNMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("RGN"+i))); readRGN(new DataInputStream(bais),true,0,0); } } // QCD marker segment if((nfMarkSeg&QCD_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("QCD"))); readQCD(new DataInputStream(bais),true,0,0); } // QCC marker segments if((nfMarkSeg&QCC_FOUND) != 0) { for(int i=0;i<nQCCMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("QCC"+i))); readQCC(new DataInputStream(bais),true,0,0); } } // POC marker segment if( (nfMarkSeg&POC_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("POC"))); readPOC(new DataInputStream(bais),true,0,0); } // PPM marker segments if((nfMarkSeg&PPM_FOUND) != 0) { for(int i=0;i<nPPMMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("PPM"+i))); readPPM(new DataInputStream(bais)); } } // Reset the hashtable ht = null; } /** * Return the DecoderSpecs instance filled when reading the headers * * Retrieves and reads all marker segments previously found in the * tile-part header. * * @param tileIdx The index of the current tile * * @param tpIdx Index of the current tile-part * */ public void readFoundTilePartMarkSeg(int tileIdx,int tpIdx) throws IOException { DataInputStream dis; ByteArrayInputStream bais; // COD marker segment if((nfMarkSeg&COD_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("COD")) ); readCOD(new DataInputStream(bais),false,tileIdx,tpIdx); } // COC marker segments if((nfMarkSeg&COC_FOUND) != 0) { for(int i=0; i<nCOCMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("COC"+i)) ); readCOC(new DataInputStream(bais),false,tileIdx,tpIdx); } } // RGN marker segment if((nfMarkSeg&RGN_FOUND) != 0) { for(int i=0; i<nRGNMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("RGN"+i)) ); readRGN(new DataInputStream(bais),false,tileIdx,tpIdx); } } // QCD marker segment if((nfMarkSeg&QCD_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("QCD")) ); readQCD(new DataInputStream(bais),false,tileIdx,tpIdx); } // QCC marker segments if((nfMarkSeg&QCC_FOUND) != 0) { for(int i=0;i<nQCCMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("QCC"+i)) ); readQCC(new DataInputStream(bais),false,tileIdx,tpIdx); } } // POC marker segment if( (nfMarkSeg&POC_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("POC"))); readPOC(new DataInputStream(bais),false,tileIdx,tpIdx); } // COM marker segments if((nfMarkSeg&COM_FOUND) != 0) { for(int i=0; i<nCOMMarkSeg; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("COM"+i)) ); readCOM(new DataInputStream(bais),false,tileIdx,i); } } // PPT marker segments if((nfMarkSeg&PPT_FOUND) != 0) { for(int i=0;i<nPPTMarkSeg[tileIdx][tpIdx]; i++) { bais = new ByteArrayInputStream( (byte[])(ht.get("PPT"+i)) ); readPPT(new DataInputStream(bais),tileIdx,tpIdx); } } // Reset ht ht = null; } /** * Return the DecoderSpecs instance filled when reading the headers * * @return The DecoderSpecs of the decoder * */ public DecoderSpecs getDecoderSpecs(){ return decSpec; } /** * Creates a HeaderDecoder instance and read in two passes the main header * of the codestream. The first and last marker segments shall be * respectively SOC and SOT. * * @param ehs The encoded header stream where marker segment are * extracted. * * @param j2krparam The parameter list of the decoder * * @param hi The HeaderInfo holding information found in marker segments * * @exception IOException If an I/O error occurs while reading from the * encoded header stream. * * @exception EOFException If the end of the encoded header stream is * reached before getting all the data. * * @exception CorruptedCodestreamException If invalid data is found in the * codestream main header. * */ public HeaderDecoder(RandomAccessIO ehs, J2KImageReadParamJava j2krparam, HeaderInfo hi) throws IOException { this.hi = hi; this.j2krparam = j2krparam; mainHeadOff = ehs.getPos(); if( ((short)ehs.readShort()) != Markers.SOC ) { throw new CorruptedCodestreamException("SOC marker segment not "+ " found at the "+ "beginning of the "+ "codestream."); } // First Pass: Decode and store main header information until the SOT // marker segment is found nfMarkSeg = 0; do { extractMainMarkSeg(ehs.readShort(),ehs); } while ((nfMarkSeg & SOT_FOUND)==0); //Stop when SOT is found ehs.seek(ehs.getPos()-2); // Realign codestream on SOT marker // Second pass: Read each marker segment previously found readFoundMainMarkSeg(); } /** * Creates and returns the entropy decoder corresponding to the * information read from the codestream header and with the special * additional parameters from the parameter list. * * @param src The bit stream reader agent where to get code-block data * from. * * @param j2krparam The parameter list containing parameters applicable to the * entropy decoder (other parameters can also be present). * * @return The entropy decoder * */ public EntropyDecoder createEntropyDecoder(CodedCBlkDataSrcDec src, J2KImageReadParamJava j2krparam) { // Get error detection option // boolean doer = j2krparam.getCer();; boolean doer = true; // Get verbose error detection option //boolean verber = j2krparam.getVerbose(); boolean verber = false; // Get maximum number of bit planes from m quit condition // int mMax = j2krparam.getMQuit(); int mMax = -1; return new StdEntropyDecoder(src,decSpec,doer,verber,mMax); } /** * Creates and returns the EnumeratedColorSpaceMapper * corresponding to the information read from the JP2 image file * via the ColorSpace parameter. * * @param src The bit stream reader agent where to get code-block * data from. * @param csMap provides color space information from the image file * * @return The color space mapping object * @exception IOException image access exception * @exception ICCProfileException if image contains a bad icc profile * @exception ColorSpaceException if image contains a bad colorspace box **/ /* public BlkImgDataSrc createColorSpaceMapper(BlkImgDataSrc src, ColorSpace csMap) throws IOException, ICCProfileException, ColorSpaceException { return ColorSpaceMapper.createInstance(src,csMap); } */ /** * Creates and returns the ChannelDefinitonMapper which maps the * input channels to the channel definition for the appropriate * colorspace. * * @param src The bit stream reader agent where to get code-block * data from. * @param csMap provides color space information from the image file * * @return The channel definition mapping object * @exception IOException image access exception * @exception ColorSpaceException if image contains a bad colorspace box **/ /* public BlkImgDataSrc createChannelDefinitionMapper(BlkImgDataSrc src, ColorSpace csMap) throws IOException, ColorSpaceException { return ChannelDefinitionMapper.createInstance(src,csMap); } */ /** * Creates and returns the PalettizedColorSpaceMapper which uses * the input samples as indicies into a sample palette to * construct the output. * * @param src The bit stream reader agent where to get code-block * data from. * @param csMap provides color space information from the image file * * @return a PalettizedColorSpaceMapper instance * @exception IOException image access exception * @exception ColorSpaceException if image contains a bad colorspace box **/ /* public BlkImgDataSrc createPalettizedColorSpaceMapper(BlkImgDataSrc src, ColorSpace csMap) throws IOException, ColorSpaceException { return PalettizedColorSpaceMapper.createInstance(src, csMap); } */ /** * Creates and returns the Resampler which converts the input * source to one in which all channels have the same number of * samples. This is required for colorspace conversions. * * @param src The bit stream reader agent where to get code-block * data from. * @param csMap provides color space information from the image file * * @return The resampled BlkImgDataSrc * @exception IOException image access exception * @exception ColorSpaceException if image contains a bad colorspace box **/ /* public BlkImgDataSrc createResampler(BlkImgDataSrc src, ColorSpace csMap) throws IOException, ColorSpaceException { return Resampler.createInstance(src, csMap); } */ /** * Creates and returns the ROIDeScaler corresponding to the information * read from the codestream header and with the special additional * parameters from the parameter list. * * @param src The bit stream reader agent where to get code-block data * from. * * @param j2krparam The parameters applicable to the entropy decoder. * * @return The ROI descaler * */ public ROIDeScaler createROIDeScaler(CBlkQuantDataSrcDec src, J2KImageReadParamJava j2krparam, DecoderSpecs decSpec2){ return ROIDeScaler.createInstance(src, j2krparam, decSpec2); } /** * Method that resets members indicating which markers have already been * found * */ public void resetHeaderMarkers() { // The found status of PLM remains since only PLM OR PLT allowed // Same goes for PPM and PPT nfMarkSeg = nfMarkSeg & (PLM_FOUND | PPM_FOUND); nCOCMarkSeg = 0; nQCCMarkSeg = 0; nCOMMarkSeg = 0; nRGNMarkSeg = 0; } /** * Print information about the current header. * * @return Information in a String * */ public String toString(){ return hdStr; } /** * Returns the parameters that are used in this class. It returns a 2D * String array. Each of the 1D arrays is for a different option, and they * have 3 elements. The first element is the option name, the second one * is the synopsis and the third one is a long description of what the * parameter is. The synopsis or description may be 'null', in which case * it is assumed that there is no synopsis or description of the option, * respectively. * * @return the options name, their synopsis and their explanation. * */ public static String[][] getParameterInfo() { return pinfo; } /** * Return the number of tiles in the image * * @return The number of tiles * */ public int getNumTiles(){ return nTiles; } /** * Return the packed packet headers for a given tile. * * @return An input stream containing the packed packet headers for a * particular tile * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ public ByteArrayInputStream getPackedPktHead(int tile) throws IOException { if(pkdPktHeaders==null) { int i,t; pkdPktHeaders = new ByteArrayOutputStream[nTiles]; for(i=nTiles-1; i>=0; i--) { pkdPktHeaders[i] = new ByteArrayOutputStream(); } if(nPPMMarkSeg!=0) { // If this is first time packed packet headers are requested, // create packed packet headers from Nppm and Ippm fields int nppm; int nTileParts = tileOfTileParts.size(); byte[] temp; ByteArrayInputStream pph; ByteArrayOutputStream allNppmIppm = new ByteArrayOutputStream(); // Concatenate all Nppm and Ippm fields for(i=0 ; i<nPPMMarkSeg ; i++) { allNppmIppm.write(pPMMarkerData[i]); } pph = new ByteArrayInputStream(allNppmIppm.toByteArray()); // Read all packed packet headers and concatenate for each // tile part for(i=0; i<nTileParts ; i++) { t = ((Integer)tileOfTileParts.elementAt(i)).intValue(); // get Nppm value nppm = (pph.read()<<24)|(pph.read()<<16)| (pph.read()<<8)|(pph.read()); temp = new byte[nppm]; // get ippm field pph.read(temp); pkdPktHeaders[t].write(temp); } } else { int tp; // Write all packed packet headers to pkdPktHeaders for(t=nTiles-1; t>=0; t--) { for(tp=0; tp<nTileParts[t]; tp++){ for(i=0 ; i<nPPTMarkSeg[t][tp] ; i++) { pkdPktHeaders[t]. write(tilePartPkdPktHeaders[t][tp][i]); } } } } } return new ByteArrayInputStream(pkdPktHeaders[tile].toByteArray()); } /** * Sets the tile of each tile part in order. This information is needed * for identifying which packet header belongs to which tile when using * the PPM marker. * * @param tile The tile number that the present tile part belongs to. * */ public void setTileOfTileParts(int tile) { if(nPPMMarkSeg!=0) { tileOfTileParts.addElement(new Integer(tile)); } } /** * Returns the number of found marker segments in the current header. * * @return The number of marker segments found in the current header. * */ public int getNumFoundMarkSeg() { return nfMarkSeg; } }