/// <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);
/// <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; }
/// <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); }
/// <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); } } }
/// <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> 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; }