Exemple #1
0
        /// <summary> Splits the current subband in its four subbands. It changes the status
        /// of this element (from a leaf to a node, and sets the filters), creates
        /// the childs and initializes them. An IllegalArgumentException is thrown
        /// if this subband is not a leaf.
        ///
        /// <p>It uses the initChilds() method to initialize the childs.</p>
        ///
        /// </summary>
        /// <param name="hfilter">The horizontal wavelet filter used to decompose this
        /// subband. It has to be a SynWTFilter object.
        ///
        /// </param>
        /// <param name="vfilter">The vertical wavelet filter used to decompose this
        /// subband. It has to be a SynWTFilter object.
        ///
        /// </param>
        /// <returns> A reference to the LL leaf (subb_LL).
        ///
        /// </returns>
        /// <seealso cref="Subband.initChilds">
        ///
        /// </seealso>
        protected internal override Subband split(WaveletFilter hfilter, WaveletFilter vfilter)
        {
            // Test that this is a node
            if (isNode)
            {
                throw new System.ArgumentException();
            }

            // Modify this element into a node and set the filters
            isNode       = true;
            this.hFilter = (SynWTFilter)hfilter;
            this.vFilter = (SynWTFilter)vfilter;

            // Create childs
            subb_LL = new SubbandSyn();
            subb_LH = new SubbandSyn();
            subb_HL = new SubbandSyn();
            subb_HH = new SubbandSyn();

            // Assign parent
            subb_LL.parent = this;
            subb_HL.parent = this;
            subb_LH.parent = this;
            subb_HH.parent = this;

            // Initialize childs
            initChilds();

            // Return reference to LL subband
            return(subb_LL);
        }
		/// <summary> Returns the specified coded code-block, for the specified component, in
		/// the current tile. The first layer to return is indicated by 'fl'. The
		/// number of layers that is returned depends on 'nl' and the amount of
		/// available data.
		/// 
		/// <p>The argument 'fl' is to be used by subsequent calls to this method
		/// for the same code-block. In this way supplemental data can be retrieved
		/// at a later time. The fact that data from more than one layer can be
		/// returned means that several packets from the same code-block, of the
		/// same component, and the same tile, have been concatenated.</p>
		/// 
		/// <p>The returned compressed code-block can have its progressive
		/// attribute set. If this attribute is set it means that more data can be
		/// obtained by subsequent calls to this method (subject to transmission
		/// delays, etc). If the progressive attribute is not set it means that the
		/// returned data is all the data that can be obtained for the specified
		/// code-block.</p>
		/// 
		/// <p>The compressed code-block is uniquely specified by the current tile,
		/// the component (identified by 'c'), the subband (indentified by 'sb')
		/// and the code-block vertical and horizontal indexes 'n' and 'm'.</p>
		/// 
		/// <p>The 'ulx' and 'uly' members of the returned 'DecLyrdCBlk' object
		/// contain the coordinates of the top-left corner of the block, with
		/// respect to the tile, not the subband.</p>
		/// 
		/// </summary>
		/// <param name="c">The index of the component, from 0 to N-1.
		/// 
		/// </param>
		/// <param name="m">The vertical index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="n">The horizontal index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="sb">The subband in whic the requested code-block is.
		/// 
		/// </param>
		/// <param name="fl">The first layer to return.
		/// 
		/// </param>
		/// <param name="nl">The number of layers to return, if negative all available
		/// layers are returned, starting at 'fl'.
		/// 
		/// </param>
		/// <param name="ccb">If not null this object is used to return the compressed
		/// code-block. If null a new object is created and returned. If the data
		/// array in ccb is not null then it can be reused to return the compressed
		/// data.
		/// 
		/// </param>
		/// <returns> The compressed code-block, with a certain number of layers
		/// determined by the available data and 'nl'.
		/// 
		/// </returns>
		public override DecLyrdCBlk getCodeBlock(int c, int m, int n, SubbandSyn sb, int fl, int nl, DecLyrdCBlk ccb)
		{
			
			int t = TileIdx;
			CBlkInfo rcb; // requested code-block
			int r = sb.resLvl; // Resolution level
			int s = sb.sbandIdx; // Subband index
			int tpidx;
			int passtype;
			
			// Number of layers
			int numLayers = ((System.Int32) decSpec.nls.getTileDef(t));
			int options = ((System.Int32) decSpec.ecopts.getTileCompVal(t, c));
			if (nl < 0)
			{
				nl = numLayers - fl + 1;
			}
			
			// If the l quit condition is used, Make sure that no layer 
			// after lquit is returned
			if (lQuit != - 1 && fl + nl > lQuit)
			{
				nl = lQuit - fl;
			}
			
			// Check validity of resquested resolution level (according to the
			// "-res" option).
			int maxdl = getSynSubbandTree(t, c).resLvl;
			if (r > targetRes + maxdl - decSpec.dls.Min)
			{
				throw new System.ApplicationException("JJ2000 error: requesting a code-block " + "disallowed by the '-res' option.");
			}
			
			// Check validity of all the arguments
			try
			{
				rcb = cbI[c][r][s][m][n];
				
				if (fl < 1 || fl > numLayers || fl + nl - 1 > numLayers)
				{
					throw new System.ArgumentException();
				}
			}
			catch (System.IndexOutOfRangeException)
			{
				throw new System.ArgumentException("Code-block (t:" + t + ", c:" + c + ", r:" + r + ", s:" + s + ", " + m + "x" + (+ n) + ") not found in codestream");
			}
			catch (System.NullReferenceException)
			{
				throw new System.ArgumentException("Code-block (t:" + t + ", c:" + c + ", r:" + r + ", s:" + s + ", " + m + "x" + n + ") not found in bit stream");
			}
			
			// Create DecLyrdCBlk object if necessary
			if (ccb == null)
			{
				ccb = new DecLyrdCBlk();
			}
			ccb.m = m;
			ccb.n = n;
			ccb.nl = 0;
			ccb.dl = 0;
			ccb.nTrunc = 0;
			
			if (rcb == null)
			{
				// This code-block was skipped when reading. Returns no data
				ccb.skipMSBP = 0;
				ccb.prog = false;
				ccb.w = ccb.h = ccb.ulx = ccb.uly = 0;
				return ccb;
			}
			
			// ccb initialization
			ccb.skipMSBP = rcb.msbSkipped;
			ccb.ulx = rcb.ulx;
			ccb.uly = rcb.uly;
			ccb.w = rcb.w;
			ccb.h = rcb.h;
			ccb.ftpIdx = 0;
			
			// Search for index of first truncation point (first layer where
			// length of data is not zero)
			int l = 0;
			while ((l < rcb.len.Length) && (rcb.len[l] == 0))
			{
				ccb.ftpIdx += rcb.ntp[l];
				l++;
			}
			
			// Calculate total length, number of included layer and number of
			// truncation points
			for (l = fl - 1; l < fl + nl - 1; l++)
			{
				ccb.nl++;
				ccb.dl += rcb.len[l];
				ccb.nTrunc += rcb.ntp[l];
			}
			
			// Calculate number of terminated segments
			int nts;
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0)
			{
				// Regular termination in use One segment per pass
				// (i.e. truncation point)
				nts = ccb.nTrunc - ccb.ftpIdx;
			}
			else if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0)
			{
				// Selective arithmetic coding bypass mode in use, but no regular
				// termination: 1 segment upto the end of the last pass of the 4th
				// most significant bit-plane, and, in each following bit-plane,
				// one segment upto the end of the 2nd pass and one upto the end
				// of the 3rd pass.
				
				if (ccb.nTrunc <= CSJ2K.j2k.entropy.StdEntropyCoderOptions.FIRST_BYPASS_PASS_IDX)
				{
					nts = 1;
				}
				else
				{
					nts = 1;
					// Adds one for each terminated pass
					for (tpidx = ccb.ftpIdx; tpidx < ccb.nTrunc; tpidx++)
					{
						if (tpidx >= CSJ2K.j2k.entropy.StdEntropyCoderOptions.FIRST_BYPASS_PASS_IDX - 1)
						{
							passtype = (tpidx + CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_EMPTY_PASSES_IN_MS_BP) % CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES;
							if (passtype == 1 || passtype == 2)
							{
								// lazy pass just before MQ pass or MQ pass just
								// before lazy pass => terminated
								nts++;
							}
						}
					}
				}
			}
			else
			{
				// Nothing special in use, just one terminated segment
				nts = 1;
			}
			
			// ccb.data creation
			if (ccb.data == null || ccb.data.Length < ccb.dl)
			{
				ccb.data = new byte[ccb.dl];
			}
			
			// ccb.tsLengths creation
			if (nts > 1 && (ccb.tsLengths == null || ccb.tsLengths.Length < nts))
			{
				ccb.tsLengths = new int[nts];
			}
			else if (nts > 1 && (options & (CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS | CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS)) == CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS)
			{
				ArrayUtil.intArraySet(ccb.tsLengths, 0);
			}
			
			// Fill ccb with compressed data
			int dataIdx = - 1;
			tpidx = ccb.ftpIdx;
			int ctp = ccb.ftpIdx; // Cumulative number of truncation
			// point for the current layer layer
			int tsidx = 0;
			int j;
			
			for (l = fl - 1; l < fl + nl - 1; l++)
			{
				ctp += rcb.ntp[l];
				// No data in this layer
				if (rcb.len[l] == 0)
					continue;
				
				// Read data
				// NOTE: we should never get an EOFException here since all
				// data is checked to be within the file.
				try
				{
					in_Renamed.seek(rcb.off[l]);
					in_Renamed.readFully(ccb.data, dataIdx + 1, rcb.len[l]);
					dataIdx += rcb.len[l];
				}
				catch (System.IO.IOException e)
				{
					JJ2KExceptionHandler.handleException(e);
				}
				
				// Get the terminated segment lengths, if any
				if (nts == 1)
					continue;
				if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0)
				{
					// Regular termination => each pass is terminated
					for (j = 0; tpidx < ctp; j++, tpidx++)
					{
						if (rcb.segLen[l] != null)
						{
							ccb.tsLengths[tsidx++] = rcb.segLen[l][j];
						}
						else
						{
							// Only one terminated segment in packet
							ccb.tsLengths[tsidx++] = rcb.len[l];
						}
					}
				}
				else
				{
					// Lazy coding without regular termination
					for (j = 0; tpidx < ctp; tpidx++)
					{
						if (tpidx >= CSJ2K.j2k.entropy.StdEntropyCoderOptions.FIRST_BYPASS_PASS_IDX - 1)
						{
							passtype = (tpidx + CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_EMPTY_PASSES_IN_MS_BP) % CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES;
							if (passtype != 0)
							{
								// lazy pass just before MQ pass or MQ
								// pass just before lazy pass =>
								// terminated
								if (rcb.segLen[l] != null)
								{
									ccb.tsLengths[tsidx++] += rcb.segLen[l][j++];
									rcb.len[l] -= rcb.segLen[l][j - 1];
								}
								else
								{
									// Only one terminated segment in packet
									ccb.tsLengths[tsidx++] += rcb.len[l];
									rcb.len[l] = 0;
								}
							}
						}
					}
					
					// Last length in packet always in (either terminated segment
					// or contribution to terminated segment)
					if (rcb.segLen[l] != null && j < rcb.segLen[l].Length)
					{
						ccb.tsLengths[tsidx] += rcb.segLen[l][j];
						rcb.len[l] -= rcb.segLen[l][j];
					}
					else
					{
						// Only one terminated segment in packet
						if (tsidx < nts)
						{
							ccb.tsLengths[tsidx] += rcb.len[l];
							rcb.len[l] = 0;
						}
					}
				}
			}
			if (nts == 1 && ccb.tsLengths != null)
			{
				ccb.tsLengths[0] = ccb.dl;
			}
			
			// Set the progressive flag
			int lastlayer = fl + nl - 1;
			if (lastlayer < numLayers - 1)
			{
				for (l = lastlayer + 1; l < numLayers; l++)
				{
					// It remains data for this code-block in the bit stream
					if (rcb.len[l] != 0)
					{
						ccb.prog = true;
					}
				}
			}
			
			return ccb;
		}
		/// <summary> Changes the current tile, given the new indexes. An
		/// IllegalArgumentException is thrown if the indexes do not correspond to
		/// a valid tile.
		/// 
		/// </summary>
		/// <param name="x">The horizontal indexes the tile.
		/// 
		/// </param>
		/// <param name="y">The vertical indexes of the new tile.
		/// 
		/// </param>
		public override void  setTile(int x, int y)
		{
			
			int i; // counter
			// Check validity of tile indexes
			if (x < 0 || y < 0 || x >= ntX || y >= ntY)
			{
				throw new System.ArgumentException();
			}
			int t = (y * ntX + x);
			
			// Reset number of read bytes if needed
			if (t == 0)
			{
				anbytes = headLen;
				if (!isTruncMode)
				{
					anbytes += 2;
				}
				// Restore values of nBytes
				for (int tIdx = 0; tIdx < nt; tIdx++)
				{
					nBytes[tIdx] = baknBytes[tIdx];
				}
			}
			
			// Set the new current tile
			ctX = x;
			ctY = y;
			// Calculate tile relative points
			int ctox = (x == 0)?ax:px + x * ntW;
			int ctoy = (y == 0)?ay:py + y * ntH;
			for (i = nc - 1; i >= 0; i--)
			{
				culx[i] = (ctox + hd.getCompSubsX(i) - 1) / hd.getCompSubsX(i);
				culy[i] = (ctoy + hd.getCompSubsY(i) - 1) / hd.getCompSubsY(i);
				offX[i] = (px + x * ntW + hd.getCompSubsX(i) - 1) / hd.getCompSubsX(i);
				offY[i] = (py + y * ntH + hd.getCompSubsY(i) - 1) / hd.getCompSubsY(i);
			}
			
			// Initialize subband tree and number of resolution levels
			subbTrees = new SubbandSyn[nc];
			mdl = new int[nc];
			derived = new bool[nc];
			params_Renamed = new StdDequantizerParams[nc];
			gb = new int[nc];
			
			for (int c = 0; c < nc; c++)
			{
				derived[c] = decSpec.qts.isDerived(t, c);
				params_Renamed[c] = (StdDequantizerParams) decSpec.qsss.getTileCompVal(t, c);
				gb[c] = ((System.Int32) decSpec.gbs.getTileCompVal(t, c));
				mdl[c] = ((System.Int32) decSpec.dls.getTileCompVal(t, c));
				
				subbTrees[c] = new SubbandSyn(getTileCompWidth(t, c, mdl[c]), getTileCompHeight(t, c, mdl[c]), getResULX(c, mdl[c]), getResULY(c, mdl[c]), mdl[c], decSpec.wfs.getHFilters(t, c), decSpec.wfs.getVFilters(t, c));
				initSubbandsFields(c, subbTrees[c]);
			}
			
			// Read tile's packets
			try
			{
				readTilePkts(t);
			}
			catch (System.IO.IOException e)
			{
				SupportClass.WriteStackTrace(e, Console.Error);
				throw new System.ApplicationException("IO Error when reading tile " + x + " x " + y);
			}
		}
 public abstract CSJ2K.j2k.image.DataBlk getInternCodeBlock(int param1, int param2, int param3, CSJ2K.j2k.wavelet.synthesis.SubbandSyn param4, CSJ2K.j2k.image.DataBlk param5);
Exemple #5
0
		/// <summary> Returns the specified code-block in the current tile for the specified
		/// component (as a reference or copy).
		/// 
		/// <p>The returned code-block may be progressive, which is indicated by
		/// the 'progressive' variable of the returned 'DataBlk' object. If a
		/// code-block is progressive it means that in a later request to this
		/// method for the same code-block it is possible to retrieve data which is
		/// a better approximation, since meanwhile more data to decode for the
		/// code-block could have been received. If the code-block is not
		/// progressive then later calls to this method for the same code-block
		/// will return the exact same data values.</p>
		/// 
		/// <p>The data returned by this method can be the data in the internal
		/// buffer of this object, if any, and thus can not be modified by the
		/// caller. The 'offset' and 'scanw' of the returned data can be
		/// arbitrary. See the 'DataBlk' class.</p>
		/// 
		/// <p>The 'ulx' and 'uly' members of the returned 'DataBlk' object contain
		/// the coordinates of the top-left corner of the block, with respect to
		/// the tile, not the subband.</p>
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="m">The vertical index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="n">The horizontal index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="sb">The subband in which the code-block to return is.
		/// 
		/// </param>
		/// <param name="cblk">If non-null this object will be used to return the new
		/// code-block. If null a new one will be allocated and returned. If the
		/// "data" array of the object is non-null it will be reused, if possible,
		/// to return the data.
		/// 
		/// </param>
		/// <returns> The requested code-block in the current tile for component 'c'.
		/// 
		/// </returns>
		/// <seealso cref="DataBlk">
		/// 
		/// </seealso>
		public virtual DataBlk getInternCodeBlock(int c, int m, int n, SubbandSyn sb, DataBlk cblk)
		{
			int i, j, k, wrap; // mi removed
			int ulx, uly, w, h;
			int[] data; // local copy of quantized data
			int tmp;
			//int limit;
			
			// Get data block from entropy decoder
			cblk = src.getInternCodeBlock(c, m, n, sb, cblk);
			
			// If there are no ROIs in the tile, Or if we already got all blocks
			bool noRoiInTile = false;
			if (mss == null || mss.getTileCompVal(TileIdx, c) == null)
				noRoiInTile = true;
			
			if (noRoiInTile || cblk == null)
			{
				return cblk;
			}
			data = (int[]) cblk.Data;
			ulx = cblk.ulx;
			uly = cblk.uly;
			w = cblk.w;
			h = cblk.h;
			
			// Scale coefficients according to magnitude. If the magnitude of a
			// coefficient is lower than 2 pow 31-magbits then it is a background
			// coeff and should be up-scaled
			int boost = ((System.Int32) mss.getTileCompVal(TileIdx, c));
			int mask = ((1 << sb.magbits) - 1) << (31 - sb.magbits);
			int mask2 = (~ mask) & 0x7FFFFFFF;
			
			wrap = cblk.scanw - w;
			i = cblk.offset + cblk.scanw * (h - 1) + w - 1;
			for (j = h; j > 0; j--)
			{
				for (k = w; k > 0; k--, i--)
				{
					tmp = data[i];
					if ((tmp & mask) == 0)
					{
						// BG
						data[i] = (tmp & unchecked((int) 0x80000000)) | (tmp << boost);
					}
					else
					{
						// ROI
						if ((tmp & mask2) != 0)
						{
							// decoded more than magbits bit-planes, set
							// quantization mid-interval approx. bit just after
							// the magbits.
							data[i] = (tmp & (~ mask2)) | (1 << (30 - sb.magbits));
						}
					}
				}
				i -= wrap;
			}
			return cblk;
		}
Exemple #6
0
		/// <summary> Returns the specified code-block in the current tile for the specified
		/// component, as a copy (see below).
		/// 
		/// <p>The returned code-block may be progressive, which is indicated by
		/// the 'progressive' variable of the returned 'DataBlk' object. If a
		/// code-block is progressive it means that in a later request to this
		/// method for the same code-block it is possible to retrieve data which is
		/// a better approximation, since meanwhile more data to decode for the
		/// code-block could have been received. If the code-block is not
		/// progressive then later calls to this method for the same code-block
		/// will return the exact same data values.</p>
		/// 
		/// <p>The data returned by this method is always a copy of the internal
		/// data of this object, if any, and it can be modified "in place" without
		/// any problems after being returned. The 'offset' of the returned data is
		/// 0, and the 'scanw' is the same as the code-block width. See the
		/// 'DataBlk' class.</p>
		/// 
		/// <p>The 'ulx' and 'uly' members of the returned 'DataBlk' object contain
		/// the coordinates of the top-left corner of the block, with respect to
		/// the tile, not the subband.</p>
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="m">The vertical index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="n">The horizontal index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="sb">The subband in which the code-block to return is.
		/// 
		/// </param>
		/// <param name="cblk">If non-null this object will be used to return the new
		/// code-block. If null a new one will be allocated and returned. If the
		/// "data" array of the object is non-null it will be reused, if possible,
		/// to return the data.
		/// 
		/// </param>
		/// <returns> The next code-block in the current tile for component 'c', or
		/// null if all code-blocks for the current tile have been returned.
		/// 
		/// </returns>
		/// <seealso cref="DataBlk">
		/// 
		/// </seealso>
		public virtual DataBlk getCodeBlock(int c, int m, int n, SubbandSyn sb, DataBlk cblk)
		{
			return getInternCodeBlock(c, m, n, sb, cblk);
		}
Exemple #7
0
        /// <summary> Performs the inverse wavelet transform on the whole component. It
        /// iteratively reconstructs the subbands from leaves up to the root
        /// node. This method is recursive, the first call to it the 'sb' must be
        /// the root of the subband tree. The method will then process the entire
        /// subband tree by calling itslef recursively.
        /// 
        /// </summary>
        /// <param name="img">The buffer for the image/wavelet data.
        /// 
        /// </param>
        /// <param name="sb">The subband to reconstruct.
        /// 
        /// </param>
        /// <param name="c">The index of the component to reconstruct 
        /// 
        /// </param>
        private void waveletTreeReconstruction(DataBlk img, SubbandSyn sb, int c)
        {
            DataBlk subbData;

            // If the current subband is a leaf then get the data from the source
            if (!sb.isNode)
            {
                int i, m, n;
                System.Object src_data, dst_data;
                Coord ncblks;

                if (sb.w == 0 || sb.h == 0)
                {
                    return ; // If empty subband do nothing
                }

                // Get all code-blocks in subband
                if (dtype == DataBlk.TYPE_INT)
                {
                    subbData = new DataBlkInt();
                }
                else
                {
                    subbData = new DataBlkFloat();
                }
                ncblks = sb.numCb;
                dst_data = img.Data;
                for (m = 0; m < ncblks.y; m++)
                {
                    for (n = 0; n < ncblks.x; n++)
                    {
                        subbData = src.getInternCodeBlock(c, m, n, sb, subbData);
                        src_data = subbData.Data;

                        // Copy the data line by line
                        for (i = subbData.h - 1; i >= 0; i--)
                        {
                            // CONVERSION PROBLEM
                            Array.Copy((System.Array)src_data, subbData.offset + i * subbData.scanw, (System.Array)dst_data, (subbData.uly + i) * img.w + subbData.ulx, subbData.w);
                        }
                    }
                }
            }
            else if (sb.isNode)
            {
                // Reconstruct the lower resolution levels if the current subbands
                // is a node

                //Perform the reconstruction of the LL subband
                waveletTreeReconstruction(img, (SubbandSyn) sb.LL, c);

                if (sb.resLvl <= reslvl - maxImgRes + ndl[c])
                {
                    //Reconstruct the other subbands
                    waveletTreeReconstruction(img, (SubbandSyn) sb.HL, c);
                    waveletTreeReconstruction(img, (SubbandSyn) sb.LH, c);
                    waveletTreeReconstruction(img, (SubbandSyn) sb.HH, c);

                    //Perform the 2D wavelet decomposition of the current subband
                    wavelet2DReconstruction(img, (SubbandSyn) sb, c);
                }
            }
        }
Exemple #8
0
        /// <summary> Performs the 2D inverse wavelet transform on a subband of the image, on
        /// the specified component. This method will successively perform 1D
        /// filtering steps on all columns and then all lines of the subband.
        /// 
        /// </summary>
        /// <param name="db">the buffer for the image/wavelet data.
        /// 
        /// </param>
        /// <param name="sb">The subband to reconstruct.
        /// 
        /// </param>
        /// <param name="c">The index of the component to reconstruct 
        /// 
        /// </param>
        private void wavelet2DReconstruction(DataBlk db, SubbandSyn sb, int c)
        {
            System.Object data;
            System.Object buf;
            int ulx, uly, w, h;
            int i, j, k;
            int offset;

            // If subband is empty (i.e. zero size) nothing to do
            if (sb.w == 0 || sb.h == 0)
            {
                return ;
            }

            data = db.Data;

            ulx = sb.ulx;
            uly = sb.uly;
            w = sb.w;
            h = sb.h;

            buf = null; // To keep compiler happy

            switch (sb.HorWFilter.DataType)
            {

                case DataBlk.TYPE_INT:
                    buf = new int[(w >= h)?w:h];
                    break;

                case DataBlk.TYPE_FLOAT:
                    buf = new float[(w >= h)?w:h];
                    break;
                }

            //Perform the horizontal reconstruction
            offset = (uly - db.uly) * db.w + ulx - db.ulx;
            if (sb.ulcx % 2 == 0)
            {
                // start index is even => use LPF
                for (i = 0; i < h; i++, offset += db.w)
                {
                    // CONVERSION PROBLEM?
                    Array.Copy((System.Array)data, offset, (System.Array)buf, 0, w);
                    sb.hFilter.synthetize_lpf(buf, 0, (w + 1) / 2, 1, buf, (w + 1) / 2, w / 2, 1, data, offset, 1);
                }
            }
            else
            {
                // start index is odd => use HPF
                for (i = 0; i < h; i++, offset += db.w)
                {
                    // CONVERSION PROBLEM?
                    Array.Copy((System.Array)data, offset, (System.Array)buf, 0, w);
                    sb.hFilter.synthetize_hpf(buf, 0, w / 2, 1, buf, w / 2, (w + 1) / 2, 1, data, offset, 1);
                }
            }

            //Perform the vertical reconstruction
            offset = (uly - db.uly) * db.w + ulx - db.ulx;
            switch (sb.VerWFilter.DataType)
            {

                case DataBlk.TYPE_INT:
                    int[] data_int, buf_int;
                    data_int = (int[]) data;
                    buf_int = (int[]) buf;
                    if (sb.ulcy % 2 == 0)
                    {
                        // start index is even => use LPF
                        for (j = 0; j < w; j++, offset++)
                        {
                            for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                                buf_int[i] = data_int[k];
                            sb.vFilter.synthetize_lpf(buf, 0, (h + 1) / 2, 1, buf, (h + 1) / 2, h / 2, 1, data, offset, db.w);
                        }
                    }
                    else
                    {
                        // start index is odd => use HPF
                        for (j = 0; j < w; j++, offset++)
                        {
                            for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                                buf_int[i] = data_int[k];
                            sb.vFilter.synthetize_hpf(buf, 0, h / 2, 1, buf, h / 2, (h + 1) / 2, 1, data, offset, db.w);
                        }
                    }
                    break;

                case DataBlk.TYPE_FLOAT:
                    float[] data_float, buf_float;
                    data_float = (float[]) data;
                    buf_float = (float[]) buf;
                    if (sb.ulcy % 2 == 0)
                    {
                        // start index is even => use LPF
                        for (j = 0; j < w; j++, offset++)
                        {
                            for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                                buf_float[i] = data_float[k];
                            sb.vFilter.synthetize_lpf(buf, 0, (h + 1) / 2, 1, buf, (h + 1) / 2, h / 2, 1, data, offset, db.w);
                        }
                    }
                    else
                    {
                        // start index is odd => use HPF
                        for (j = 0; j < w; j++, offset++)
                        {
                            for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                                buf_float[i] = data_float[k];
                            sb.vFilter.synthetize_hpf(buf, 0, h / 2, 1, buf, h / 2, (h + 1) / 2, 1, data, offset, db.w);
                        }
                    }
                    break;
                }
        }
Exemple #9
0
		/// <summary> Splits the current subband in its four subbands. It changes the status
		/// of this element (from a leaf to a node, and sets the filters), creates
		/// the childs and initializes them. An IllegalArgumentException is thrown
		/// if this subband is not a leaf.
		/// 
		/// <p>It uses the initChilds() method to initialize the childs.</p>
		/// 
		/// </summary>
		/// <param name="hfilter">The horizontal wavelet filter used to decompose this
		/// subband. It has to be a SynWTFilter object.
		/// 
		/// </param>
		/// <param name="vfilter">The vertical wavelet filter used to decompose this
		/// subband. It has to be a SynWTFilter object.
		/// 
		/// </param>
		/// <returns> A reference to the LL leaf (subb_LL).
		/// 
		/// </returns>
		/// <seealso cref="Subband.initChilds">
		/// 
		/// </seealso>
		protected internal override Subband split(WaveletFilter hfilter, WaveletFilter vfilter)
		{
			// Test that this is a node
			if (isNode)
			{
				throw new System.ArgumentException();
			}
			
			// Modify this element into a node and set the filters
			isNode = true;
			this.hFilter = (SynWTFilter) hfilter;
			this.vFilter = (SynWTFilter) vfilter;
			
			// Create childs
			subb_LL = new SubbandSyn();
			subb_LH = new SubbandSyn();
			subb_HL = new SubbandSyn();
			subb_HH = new SubbandSyn();
			
			// Assign parent
			subb_LL.parent = this;
			subb_HL.parent = this;
			subb_LH.parent = this;
			subb_HH.parent = this;
			
			// Initialize childs
			initChilds();
			
			// Return reference to LL subband
			return subb_LL;
		}
		/// <summary> Returns the specified code-block in the current tile for the specified
		/// component, as a copy (see below).
		/// 
		/// <P>The returned code-block may be progressive, which is indicated by
		/// the 'progressive' variable of the returned 'DataBlk' object. If a
		/// code-block is progressive it means that in a later request to this
		/// method for the same code-block it is possible to retrieve data which is
		/// a better approximation, since meanwhile more data to decode for the
		/// code-block could have been received. If the code-block is not
		/// progressive then later calls to this method for the same code-block
		/// will return the exact same data values.
		/// 
		/// <P>The data returned by this method is always a copy of the internal
		/// data of this object, if any, and it can be modified "in place" without
		/// any problems after being returned. The 'offset' of the returned data is
		/// 0, and the 'scanw' is the same as the code-block width. See the
		/// 'DataBlk' class.
		/// 
		/// <P>The 'ulx' and 'uly' members of the returned 'DataBlk' object
		/// contain the coordinates of the top-left corner of the block, with
		/// respect to the tile, not the subband.
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="m">The vertical index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="n">The horizontal index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="sb">The subband in which the code-block to return is.
		/// 
		/// </param>
		/// <param name="cblk">If non-null this object will be used to return the new
		/// code-block. If null a new one will be allocated and returned. If the
		/// "data" array of the object is non-null it will be reused, if possible,
		/// to return the data.
		/// 
		/// </param>
		/// <returns> The next code-block in the current tile for component 'n', or
		/// null if all code-blocks for the current tile have been returned.
		/// 
		/// </returns>
		/// <seealso cref="DataBlk">
		/// 
		/// </seealso>
		public override DataBlk getCodeBlock(int c, int m, int n, SubbandSyn sb, DataBlk cblk)
		{
			//long stime = 0L; // Start time for timed sections
			int[] zc_lut; // The ZC lookup table to use
			int[] out_data; // The outupt data buffer
			int npasses; // The number of coding passes to perform
			int curbp; // The current magnitude bit-plane (starts at 30)
			bool error; // Error indicator
			int tslen; // Length of first terminated segment
			int tsidx; // Index of current terminated segment
			ByteInputBuffer in_Renamed = null;
			
			bool isterm;
			
			// Get the code-block to decode
			srcblk = src.getCodeBlock(c, m, n, sb, 1, - 1, srcblk);
			
#if DO_TIMING
			stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
#endif

			// Retrieve options from decSpec
			options = ((System.Int32) decSpec.ecopts.getTileCompVal(tIdx, c));
			
			// Reset state
			ArrayUtil.intArraySet(state, 0);
			
			// Initialize output code-block
			if (cblk == null)
				cblk = new DataBlkInt();
			cblk.progressive = srcblk.prog;
			cblk.ulx = srcblk.ulx;
			cblk.uly = srcblk.uly;
			cblk.w = srcblk.w;
			cblk.h = srcblk.h;
			cblk.offset = 0;
			cblk.scanw = cblk.w;
			out_data = (int[]) cblk.Data;
			
			if (out_data == null || out_data.Length < srcblk.w * srcblk.h)
			{
				out_data = new int[srcblk.w * srcblk.h];
				cblk.Data = out_data;
			}
			else
			{
				// Set data values to 0
				ArrayUtil.intArraySet(out_data, 0);
			}
			
			if (srcblk.nl <= 0 || srcblk.nTrunc <= 0)
			{
				// 0 layers => no data to decode => return all 0s
				return cblk;
			}
			
			// Get the length of the first terminated segment
			tslen = (srcblk.tsLengths == null)?srcblk.dl:srcblk.tsLengths[0];
			tsidx = 0;
			// Initialize for decoding
			npasses = srcblk.nTrunc;
			if (mq == null)
			{
				in_Renamed = new ByteInputBuffer(srcblk.data, 0, tslen);
				mq = new MQDecoder(in_Renamed, NUM_CTXTS, MQ_INIT);
			}
			else
			{
				// We always start by an MQ segment
				mq.nextSegment(srcblk.data, 0, tslen);
				mq.resetCtxts();
			}
			error = false;
			
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0)
			{
				if (bin == null)
				{
					if (in_Renamed == null)
						in_Renamed = mq.ByteInputBuffer;
					bin = new ByteToBitInput(in_Renamed);
				}
			}
			
			// Choose correct ZC lookup table for global orientation
			switch (sb.orientation)
			{
				
				case Subband.WT_ORIENT_HL: 
					zc_lut = ZC_LUT_HL;
					break;
				
				case Subband.WT_ORIENT_LH: 
				case Subband.WT_ORIENT_LL: 
					zc_lut = ZC_LUT_LH;
					break;
				
				case Subband.WT_ORIENT_HH: 
					zc_lut = ZC_LUT_HH;
					break;
				
				default: 
					throw new System.ApplicationException("JJ2000 internal error");
				
			}
			
			// NOTE: we don't currently detect which is the last magnitude
			// bit-plane so that 'isterm' is true for the last pass of it. Doing
			// so would aid marginally in error detection with the predictable
			// error resilient MQ termination. However, determining which is the
			// last magnitude bit-plane is quite hard (due to ROI, quantization,
			// etc.)  and in any case the predictable error resilient termination
			// used without the arithmetic coding bypass and/or regular
			// termination modes is almost useless.
			
			// Loop on bit-planes and passes
			
			curbp = 30 - srcblk.skipMSBP;
			
			// Check for maximum number of bitplanes quit condition
			if (mQuit != - 1 && (mQuit * 3 - 2) < npasses)
			{
				npasses = mQuit * 3 - 2;
			}
			
			// First bit-plane has only the cleanup pass
			if (curbp >= 0 && npasses > 0)
			{
				isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP) >= curbp);
				error = cleanuppass(cblk, mq, curbp, state, zc_lut, isterm);
				npasses--;
				if (!error || !doer)
					curbp--;
			}
			
			// Other bit-planes have the three coding passes
			if (!error || !doer)
			{
				while (curbp >= 0 && npasses > 0)
				{
					
					if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (curbp < 31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP))
					{
						// Use bypass decoding mode (only all bit-planes
						// after the first 4 bit-planes).
						
						// Here starts a new raw segment
						bin.setByteArray(null, - 1, srcblk.tsLengths[++tsidx]);
						isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0;
						error = rawSigProgPass(cblk, bin, curbp, state, isterm);
						npasses--;
						if (npasses <= 0 || (error && doer))
							break;
						
						if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0)
						{
							// Start a new raw segment
							bin.setByteArray(null, - 1, srcblk.tsLengths[++tsidx]);
						}
						isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP > curbp));
						error = rawMagRefPass(cblk, bin, curbp, state, isterm);
					}
					else
					{
						// Do not use bypass decoding mode
						if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0)
						{
							// Here starts a new MQ segment
							mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]);
						}
						isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0;
						error = sigProgPass(cblk, mq, curbp, state, zc_lut, isterm);
						npasses--;
						if (npasses <= 0 || (error && doer))
							break;
						
						if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0)
						{
							// Here starts a new MQ segment
							mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]);
						}
						isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP > curbp));
						error = magRefPass(cblk, mq, curbp, state, isterm);
					}
					
					npasses--;
					if (npasses <= 0 || (error && doer))
						break;
					
					if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (curbp < 31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP)))
					{
						// Here starts a new MQ segment
						mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]);
					}
					isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP) >= curbp);
					error = cleanuppass(cblk, mq, curbp, state, zc_lut, isterm);
					npasses--;
					if (error && doer)
						break;
					// Goto next bit-plane
					curbp--;
				}
			}
			
			// If an error ocurred conceal it
			if (error && doer)
			{
				if (verber)
				{
					FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Error detected at bit-plane " + curbp + " in code-block (" + m + "," + n + "), sb_idx " + sb.sbandIdx + ", res. level " + sb.resLvl + ". Concealing...");
				}
				conceal(cblk, curbp);
			}
			
#if DO_TIMING
			time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
#endif
			
			// Return decoded block
			return cblk;
		}
		/// <summary> Initialises subbands fields, such as number of code-blocks, code-blocks
		/// dimension and number of magnitude bits, in the subband tree. The
		/// nominal code-block width/height depends on the precincts dimensions if
		/// used. The way the number of magnitude bits is computed depends on the
		/// quantization type (reversible, derived, expounded).
		/// 
		/// </summary>
		/// <param name="c">The component index
		/// 
		/// </param>
		/// <param name="sb">The subband tree to be initialised.
		/// 
		/// </param>
		protected internal virtual void  initSubbandsFields(int c, SubbandSyn sb)
		{
			int t = TileIdx;
			int rl = sb.resLvl;
			int cbw, cbh;
			
			cbw = decSpec.cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, t, c);
			cbh = decSpec.cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, t, c);
			
			if (!sb.isNode)
			{
				// Code-block dimensions
				if (hd.precinctPartitionUsed())
				{
					// The precinct partition is used
					int ppxExp, ppyExp, cbwExp, cbhExp;
					
					// Get exponents
					ppxExp = MathUtil.log2(getPPX(t, c, rl));
					ppyExp = MathUtil.log2(getPPY(t, c, rl));
					cbwExp = MathUtil.log2(cbw);
					cbhExp = MathUtil.log2(cbh);
					
					switch (sb.resLvl)
					{
						
						case 0: 
							sb.nomCBlkW = (cbwExp < ppxExp?(1 << cbwExp):(1 << ppxExp));
							sb.nomCBlkH = (cbhExp < ppyExp?(1 << cbhExp):(1 << ppyExp));
							break;
						
						
						default: 
							sb.nomCBlkW = (cbwExp < ppxExp - 1?(1 << cbwExp):(1 << (ppxExp - 1)));
							sb.nomCBlkH = (cbhExp < ppyExp - 1?(1 << cbhExp):(1 << (ppyExp - 1)));
							break;
						
					}
				}
				else
				{
					sb.nomCBlkW = cbw;
					sb.nomCBlkH = cbh;
				}
				
				// Number of code-blocks
				if (sb.numCb == null)
					sb.numCb = new Coord();
				if (sb.w == 0 || sb.h == 0)
				{
					sb.numCb.x = 0;
					sb.numCb.y = 0;
				}
				else
				{
					int cb0x = CbULX;
					int cb0y = CbULY;
					int tmp;
					
					// Projects code-block partition origin to subband. Since the
					// origin is always 0 or 1, it projects to the low-pass side
					// (throught the ceil operator) as itself (i.e. no change) and
					// to the high-pass side (through the floor operator) as 0,
					// always.
					int acb0x = cb0x;
					int acb0y = cb0y;
					
					switch (sb.sbandIdx)
					{
						
						case Subband.WT_ORIENT_LL: 
							// No need to project since all low-pass => nothing to do
							break;
						
						case Subband.WT_ORIENT_HL: 
							acb0x = 0;
							break;
						
						case Subband.WT_ORIENT_LH: 
							acb0y = 0;
							break;
						
						case Subband.WT_ORIENT_HH: 
							acb0x = 0;
							acb0y = 0;
							break;
						
						default: 
							throw new System.ApplicationException("Internal JJ2000 error");
						
					}
					if (sb.ulcx - acb0x < 0 || sb.ulcy - acb0y < 0)
					{
						throw new System.ArgumentException("Invalid code-blocks " + "partition origin or " + "image offset in the " + "reference grid.");
					}
					
					// NOTE: when calculating "floor()" by integer division the
					// dividend and divisor must be positive, we ensure that by
					// adding the divisor to the dividend and then substracting 1
					// to the result of the division
					
					tmp = sb.ulcx - acb0x + sb.nomCBlkW;
					sb.numCb.x = (tmp + sb.w - 1) / sb.nomCBlkW - (tmp / sb.nomCBlkW - 1);
					
					tmp = sb.ulcy - acb0y + sb.nomCBlkH;
					sb.numCb.y = (tmp + sb.h - 1) / sb.nomCBlkH - (tmp / sb.nomCBlkH - 1);
				}
				
				// Number of magnitude bits
				if (derived[c])
				{
					sb.magbits = gb[c] + (params_Renamed[c].exp[0][0] - (mdl[c] - sb.level)) - 1;
				}
				else
				{
					sb.magbits = gb[c] + params_Renamed[c].exp[sb.resLvl][sb.sbandIdx] - 1;
				}
			}
			else
			{
				initSubbandsFields(c, (SubbandSyn) sb.LL);
				initSubbandsFields(c, (SubbandSyn) sb.HL);
				initSubbandsFields(c, (SubbandSyn) sb.LH);
				initSubbandsFields(c, (SubbandSyn) sb.HH);
			}
		}
        /// <summary> Performs the inverse wavelet transform on the whole component. It
        /// iteratively reconstructs the subbands from leaves up to the root
        /// node. This method is recursive, the first call to it the 'sb' must be
        /// the root of the subband tree. The method will then process the entire
        /// subband tree by calling itslef recursively.
        ///
        /// </summary>
        /// <param name="img">The buffer for the image/wavelet data.
        ///
        /// </param>
        /// <param name="sb">The subband to reconstruct.
        ///
        /// </param>
        /// <param name="c">The index of the component to reconstruct
        ///
        /// </param>
        private void waveletTreeReconstruction(DataBlk img, SubbandSyn sb, int c)
        {
            DataBlk subbData;

            // If the current subband is a leaf then get the data from the source
            if (!sb.isNode)
            {
                int           i, m, n;
                System.Object src_data, dst_data;
                Coord         ncblks;

                if (sb.w == 0 || sb.h == 0)
                {
                    return; // If empty subband do nothing
                }

                // Get all code-blocks in subband
                if (dtype == DataBlk.TYPE_INT)
                {
                    subbData = new DataBlkInt();
                }
                else
                {
                    subbData = new DataBlkFloat();
                }
                ncblks   = sb.numCb;
                dst_data = img.Data;
                for (m = 0; m < ncblks.y; m++)
                {
                    for (n = 0; n < ncblks.x; n++)
                    {
                        subbData = src.getInternCodeBlock(c, m, n, sb, subbData);
                        src_data = subbData.Data;
                        if (pw != null)
                        {
                            nDecCblk++;
                            pw.updateProgressWatch(nDecCblk, null);
                        }
                        // Copy the data line by line
                        for (i = subbData.h - 1; i >= 0; i--)
                        {
                            // CONVERSION PROBLEM
                            Array.Copy((System.Array)src_data, subbData.offset + i * subbData.scanw, (System.Array)dst_data, (subbData.uly + i) * img.w + subbData.ulx, subbData.w);
                        }
                    }
                }
            }
            else if (sb.isNode)
            {
                // Reconstruct the lower resolution levels if the current subbands
                // is a node

                //Perform the reconstruction of the LL subband
                waveletTreeReconstruction(img, (SubbandSyn)sb.LL, c);

                if (sb.resLvl <= reslvl - maxImgRes + ndl[c])
                {
                    //Reconstruct the other subbands
                    waveletTreeReconstruction(img, (SubbandSyn)sb.HL, c);
                    waveletTreeReconstruction(img, (SubbandSyn)sb.LH, c);
                    waveletTreeReconstruction(img, (SubbandSyn)sb.HH, c);

                    //Perform the 2D wavelet decomposition of the current subband
                    wavelet2DReconstruction(img, (SubbandSyn)sb, c);
                }
            }
        }
        /// <summary> Performs the 2D inverse wavelet transform on a subband of the image, on
        /// the specified component. This method will successively perform 1D
        /// filtering steps on all columns and then all lines of the subband.
        ///
        /// </summary>
        /// <param name="db">the buffer for the image/wavelet data.
        ///
        /// </param>
        /// <param name="sb">The subband to reconstruct.
        ///
        /// </param>
        /// <param name="c">The index of the component to reconstruct
        ///
        /// </param>
        private void wavelet2DReconstruction(DataBlk db, SubbandSyn sb, int c)
        {
            System.Object data;
            System.Object buf;
            int           ulx, uly, w, h;
            int           i, j, k;
            int           offset;

            // If subband is empty (i.e. zero size) nothing to do
            if (sb.w == 0 || sb.h == 0)
            {
                return;
            }

            data = db.Data;

            ulx = sb.ulx;
            uly = sb.uly;
            w   = sb.w;
            h   = sb.h;

            buf = null; // To keep compiler happy

            switch (sb.HorWFilter.DataType)
            {
            case DataBlk.TYPE_INT:
                buf = new int[(w >= h) ? w : h];
                break;

            case DataBlk.TYPE_FLOAT:
                buf = new float[(w >= h) ? w : h];
                break;
            }

            //Perform the horizontal reconstruction
            offset = (uly - db.uly) * db.w + ulx - db.ulx;
            if (sb.ulcx % 2 == 0)
            {
                // start index is even => use LPF
                for (i = 0; i < h; i++, offset += db.w)
                {
                    // CONVERSION PROBLEM?
                    Array.Copy((System.Array)data, offset, (System.Array)buf, 0, w);
                    sb.hFilter.synthetize_lpf(buf, 0, (w + 1) / 2, 1, buf, (w + 1) / 2, w / 2, 1, data, offset, 1);
                }
            }
            else
            {
                // start index is odd => use HPF
                for (i = 0; i < h; i++, offset += db.w)
                {
                    // CONVERSION PROBLEM?
                    Array.Copy((System.Array)data, offset, (System.Array)buf, 0, w);
                    sb.hFilter.synthetize_hpf(buf, 0, w / 2, 1, buf, w / 2, (w + 1) / 2, 1, data, offset, 1);
                }
            }

            //Perform the vertical reconstruction
            offset = (uly - db.uly) * db.w + ulx - db.ulx;
            switch (sb.VerWFilter.DataType)
            {
            case DataBlk.TYPE_INT:
                int[] data_int, buf_int;
                data_int = (int[])data;
                buf_int  = (int[])buf;
                if (sb.ulcy % 2 == 0)
                {
                    // start index is even => use LPF
                    for (j = 0; j < w; j++, offset++)
                    {
                        for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                        {
                            buf_int[i] = data_int[k];
                        }
                        sb.vFilter.synthetize_lpf(buf, 0, (h + 1) / 2, 1, buf, (h + 1) / 2, h / 2, 1, data, offset, db.w);
                    }
                }
                else
                {
                    // start index is odd => use HPF
                    for (j = 0; j < w; j++, offset++)
                    {
                        for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                        {
                            buf_int[i] = data_int[k];
                        }
                        sb.vFilter.synthetize_hpf(buf, 0, h / 2, 1, buf, h / 2, (h + 1) / 2, 1, data, offset, db.w);
                    }
                }
                break;

            case DataBlk.TYPE_FLOAT:
                float[] data_float, buf_float;
                data_float = (float[])data;
                buf_float  = (float[])buf;
                if (sb.ulcy % 2 == 0)
                {
                    // start index is even => use LPF
                    for (j = 0; j < w; j++, offset++)
                    {
                        for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                        {
                            buf_float[i] = data_float[k];
                        }
                        sb.vFilter.synthetize_lpf(buf, 0, (h + 1) / 2, 1, buf, (h + 1) / 2, h / 2, 1, data, offset, db.w);
                    }
                }
                else
                {
                    // start index is odd => use HPF
                    for (j = 0; j < w; j++, offset++)
                    {
                        for (i = h - 1, k = offset + i * db.w; i >= 0; i--, k -= db.w)
                        {
                            buf_float[i] = data_float[k];
                        }
                        sb.vFilter.synthetize_hpf(buf, 0, h / 2, 1, buf, h / 2, (h + 1) / 2, 1, data, offset, db.w);
                    }
                }
                break;
            }
        }
		/// <summary> Returns the specified code-block in the current tile for the specified
		/// component (as a reference or copy).
		/// 
		/// <p>The returned code-block may be progressive, which is indicated by
		/// the 'progressive' variable of the returned 'DataBlk'
		/// object. If a code-block is progressive it means that in a later request
		/// to this method for the same code-block it is possible to retrieve data
		/// which is a better approximation, since meanwhile more data to decode
		/// for the code-block could have been received. If the code-block is not
		/// progressive then later calls to this method for the same code-block
		/// will return the exact same data values.</p>
		/// 
		/// <p>The data returned by this method can be the data in the internal
		/// buffer of this object, if any, and thus can not be modified by the
		/// caller. The 'offset' and 'scanw' of the returned data can be
		/// arbitrary. See the 'DataBlk' class.</p>
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="m">The vertical index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="n">The horizontal index of the code-block to return, in the
		/// specified subband.
		/// 
		/// </param>
		/// <param name="sb">The subband in which the code-block to return is.
		/// 
		/// </param>
		/// <param name="cblk">If non-null this object will be used to return the new
		/// code-block. If null a new one will be allocated and returned. If the
		/// "data" array of the object is non-null it will be reused, if possible,
		/// to return the data.
		/// 
		/// </param>
		/// <returns> The next code-block in the current tile for component 'n', or
		/// null if all code-blocks for the current tile have been returned.
		/// 
		/// </returns>
		/// <seealso cref="DataBlk">
		/// 
		/// </seealso>
		public override DataBlk getInternCodeBlock(int c, int m, int n, SubbandSyn sb, DataBlk cblk)
		{
			// This method is declared final since getNextCodeBlock() relies on
			// the actual implementation of this method.
			int j, jmin, k;
			int temp;
			float step;
			int shiftBits;
			int magBits;
			int[] outiarr, inarr;
			float[] outfarr;
			int w, h;
			bool reversible = qts.isReversible(tIdx, c);
			bool derived = qts.isDerived(tIdx, c);
			StdDequantizerParams params_Renamed = (StdDequantizerParams) qsss.getTileCompVal(tIdx, c);
			int G = ((System.Int32) gbs.getTileCompVal(tIdx, c));
			
			outdtype = cblk.DataType;
			
			if (reversible && outdtype != DataBlk.TYPE_INT)
			{
				throw new System.ArgumentException("Reversible quantizations " + "must use int data");
			}
			
			// To get compiler happy
			outiarr = null;
			outfarr = null;
			inarr = null;
			
			// Get source data and initialize output DataBlk object.
			switch (outdtype)
			{
				
				case DataBlk.TYPE_INT: 
					// With int data we can use the same DataBlk object to get the
					// data from the source and return the dequantized data, and we
					// can also work "in place" (i.e. same buffer).
					cblk = src.getCodeBlock(c, m, n, sb, cblk);
					// Input and output arrays are the same
					outiarr = (int[]) cblk.Data;
					break;
				
				case DataBlk.TYPE_FLOAT: 
					// With float data we must use a different DataBlk objects to get
					// the data from the source and to return the dequantized data.
					inblk = (DataBlkInt) src.getInternCodeBlock(c, m, n, sb, inblk);
					inarr = inblk.DataInt;
					if (cblk == null)
					{
						cblk = new DataBlkFloat();
					}
					// Copy the attributes of the CodeBlock object
					cblk.ulx = inblk.ulx;
					cblk.uly = inblk.uly;
					cblk.w = inblk.w;
					cblk.h = inblk.h;
					cblk.offset = 0;
					cblk.scanw = cblk.w;
					cblk.progressive = inblk.progressive;
					// Get output data array and check its size
					outfarr = (float[]) cblk.Data;
					if (outfarr == null || outfarr.Length < cblk.w * cblk.h)
					{
						outfarr = new float[cblk.w * cblk.h];
						cblk.Data = outfarr;
					}
					break;
				}
			
			magBits = sb.magbits;
			
			// Calculate quantization step and number of magnitude bits
			// depending on reversibility and derivedness and perform
			// inverse quantization
			if (reversible)
			{
				shiftBits = 31 - magBits;
				// For int data Inverse quantization happens "in-place". The input
				// array has an offset of 0 and scan width equal to the code-block
				// width.
				for (j = outiarr.Length - 1; j >= 0; j--)
				{
					temp = outiarr[j]; // input array is same as output one
					outiarr[j] = (temp >= 0)?(temp >> shiftBits):- ((temp & 0x7FFFFFFF) >> shiftBits);
				}
			}
			else
			{
				// Not reversible 
				if (derived)
				{
					// Max resolution level
					int mrl = src.getSynSubbandTree(TileIdx, c).resLvl;
					step = params_Renamed.nStep[0][0] * (1L << (rb[c] + sb.anGainExp + mrl - sb.level));
				}
				else
				{
					step = params_Renamed.nStep[sb.resLvl][sb.sbandIdx] * (1L << (rb[c] + sb.anGainExp));
				}
				shiftBits = 31 - magBits;
				
				// Adjust step to the number of shiftBits
				step /= (1 << shiftBits);
				
				switch (outdtype)
				{
					
					case DataBlk.TYPE_INT: 
						// For int data Inverse quantization happens "in-place". The
						// input array has an offset of 0 and scan width equal to the
						// code-block width.
						for (j = outiarr.Length - 1; j >= 0; j--)
						{
							temp = outiarr[j]; // input array is same as output one
							//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
							outiarr[j] = (int) (((float) ((temp >= 0)?temp:- (temp & 0x7FFFFFFF))) * step);
						}
						break;
					
					case DataBlk.TYPE_FLOAT: 
						// For float data the inverse quantization can not happen
						// "in-place".
						w = cblk.w;
						h = cblk.h;
						for (j = w * h - 1, k = inblk.offset + (h - 1) * inblk.scanw + w - 1, jmin = w * (h - 1); j >= 0; jmin -= w)
						{
							for (; j >= jmin; k--, j--)
							{
								temp = inarr[k];
								//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
								outfarr[j] = ((float) ((temp >= 0)?temp:- (temp & 0x7FFFFFFF))) * step;
							}
							// Jump to beggining of previous line in input
							k -= (inblk.scanw - w);
						}
						break;
					}
			}
			// Return the output code-block
			return cblk;
		}