/// <summary> Returns the next code-block in the current tile for the specified /// component. The order in which code-blocks are returned is not /// specified. However each code-block is returned only once and all /// code-blocks will be returned if the method is called 'N' times, where /// 'N' is the number of code-blocks in the tile. After all the code-blocks /// have been returned for the current tile calls to this method will /// return 'null'. /// /// <p>When changing the current tile (through 'setTile()' or 'nextTile()') /// this method will always return the first code-block, as if this method /// was never called before for the new current tile.</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 'CBlkWTData' class.</p> /// /// <p>The 'ulx' and 'uly' members of the returned 'CBlkWTData' 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="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="CBlkWTData"> /// /// </seealso> public override CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk) { // NOTE: this method is declared final since getNextCodeBlock() relies // on this particular implementation int k, j; int tmp, shiftBits, jmin; int w, h; int[] outarr; float[] infarr = null; CBlkWTDataFloat infblk; float invstep; // The inverse of the quantization step size bool intq; // flag for quantizig ints SubbandAn sb; float stepUDR; // The quantization step size (for a dynamic // range of 1, or unit) int g = ((System.Int32)gbs.getTileCompVal(tIdx, c)); // Are we quantizing ints or floats? intq = (src.getDataType(tIdx, c) == DataBlk.TYPE_INT); // Check that we have an output object if (cblk == null) { cblk = new CBlkWTDataInt(); } // Cache input float code-block infblk = this.infblk; // Get data to quantize. When quantizing int data 'cblk' is used to // get the data to quantize and to return the quantized data as well, // that's why 'getNextCodeBlock()' is used. This can not be done when // quantizing float data because of the different data types, that's // why 'getNextInternCodeBlock()' is used in that case. if (intq) { // Source data is int cblk = src.getNextCodeBlock(c, cblk); if (cblk == null) { return(null); // No more code-blocks in current tile for comp. } // Input and output arrays are the same (for "in place" quant.) outarr = (int[])cblk.Data; } else { // Source data is float // Can not use 'cblk' to get float data, use 'infblk' infblk = (CBlkWTDataFloat)src.getNextInternCodeBlock(c, infblk); if (infblk == null) { // Release buffer from infblk: this enables to garbage collect // the big buffer when we are done with last code-block of // component. this.infblk.Data = null; return(null); // No more code-blocks in current tile for comp. } this.infblk = infblk; // Save local cache infarr = (float[])infblk.Data; // Get output data array and check that there is memory to put the // quantized coeffs in outarr = (int[])cblk.Data; if (outarr == null || outarr.Length < infblk.w * infblk.h) { outarr = new int[infblk.w * infblk.h]; cblk.Data = outarr; } cblk.m = infblk.m; cblk.n = infblk.n; cblk.sb = infblk.sb; cblk.ulx = infblk.ulx; cblk.uly = infblk.uly; cblk.w = infblk.w; cblk.h = infblk.h; cblk.wmseScaling = infblk.wmseScaling; cblk.offset = 0; cblk.scanw = cblk.w; } // Cache width, height and subband of code-block w = cblk.w; h = cblk.h; sb = cblk.sb; if (isReversible(tIdx, c)) { // Reversible only for int data cblk.magbits = g - 1 + src.getNomRangeBits(c) + sb.anGainExp; shiftBits = 31 - cblk.magbits; // Update the convertFactor field cblk.convertFactor = (1 << shiftBits); // Since we used getNextCodeBlock() to get the int data then // 'offset' is 0 and 'scanw' is the width of the code-block The // input and output arrays are the same (i.e. "in place") for (j = w * h - 1; j >= 0; j--) { tmp = (outarr[j] << shiftBits); outarr[j] = ((tmp < 0)?(1 << 31) | (-tmp):tmp); } } else { // Non-reversible, use step size //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" float baseStep = (float)((System.Single)qsss.getTileCompVal(tIdx, c)); // Calculate magnitude bits and quantization step size if (isDerived(tIdx, c)) { //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'" cblk.magbits = g - 1 + sb.level - (int)System.Math.Floor(System.Math.Log(baseStep) / log2); stepUDR = baseStep / (1 << sb.level); } else { //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'" cblk.magbits = g - 1 - (int)System.Math.Floor(System.Math.Log(baseStep / (sb.l2Norm * (1 << sb.anGainExp))) / log2); stepUDR = baseStep / (sb.l2Norm * (1 << sb.anGainExp)); } shiftBits = 31 - cblk.magbits; // Calculate step that decoder will get and use that one. stepUDR = convertFromExpMantissa(convertToExpMantissa(stepUDR)); invstep = 1.0f / ((1L << (src.getNomRangeBits(c) + sb.anGainExp)) * stepUDR); // Normalize to magnitude bits (output fractional point) invstep *= (1 << (shiftBits - src.getFixedPoint(c))); // Update convertFactor and stepSize fields cblk.convertFactor = invstep; cblk.stepSize = ((1L << (src.getNomRangeBits(c) + sb.anGainExp)) * stepUDR); if (intq) { // Quantizing int data // Since we used getNextCodeBlock() to get the int data then // 'offset' is 0 and 'scanw' is the width of the code-block // The input and output arrays are the same (i.e. "in place") for (j = w * h - 1; j >= 0; j--) { //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'" tmp = (int)(outarr[j] * invstep); outarr[j] = ((tmp < 0)?(1 << 31) | (-tmp):tmp); } } else { // Quantizing float data for (j = w * h - 1, k = infblk.offset + (h - 1) * infblk.scanw + w - 1, jmin = w * (h - 1); j >= 0; jmin -= w) { for (; j >= jmin; k--, j--) { //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'" tmp = (int)(infarr[k] * invstep); outarr[j] = ((tmp < 0)?(1 << 31) | (-tmp):tmp); } // Jump to beggining of previous line in input k -= (infblk.scanw - w); } } } // Return the quantized code-block return(cblk); }
/// <summary> This function gets a datablk from the entropy coder. The sample sin the /// block, which consists of the quantized coefficients from the quantizer, /// are scaled by the values given for any ROIs specified. /// /// <p>The function calls on a ROIMaskGenerator to get the mask for scaling /// the coefficients in the current block.</p> /// /// </summary> /// <param name="c">The component for which to return the next code-block. /// /// </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="CBlkWTData"> /// /// </seealso> public virtual CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk) { int mi, i, j, k, wrap; int ulx, uly, w, h; DataBlkInt mask = roiMask; // local copy of mask int[] maskData; // local copy of mask data int[] data; // local copy of quantized data int tmp; int bitMask = 0x7FFFFFFF; SubbandAn root, sb; int maxBits = 0; // local copy bool roiInTile; bool sbInMask; int nROIcoeff = 0; // Get codeblock's data from quantizer cblk = src.getNextCodeBlock(c, cblk); // If there is no ROI in the image, or if we already got all // code-blocks if (!roi || cblk == null) { return(cblk); } data = (int[])cblk.Data; sb = cblk.sb; ulx = cblk.ulx; uly = cblk.uly; w = cblk.w; h = cblk.h; sbInMask = (sb.resLvl <= useStartLevel); // Check that there is an array for the mask and set it to zero maskData = mask.DataInt; // local copy of mask data if (maskData == null || w * h > maskData.Length) { maskData = new int[w * h]; mask.DataInt = maskData; } else { for (i = w * h - 1; i >= 0; i--) { maskData[i] = 0; } } mask.ulx = ulx; mask.uly = uly; mask.w = w; mask.h = h; // Get ROI mask from generator root = src.getAnSubbandTree(tIdx, c); maxBits = maxMagBits[tIdx][c]; roiInTile = mg.getROIMask(mask, root, maxBits, c); // If there is no ROI in this tile, return the code-block untouched if (!roiInTile && (!sbInMask)) { cblk.nROIbp = 0; return(cblk); } // Update field containing the number of ROI magnitude bit-planes cblk.nROIbp = cblk.magbits; // If the entire subband belongs to the ROI mask, The code-block is // set to belong entirely to the ROI with the highest scaling value if (sbInMask) { // Scale the wmse so that instead of scaling the coefficients, the // wmse is scaled. //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'" cblk.wmseScaling *= (float)(1 << (maxBits << 1)); cblk.nROIcoeff = w * h; return(cblk); } // In 'block aligned' mode, the code-block is set to belong entirely // to the ROI with the highest scaling value if one coefficient, at // least, belongs to the ROI if (blockAligned) { wrap = cblk.scanw - w; mi = h * w - 1; i = cblk.offset + cblk.scanw * (h - 1) + w - 1; int nroicoeff = 0; for (j = h; j > 0; j--) { for (k = w - 1; k >= 0; k--, i--, mi--) { if (maskData[mi] != 0) { nroicoeff++; } } i -= wrap; } if (nroicoeff != 0) { // Include the subband //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'" cblk.wmseScaling *= (float)(1 << (maxBits << 1)); cblk.nROIcoeff = w * h; } return(cblk); } // Scale background coefficients bitMask = (((1 << cblk.magbits) - 1) << (31 - cblk.magbits)); wrap = cblk.scanw - w; mi = h * w - 1; i = cblk.offset + cblk.scanw * (h - 1) + w - 1; for (j = h; j > 0; j--) { for (k = w; k > 0; k--, i--, mi--) { tmp = data[i]; if (maskData[mi] != 0) { // ROI coeff. We need to erase fractional bits to ensure // that they do not conflict with BG coeffs. This is only // strictly necessary for ROI coeffs. which non-fractional // magnitude is zero, but much better BG quality can be // achieved if done if reset to zero since coding zeros is // much more efficient (the entropy coder knows nothing // about ROI and cannot avoid coding the ROI fractional // bits, otherwise this would not be necessary). data[i] = (unchecked ((int)0x80000000) & tmp) | (tmp & bitMask); nROIcoeff++; } else { // BG coeff. it is not necessary to erase fractional bits data[i] = (unchecked ((int)0x80000000) & tmp) | ((tmp & 0x7FFFFFFF) >> maxBits); } } i -= wrap; } // Modify the number of significant bit-planes in the code-block cblk.magbits += maxBits; // Store the number of ROI coefficients present in the code-block cblk.nROIcoeff = nROIcoeff; return(cblk); }
/// <summary> Returns the next code-block in the current tile for the specified /// component, as a copy (see below). The order in which code-blocks are /// returned is not specified. However each code-block is returned only /// once and all code-blocks will be returned if the method is called 'N' /// times, where 'N' is the number of code-blocks in the tile. After all /// the code-blocks have been returned for the current tile calls to this /// method will return 'null'. /// /// <p>When changing the current tile (through 'setTile()' or 'nextTile()') /// this method will always return the first code-block, as if this method /// was never called before for the new current tile.</p> /// /// <p>The data returned by this method is always a copy of the /// data. Therfore 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 'CBlkWTData' class.</p> /// /// <p>The 'ulx' and 'uly' members of the returned 'CBlkWTData' 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="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="CBlkWTData"> /// /// </seealso> public override CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk) { return(getNextInternCodeBlock(c, cblk)); }
/// <summary> This function gets a datablk from the entropy coder. The sample sin the /// block, which consists of the quantized coefficients from the quantizer, /// are scaled by the values given for any ROIs specified. /// /// <p>The function calls on a ROIMaskGenerator to get the mask for scaling /// the coefficients in the current block.</p> /// /// <p>The data returned by this method is a copy of the orignal /// data. Therfore 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 'CBlkWTData' class.</p> /// /// </summary> /// <param name="c">The component for which to return the next code-block. /// /// </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="CBlkWTData"> /// /// </seealso> public virtual CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk) { return(getNextInternCodeBlock(c, cblk)); }