Пример #1
0
        /// <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);
        }
Пример #3
0
 /// <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));
 }