Example #1
0
        /// <summary> Apply the inverse component transformation associated with the current
        /// tile. If no component transformation has been requested by the user,
        /// data are not modified. Else, appropriate method is called (invRCT or
        /// invICT).
        ///
        /// </summary>
        /// <seealso cref="invRCT">
        ///
        /// </seealso>
        /// <seealso cref="invICT">
        ///
        /// </seealso>
        /// <param name="blk">Determines the rectangular area to return.
        ///
        /// </param>
        /// <param name="c">Index of the output component.
        ///
        /// </param>
        /// <returns> The requested DataBlk
        ///
        /// </returns>
        public virtual DataBlk getInternCompData(DataBlk blk, int c)
        {
            // if specified in the command line that no component transform should
            // be made, return original data
            if (noCompTransf)
            {
                return(src.getInternCompData(blk, c));
            }

            switch (transfType)
            {
            case NONE:
                return(src.getInternCompData(blk, c));


            case INV_RCT:
                return(invRCT(blk, c));

            case INV_ICT:
                return(invICT(blk, c));

            default:
                throw new System.ArgumentException("Non JPEG 2000 part I" + " component transformation");
            }
        }
Example #2
0
        /// <summary> Apply the component transformation associated with the current tile. If
        /// no component transformation has been requested by the user, data are
        /// not modified. Else, appropriate method is called (forwRCT or forwICT).
        ///
        /// </summary>
        /// <seealso cref="forwRCT">
        ///
        /// </seealso>
        /// <seealso cref="forwICT">
        ///
        /// </seealso>
        /// <param name="blk">Determines the rectangular area to return.
        ///
        /// </param>
        /// <param name="c">Index of the output component.
        ///
        /// </param>
        /// <returns> The requested DataBlk
        ///
        /// </returns>
        public virtual DataBlk getInternCompData(DataBlk blk, int c)
        {
            switch (transfType)
            {
            case NONE:
                return(src.getInternCompData(blk, c));

            case FORW_RCT:
                return(forwRCT(blk, c));

            case FORW_ICT:
                return(forwICT(blk, c));

            default:
                throw new System.ArgumentException("Non JPEG 2000 part 1 " + "component" + " transformation for tile: " + tIdx);
            }
        }
Example #3
0
        /// <summary> Returns, in the blk argument, a block of image data containing the
        /// specifed rectangular area, in the specified component. The data is
        /// returned, as a reference to the internal data, if any, instead of as a
        /// copy, therefore the returned data should not be modified.
        ///
        /// <p>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
        /// and 'h' members of the 'blk' argument, relative to the current
        /// tile. These members are not modified by this method. The 'offset' and
        /// 'scanw' of the returned data can be arbitrary. See the 'DataBlk'
        /// class.</p>
        ///
        /// <p>This method, in general, is more efficient than the 'getCompData()'
        /// method since it may not copy the data. However if the array of returned
        /// data is to be modified by the caller then the other method is probably
        /// preferable.</p>
        ///
        /// <p>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one
        /// is created if necessary. The implementation of this interface may
        /// choose to return the same array or a new one, depending on what is more
        /// efficient. Therefore, the data array in <tt>blk</tt> prior to the
        /// method call should not be considered to contain the returned data, a
        /// new array may have been created. Instead, get the array from
        /// <tt>blk</tt> after the method has returned.</p>
        ///
        /// <p>The returned data may have its 'progressive' attribute set. In this
        /// case the returned data is only an approximation of the "final"
        /// data.</p>
        ///
        /// </summary>
        /// <param name="blk">Its coordinates and dimensions specify the area to return,
        /// relative to the current tile. Some fields in this object are modified
        /// to return the data.
        ///
        /// </param>
        /// <param name="c">The index of the component from which to get the data.
        ///
        /// </param>
        /// <returns> The requested DataBlk
        ///
        /// </returns>
        /// <seealso cref="getCompData">
        ///
        /// </seealso>
        public DataBlk getInternCompData(DataBlk blk, int c)
        {
            // Check that block is inside tile
            if (blk.ulx < 0 || blk.uly < 0 || blk.w > compW[c] || blk.h > compH[c])
            {
                throw new System.ArgumentException("Block is outside the tile");
            }
            // Translate to the sources coordinates
            //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'"
            int incx = (int)System.Math.Ceiling(x0siz / (double)src.getCompSubsX(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'"
            int incy = (int)System.Math.Ceiling(y0siz / (double)src.getCompSubsY(c));

            blk.ulx -= incx;
            blk.uly -= incy;
            blk      = src.getInternCompData(blk, c);
            // Translate back to the tiled coordinates
            blk.ulx += incx;
            blk.uly += incy;
            return(blk);
        }
Example #4
0
        public static Image FromStream(Stream stream)
        {
            RandomAccessIO in_stream = new ISRandomAccessIO(stream);

            // Initialize default parameters
            ParameterList defpl = GetDefaultParameterList(decoder_pinfo);

            // Create parameter list using defaults
            ParameterList pl = new ParameterList(defpl);

            // **** File Format ****
            // If the codestream is wrapped in the jp2 fileformat, Read the
            // file format wrapper
            FileFormatReader ff = new FileFormatReader(in_stream);

            ff.readFileFormat();
            if (ff.JP2FFUsed)
            {
                in_stream.seek(ff.FirstCodeStreamPos);
            }

            // +----------------------------+
            // | Instantiate decoding chain |
            // +----------------------------+

            // **** Header decoder ****
            // Instantiate header decoder and read main header
            HeaderInfo    hi = new HeaderInfo();
            HeaderDecoder hd;

            try
            {
                hd = new HeaderDecoder(in_stream, pl, hi);
            }
            catch (EndOfStreamException e)
            {
                throw new ApplicationException("Codestream too short or bad header, unable to decode.", e);
            }

            int          nCompCod = hd.NumComps;
            int          nTiles   = hi.sizValue.NumTiles;
            DecoderSpecs decSpec  = hd.DecoderSpecs;

            // Get demixed bitdepths
            int[] depth = new int[nCompCod];
            for (int i = 0; i < nCompCod; i++)
            {
                depth[i] = hd.getOriginalBitDepth(i);
            }

            // **** Bit stream reader ****
            BitstreamReaderAgent breader;

            try
            {
                breader = BitstreamReaderAgent.
                          createInstance(in_stream, hd, pl, decSpec,
                                         false, hi);
            }
            catch (IOException e)
            {
                throw new ApplicationException("Error while reading bit stream header or parsing packets.", e);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate bit stream reader.", e);
            }

            // **** Entropy decoder ****
            EntropyDecoder entdec;

            try
            {
                entdec = hd.createEntropyDecoder(breader, pl);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate entropy decoder.", e);
            }

            // **** ROI de-scaler ****
            ROIDeScaler roids;

            try
            {
                roids = hd.createROIDeScaler(entdec, pl, decSpec);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate roi de-scaler.", e);
            }

            // **** Dequantizer ****
            Dequantizer deq;

            try
            {
                deq = hd.createDequantizer(roids, depth, decSpec);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate dequantizer.", e);
            }

            // **** Inverse wavelet transform ***
            InverseWT invWT;

            try
            {
                // full page inverse wavelet transform
                invWT = InverseWT.createInstance(deq, decSpec);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate inverse wavelet transform.", e);
            }

            int res = breader.ImgRes;

            invWT.ImgResLevel = res;

            // **** Data converter **** (after inverse transform module)
            ImgDataConverter converter = new ImgDataConverter(invWT, 0);

            // **** Inverse component transformation ****
            InvCompTransf ictransf = new InvCompTransf(converter, decSpec, depth, pl);

            // **** Color space mapping ****
            BlkImgDataSrc color;

            if (ff.JP2FFUsed && pl.getParameter("nocolorspace").Equals("off"))
            {
                try
                {
                    ColorSpace    csMap      = new ColorSpace(in_stream, hd, pl);
                    BlkImgDataSrc channels   = hd.createChannelDefinitionMapper(ictransf, csMap);
                    BlkImgDataSrc resampled  = hd.createResampler(channels, csMap);
                    BlkImgDataSrc palettized = hd.createPalettizedColorSpaceMapper(resampled, csMap);
                    color = hd.createColorSpaceMapper(palettized, csMap);
                }
                catch (ArgumentException e)
                {
                    throw new ApplicationException("Could not instantiate ICC profiler.", e);
                }
                catch (ColorSpaceException e)
                {
                    throw new ApplicationException("Error processing ColorSpace information.", e);
                }
            }
            else
            { // Skip colorspace mapping
                color = ictransf;
            }

            // This is the last image in the decoding chain and should be
            // assigned by the last transformation:
            BlkImgDataSrc decodedImage = color;

            if (color == null)
            {
                decodedImage = ictransf;
            }
            int numComps      = decodedImage.NumComps;
            int bytesPerPixel = numComps; // Assuming 8-bit components

            // **** Copy to Bitmap ****
            PixelFormat pixelFormat;

            switch (numComps)
            {
            case 1:
                pixelFormat = PixelFormat.Format24bppRgb; break;

            case 3:
                pixelFormat = PixelFormat.Format24bppRgb; break;

            case 4:
            case 5:
                pixelFormat = PixelFormat.Format32bppArgb; break;

            default:
                throw new ApplicationException("Unsupported PixelFormat.  " + numComps + " components.");
            }

            Bitmap dst = new Bitmap(decodedImage.ImgWidth, decodedImage.ImgHeight, pixelFormat);

            Coord numTiles = decodedImage.getNumTiles(null);

            int tIdx = 0;

            for (int y = 0; y < numTiles.y; y++)
            {
                // Loop on horizontal tiles
                for (int x = 0; x < numTiles.x; x++, tIdx++)
                {
                    decodedImage.setTile(x, y);

                    int height = decodedImage.getTileCompHeight(tIdx, 0);
                    int width  = decodedImage.getTileCompWidth(tIdx, 0);

                    int tOffx = decodedImage.getCompULX(0) -
                                (int)Math.Ceiling(decodedImage.ImgULX /
                                                  (double)decodedImage.getCompSubsX(0));

                    int tOffy = decodedImage.getCompULY(0) -
                                (int)Math.Ceiling(decodedImage.ImgULY /
                                                  (double)decodedImage.getCompSubsY(0));

                    DataBlkInt[] db = new DataBlkInt[numComps];
                    int[]        ls = new int[numComps];
                    int[]        mv = new int[numComps];
                    int[]        fb = new int[numComps];
                    for (int i = 0; i < numComps; i++)
                    {
                        db[i] = new DataBlkInt();
                        ls[i] = 1 << (decodedImage.getNomRangeBits(0) - 1);
                        mv[i] = (1 << decodedImage.getNomRangeBits(0)) - 1;
                        fb[i] = decodedImage.getFixedPoint(0);
                    }
                    for (int l = 0; l < height; l++)
                    {
                        for (int i = numComps - 1; i >= 0; i--)
                        {
                            db[i].ulx = 0;
                            db[i].uly = l;
                            db[i].w   = width;
                            db[i].h   = 1;
                            decodedImage.getInternCompData(db[i], i);
                        }
                        int[] k = new int[numComps];
                        for (int i = numComps - 1; i >= 0; i--)
                        {
                            k[i] = db[i].offset + width - 1;
                        }

                        int    outputBytesPerPixel = Math.Max(3, Math.Min(4, bytesPerPixel));
                        byte[] rowvalues           = new byte[width * outputBytesPerPixel];

                        for (int i = width - 1; i >= 0; i--)
                        {
                            int[] tmp = new int[numComps];
                            for (int j = numComps - 1; j >= 0; j--)
                            {
                                tmp[j] = (db[j].data_array[k[j]--] >> fb[j]) + ls[j];
                                tmp[j] = (tmp[j] < 0) ? 0 : ((tmp[j] > mv[j]) ? mv[j] : tmp[j]);

                                if (decodedImage.getNomRangeBits(j) != 8)
                                {
                                    tmp[j] = (int)Math.Round(((double)tmp[j] / Math.Pow(2D, (double)decodedImage.getNomRangeBits(j))) * 255D);
                                }
                            }
                            int offset = i * outputBytesPerPixel;
                            switch (numComps)
                            {
                            case 1:
                                rowvalues[offset + 0] = (byte)tmp[0];
                                rowvalues[offset + 1] = (byte)tmp[0];
                                rowvalues[offset + 2] = (byte)tmp[0];
                                break;

                            case 3:
                                rowvalues[offset + 0] = (byte)tmp[2];
                                rowvalues[offset + 1] = (byte)tmp[1];
                                rowvalues[offset + 2] = (byte)tmp[0];
                                break;

                            case 4:
                            case 5:
                                rowvalues[offset + 0] = (byte)tmp[2];
                                rowvalues[offset + 1] = (byte)tmp[1];
                                rowvalues[offset + 2] = (byte)tmp[0];
                                rowvalues[offset + 3] = (byte)tmp[3];
                                break;
                            }
                        }

                        BitmapData dstdata = dst.LockBits(
                            new System.Drawing.Rectangle(tOffx, tOffy + l, width, 1),
                            ImageLockMode.WriteOnly, pixelFormat);

                        IntPtr ptr = dstdata.Scan0;
                        System.Runtime.InteropServices.Marshal.Copy(rowvalues, 0, ptr, rowvalues.Length);
                        dst.UnlockBits(dstdata);
                    }
                }
            }
            return(dst);
        }
Example #5
0
 /// <summary> Returns, in the blk argument, a block of image data containing the
 /// specifed rectangular area, in the specified component. The data is
 /// returned, as a reference to the internal data, if any, instead of as a
 /// copy, therefore the returned data should not be modified.
 ///
 /// <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
 /// and 'h' members of the 'blk' argument, relative to the current
 /// tile. These members are not modified by this method. The 'offset' and
 /// 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class.
 ///
 /// <P>This method, in general, is more efficient than the 'getCompData()'
 /// method since it may not copy the data. However if the array of returned
 /// data is to be modified by the caller then the other method is probably
 /// preferable.
 ///
 /// <P>If possible, the data in the returned 'DataBlk' should be the
 /// internal data itself, instead of a copy, in order to increase the data
 /// transfer efficiency. However, this depends on the particular
 /// implementation (it may be more convenient to just return a copy of the
 /// data). This is the reason why the returned data should not be modified.
 ///
 /// <P>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one
 /// is created if necessary. The implementation of this interface may
 /// choose to return the same array or a new one, depending on what is more
 /// efficient. Therefore, the data array in <tt>blk</tt> prior to the
 /// method call should not be considered to contain the returned data, a
 /// new array may have been created. Instead, get the array from
 /// <tt>blk</tt> after the method has returned.
 ///
 /// <P>The returned data may have its 'progressive' attribute set. In this
 /// case the returned data is only an approximation of the "final" data.
 ///
 /// </summary>
 /// <param name="blk">Its coordinates and dimensions specify the area to return,
 /// relative to the current tile. Some fields in this object are modified
 /// to return the data.
 ///
 /// </param>
 /// <param name="c">The index of the component from which to get the data.
 ///
 /// </param>
 /// <returns> The requested DataBlk
 ///
 /// </returns>
 /// <seealso cref="getCompData">
 ///
 /// </seealso>
 public virtual DataBlk getInternCompData(DataBlk out_Renamed, int c)
 {
     return(src.getInternCompData(out_Renamed, c));
 }
Example #6
0
        /// <summary> Implements the 'getInternCompData()' and the 'getCompData()'
        /// methods. The 'intern' flag signals which of the two methods should run
        /// as.
        ///
        /// </summary>
        /// <param name="blk">The data block to get.
        ///
        /// </param>
        /// <param name="c">The index of the component from which to get the data.
        ///
        /// </param>
        /// <param name="intern">If true behave as 'getInternCompData(). Otherwise behave
        /// as 'getCompData()'
        ///
        /// </param>
        /// <returns> The requested data block
        ///
        /// </returns>
        /// <seealso cref="getInternCompData">
        ///
        /// </seealso>
        /// <seealso cref="getCompData">
        ///
        /// </seealso>
        private DataBlk getData(DataBlk blk, int c, bool intern)
        {
            DataBlk reqBlk; // Reference to block used in request to source

            // Keep request data type
            int otype = blk.DataType;

            if (otype == srcBlk.DataType)
            {
                // Probably requested type is same as source type
                reqBlk = blk;
            }
            else
            {
                // Probably requested type is not the same as source type
                reqBlk = srcBlk;
                // We need to copy requested coordinates and size
                reqBlk.ulx = blk.ulx;
                reqBlk.uly = blk.uly;
                reqBlk.w   = blk.w;
                reqBlk.h   = blk.h;
            }

            // Get source data block
            if (intern)
            {
                // We can use the intern variant
                srcBlk = src.getInternCompData(reqBlk, c);
            }
            else
            {
                // Do not use the intern variant. Note that this is not optimal
                // since if we are going to convert below then we could have used
                // the intern variant. But there is currently no way to know if we
                // will need to do conversion or not before getting the data.
                srcBlk = src.getCompData(reqBlk, c);
            }

            // Check if casting is needed
            if (srcBlk.DataType == otype)
            {
                return(srcBlk);
            }

            int   i;
            int   k, kSrc, kmin;
            float mult;
            int   w = srcBlk.w;
            int   h = srcBlk.h;

            switch (otype)
            {
            case DataBlk.TYPE_FLOAT:     // Cast INT -> FLOAT

                float[] farr;
                int[]   srcIArr;

                // Get data array from resulting blk
                farr = (float[])blk.Data;
                if (farr == null || farr.Length < w * h)
                {
                    farr     = new float[w * h];
                    blk.Data = farr;
                }

                blk.scanw       = srcBlk.w;
                blk.offset      = 0;
                blk.progressive = srcBlk.progressive;
                srcIArr         = (int[])srcBlk.Data;

                // Cast data from source to blk
                fp = src.getFixedPoint(c);
                if (fp != 0)
                {
                    mult = 1.0f / (1 << fp);
                    for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset + (h - 1) * srcBlk.scanw + w - 1;
                         i >= 0;
                         i--)
                    {
                        for (kmin = k - w; k > kmin; k--, kSrc--)
                        {
                            farr[k] = ((srcIArr[kSrc] * mult));
                        }
                        // Jump to geggining of next line in source
                        kSrc -= (srcBlk.scanw - w);
                    }
                }
                else
                {
                    for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset + (h - 1) * srcBlk.scanw + w - 1;
                         i >= 0;
                         i--)
                    {
                        for (kmin = k - w; k > kmin; k--, kSrc--)
                        {
                            //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'"
                            farr[k] = ((float)(srcIArr[kSrc]));
                        }
                        // Jump to geggining of next line in source
                        kSrc -= (srcBlk.scanw - w);
                    }
                }
                break;     // End of cast INT-> FLOAT


            case DataBlk.TYPE_INT:     // cast FLOAT -> INT
                int[]   iarr;
                float[] srcFArr;

                // Get data array from resulting blk
                iarr = (int[])blk.Data;
                if (iarr == null || iarr.Length < w * h)
                {
                    iarr     = new int[w * h];
                    blk.Data = iarr;
                }
                blk.scanw       = srcBlk.w;
                blk.offset      = 0;
                blk.progressive = srcBlk.progressive;
                srcFArr         = (float[])srcBlk.Data;

                // Cast data from source to blk
                if (fp != 0)
                {
                    //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'"
                    mult = (float)(1 << fp);
                    for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset + (h - 1) * srcBlk.scanw + w - 1;
                         i >= 0;
                         i--)
                    {
                        for (kmin = k - w; k > kmin; k--, kSrc--)
                        {
                            if (srcFArr[kSrc] > 0.0f)
                            {
                                //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'"
                                iarr[k] = (int)(srcFArr[kSrc] * mult + 0.5f);
                            }
                            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'"
                                iarr[k] = (int)(srcFArr[kSrc] * mult - 0.5f);
                            }
                        }
                        // Jump to geggining of next line in source
                        kSrc -= (srcBlk.scanw - w);
                    }
                }
                else
                {
                    for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset + (h - 1) * srcBlk.scanw + w - 1;
                         i >= 0;
                         i--)
                    {
                        for (kmin = k - w; k > kmin; k--, kSrc--)
                        {
                            if (srcFArr[kSrc] > 0.0f)
                            {
                                //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'"
                                iarr[k] = (int)(srcFArr[kSrc] + 0.5f);
                            }
                            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'"
                                iarr[k] = (int)(srcFArr[kSrc] - 0.5f);
                            }
                        }
                        // Jump to geggining of next line in source
                        kSrc -= (srcBlk.scanw - w);
                    }
                }
                break;     // End cast FLOAT -> INT

            default:
                throw new System.ArgumentException("Only integer and float data " + "are " + "supported by JJ2000");
            }
            return(blk);
        }
Example #7
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 is the data in the internal buffer
        /// of this object, and thus can not be modified by the caller. The
        /// 'offset' and 'scanw' of the returned data have, in general, some
        /// non-zero value. The 'magbits' of the returned data is not set by this
        /// method and should be ignored. 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.
        ///
        /// </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)
        {
            int       cbm, cbn, cn, cm;
            int       acb0x, acb0y;
            SubbandAn sb;

            intData = (filters.getWTDataType(tIdx, c) == DataBlk.TYPE_INT);

            //If the source image has not been decomposed
            if (decomposedComps[c] == null)
            {
                int           k, w, h;
                DataBlk       bufblk;
                System.Object dst_data;

                w = getTileCompWidth(tIdx, c);
                h = getTileCompHeight(tIdx, c);

                //Get the source image data
                if (intData)
                {
                    decomposedComps[c] = new DataBlkInt(0, 0, w, h);
                    bufblk             = new DataBlkInt();
                }
                else
                {
                    decomposedComps[c] = new DataBlkFloat(0, 0, w, h);
                    bufblk             = new DataBlkFloat();
                }

                // Get data from source line by line (this diminishes the memory
                // requirements on the data source)
                dst_data = decomposedComps[c].Data;
                int lstart = getCompULX(c);
                bufblk.ulx = lstart;
                bufblk.w   = w;
                bufblk.h   = 1;
                int kk = getCompULY(c);
                for (k = 0; k < h; k++, kk++)
                {
                    bufblk.uly = kk;
                    bufblk.ulx = lstart;
                    bufblk     = src.getInternCompData(bufblk, c);
                    // CONVERSION PROBLEM?
                    Array.Copy((System.Array)bufblk.Data, bufblk.offset, (System.Array)dst_data, k * w, w);
                }

                //Decompose source image
                waveletTreeDecomposition(decomposedComps[c], getAnSubbandTree(tIdx, c), c);

                // Make the first subband the current one
                currentSubband[c] = getNextSubband(c);

                lastn[c] = -1;
                lastm[c] = 0;
            }

            // Get the next code-block to "send"
            do
            {
                // Calculate number of code-blocks in current subband
                ncblks = currentSubband[c].numCb;
                // Goto next code-block
                lastn[c]++;
                if (lastn[c] == ncblks.x)
                {
                    // Got to end of this row of
                    // code-blocks
                    lastn[c] = 0;
                    lastm[c]++;
                }
                if (lastm[c] < ncblks.y)
                {
                    // Not past the last code-block in the subband, we can return
                    // this code-block
                    break;
                }
                // If we get here we already sent all code-blocks in this subband,
                // goto next subband
                currentSubband[c] = getNextSubband(c);
                lastn[c]          = -1;
                lastm[c]          = 0;
                if (currentSubband[c] == null)
                {
                    // We don't need the transformed data any more (a priori)
                    decomposedComps[c] = null;
                    // All code-blocks from all subbands in the current
                    // tile have been returned so we return a null
                    // reference
                    return(null);
                }
                // Loop to find the next code-block
            }while (true);


            // Project 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.
            acb0x = cb0x;
            acb0y = cb0y;
            switch (currentSubband[c].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");
            }

            // Initialize output code-block
            if (cblk == null)
            {
                if (intData)
                {
                    cblk = new CBlkWTDataInt();
                }
                else
                {
                    cblk = new CBlkWTDataFloat();
                }
            }
            cbn     = lastn[c];
            cbm     = lastm[c];
            sb      = currentSubband[c];
            cblk.n  = cbn;
            cblk.m  = cbm;
            cblk.sb = sb;
            // Calculate the indexes of first code-block in subband with respect
            // to the partitioning origin, to then calculate the position and size
            // 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
            cn = (sb.ulcx - acb0x + sb.nomCBlkW) / sb.nomCBlkW - 1;
            cm = (sb.ulcy - acb0y + sb.nomCBlkH) / sb.nomCBlkH - 1;
            if (cbn == 0)
            {
                // Left-most code-block, starts where subband starts
                cblk.ulx = sb.ulx;
            }
            else
            {
                // Calculate starting canvas coordinate and convert to subb. coords
                cblk.ulx = (cn + cbn) * sb.nomCBlkW - (sb.ulcx - acb0x) + sb.ulx;
            }
            if (cbm == 0)
            {
                // Bottom-most code-block, starts where subband starts
                cblk.uly = sb.uly;
            }
            else
            {
                cblk.uly = (cm + cbm) * sb.nomCBlkH - (sb.ulcy - acb0y) + sb.uly;
            }
            if (cbn < ncblks.x - 1)
            {
                // Calculate where next code-block starts => width
                cblk.w = (cn + cbn + 1) * sb.nomCBlkW - (sb.ulcx - acb0x) + sb.ulx - cblk.ulx;
            }
            else
            {
                // Right-most code-block, ends where subband ends
                cblk.w = sb.ulx + sb.w - cblk.ulx;
            }
            if (cbm < ncblks.y - 1)
            {
                // Calculate where next code-block starts => height
                cblk.h = (cm + cbm + 1) * sb.nomCBlkH - (sb.ulcy - acb0y) + sb.uly - cblk.uly;
            }
            else
            {
                // Bottom-most code-block, ends where subband ends
                cblk.h = sb.uly + sb.h - cblk.uly;
            }
            cblk.wmseScaling = 1f;

            // Since we are in getNextInternCodeBlock() we can return a
            // reference to the internal buffer, no need to copy. Just initialize
            // the 'offset' and 'scanw'
            cblk.offset = cblk.uly * decomposedComps[c].w + cblk.ulx;
            cblk.scanw  = decomposedComps[c].w;

            // For the data just put a reference to our buffer
            cblk.Data = decomposedComps[c].Data;
            // Return code-block
            return(cblk);
        }