/// <summary> Copy constructor. Creates a DataBlkFloat which is the copy of the /// DataBlkFloat given as paramter. /// /// </summary> /// <param name="DataBlkFloat">the object to be copied. /// /// </param> public DataBlkFloat(DataBlkFloat src) { this.ulx = src.ulx; this.uly = src.uly; this.w = src.w; this.h = src.h; this.offset = 0; this.scanw = this.w; this.data = new float[this.w * this.h]; for (int i = 0; i < this.h; i++) { Array.Copy(src.data, i * src.scanw, this.data, i * this.scanw, this.w); } }
/// <summary> Copy constructor. Creates a DataBlkFloat which is the copy of the /// DataBlkFloat given as paramter. /// /// </summary> /// <param name="DataBlkFloat">the object to be copied. /// /// </param> public DataBlkFloat(DataBlkFloat src) { this.ulx = src.ulx; this.uly = src.uly; this.w = src.w; this.h = src.h; this.offset = 0; this.scanw = this.w; this.data = new float[this.w * this.h]; for (int i = 0; i < this.h; i++) Array.Copy(src.data, i * src.scanw, this.data, i * this.scanw, this.w); }
/// <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> Returns a block of image data containing the specifed rectangular area, /// in the specified component, as a reference to the internal buffer (see /// below). The rectangular area is specified by the coordinates and /// dimensions of the 'blk' object. /// /// <p>The area to return is specified by the 'ulx', 'uly', 'w' and 'h' /// members of the 'blk' argument. These members are not modified by this /// method.</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 returned data has its 'progressive' attribute unset /// (i.e. false).</p> /// /// </summary> /// <param name="blk">Its coordinates and dimensions specify the area to return. /// /// </param> /// <param name="c">The index of the component from which to get the data. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getInternCompData"> /// /// </seealso> public override DataBlk getInternCompData(DataBlk blk, int c) { int tIdx = TileIdx; if (src.getSynSubbandTree(tIdx, c).HorWFilter == null) { dtype = DataBlk.TYPE_INT; } else { dtype = src.getSynSubbandTree(tIdx, c).HorWFilter.DataType; } //If the source image has not been decomposed if (reconstructedComps[c] == null) { //Allocate component data buffer switch (dtype) { case DataBlk.TYPE_FLOAT: reconstructedComps[c] = new DataBlkFloat(0, 0, getTileCompWidth(tIdx, c), getTileCompHeight(tIdx, c)); break; case DataBlk.TYPE_INT: reconstructedComps[c] = new DataBlkInt(0, 0, getTileCompWidth(tIdx, c), getTileCompHeight(tIdx, c)); break; } //Reconstruct source image waveletTreeReconstruction(reconstructedComps[c], src.getSynSubbandTree(tIdx, c), c); } if (blk.DataType != dtype) { if (dtype == DataBlk.TYPE_INT) { blk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); } else { blk = new DataBlkFloat(blk.ulx, blk.uly, blk.w, blk.h); } } // Set the reference to the internal buffer blk.Data = reconstructedComps[c].Data; blk.offset = reconstructedComps[c].w * blk.uly + blk.ulx; blk.scanw = reconstructedComps[c].w; blk.progressive = false; return blk; }
/// <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; }
/// <summary> Apply inverse irreversible component transformation to obtain requested /// component from specified block of data. Whatever the type of requested /// DataBlk, it always returns a DataBlkFloat. /// /// </summary> /// <param name="blk">Determine the rectangular area to return /// /// </param> /// <param name="c">The index of the requested component /// /// </param> /// <returns> Data of requested component /// /// </returns> private DataBlk invICT(DataBlk blk, int c) { if (c >= 3 && c < NumComps) { // Requesting a component whose index is greater than 3 int k, k0, mink, i; // k1, k2 removed int w = blk.w; //width of output block int h = blk.h; //height of ouput block int[] out_data; // array of output data //Reference to output block data array out_data = (int[]) blk.Data; //Create data array of blk if necessary if (out_data == null) { out_data = new int[h * w]; blk.Data = out_data; } // Variables DataBlkFloat indb = new DataBlkFloat(blk.ulx, blk.uly, w, h); float[] indata; // input data array // Get the input data // (returned block may be larger than requested one) src.getInternCompData(indb, c); indata = (float[]) indb.Data; // Copy the data converting from int to int k = w * h - 1; k0 = indb.offset + (h - 1) * indb.scanw + w - 1; for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--) { //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'" out_data[k] = (int) (indata[k0]); } // Jump to beggining of previous line in input k0 -= (indb.scanw - w); } // Set the progressivity and offset blk.progressive = indb.progressive; blk.offset = 0; blk.scanw = w; } // If asking a component for the first time for this block, // do transform for the 3 components else if ((outdata[c] == null) || (dbi.ulx > blk.ulx) || (dbi.uly > blk.uly) || (dbi.ulx + dbi.w < blk.ulx + blk.w) || (dbi.uly + dbi.h < blk.uly + blk.h)) { int k, k0, k1, k2, mink, i; int w = blk.w; //width of output block int h = blk.h; //height of ouput block //Reference to output block data array outdata[c] = (int[]) blk.Data; //Create data array of blk if necessary if (outdata[c] == null || outdata[c].Length != w * h) { outdata[c] = new int[h * w]; blk.Data = outdata[c]; } outdata[(c + 1) % 3] = new int[outdata[c].Length]; outdata[(c + 2) % 3] = new int[outdata[c].Length]; if (block0 == null || block0.DataType != DataBlk.TYPE_FLOAT) block0 = new DataBlkFloat(); if (block2 == null || block2.DataType != DataBlk.TYPE_FLOAT) block2 = new DataBlkFloat(); if (block1 == null || block1.DataType != DataBlk.TYPE_FLOAT) block1 = new DataBlkFloat(); block0.w = block2.w = block1.w = blk.w; block0.h = block2.h = block1.h = blk.h; block0.ulx = block2.ulx = block1.ulx = blk.ulx; block0.uly = block2.uly = block1.uly = blk.uly; float[] data0, data1, data2; // input data arrays // Fill in buffer blocks (to be read only) // Returned blocks may have different size and position block0 = (DataBlkFloat) src.getInternCompData(block0, 0); data0 = (float[]) block0.Data; block2 = (DataBlkFloat) src.getInternCompData(block2, 1); data2 = (float[]) block2.Data; block1 = (DataBlkFloat) src.getInternCompData(block1, 2); data1 = (float[]) block1.Data; // Set the progressiveness of the output data blk.progressive = block0.progressive || block1.progressive || block2.progressive; blk.offset = 0; blk.scanw = w; // set attributes of the DataBlk used for buffering dbi.progressive = blk.progressive; dbi.ulx = blk.ulx; dbi.uly = blk.uly; dbi.w = blk.w; dbi.h = blk.h; //Perform conversion // Initialize general indexes k = w * h - 1; k0 = block0.offset + (h - 1) * block0.scanw + w - 1; k2 = block2.offset + (h - 1) * block2.scanw + w - 1; k1 = block1.offset + (h - 1) * block1.scanw + w - 1; for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--, k2--, k1--) { //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'" outdata[0][k] = (int) (data0[k0] + 1.402f * data1[k1] + 0.5f); //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'" outdata[1][k] = (int) (data0[k0] - 0.34413f * data2[k2] - 0.71414f * data1[k1] + 0.5f); //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'" outdata[2][k] = (int) (data0[k0] + 1.772f * data2[k2] + 0.5f); } // Jump to beggining of previous line in input k0 -= (block0.scanw - w); k2 -= (block2.scanw - w); k1 -= (block1.scanw - w); } outdata[c] = null; } else if ((c >= 0) && (c <= 3)) { //Asking for the 2nd or 3rd block component blk.Data = outdata[c]; blk.progressive = dbi.progressive; blk.offset = (blk.uly - dbi.uly) * dbi.w + blk.ulx - dbi.ulx; blk.scanw = dbi.w; outdata[c] = null; } else { // Requesting a non valid component index throw new System.ArgumentException(); } return blk; }
/// <summary> Return a DataBlk containing the requested component /// upsampled by the scale factor applied to the particular /// scaling direction /// /// 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 copy of the internal data, therefore the returned data /// can be modified "in place". /// /// <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' of /// the returned data is 0, and the 'scanw' is the same as the block's /// width. See the 'DataBlk' class. /// /// <P>If the data array in 'blk' is 'null', then a new one is created. If /// the data array is not 'null' then it is reused, and it must be large /// enough to contain the block's data. Otherwise an 'ArrayStoreException' /// or an 'IndexOutOfBoundsException' is thrown by the Java system. /// /// <P>The returned data has its 'progressive' attribute set to that of the /// input data. /// /// </summary> /// <param name="blk">Its coordinates and dimensions specify the area to /// return. If it contains a non-null data array, then it must have the /// correct dimensions. If it contains a null data array a new one is /// created. The 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. Only 0 /// and 3 are valid. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getCompData"> /// </seealso> public override DataBlk getInternCompData(DataBlk outblk, int c) { // If the scaling factor of this channel is 1 in both // directions, simply return the source DataBlk. if (src.getCompSubsX(c) == 1 && src.getCompSubsY(c) == 1) return src.getInternCompData(outblk, c); int wfactor = src.getCompSubsX(c); int hfactor = src.getCompSubsY(c); if ((wfactor != 2 && wfactor != 1) || (hfactor != 2 && hfactor != 1)) throw new System.ArgumentException("Upsampling by other than 2:1" + " not supported"); int leftedgeOut = - 1; // offset to the start of the output scanline int rightedgeOut = - 1; // offset to the end of the output // scanline + 1 int leftedgeIn = - 1; // offset to the start of the input scanline int rightedgeIn = - 1; // offset to the end of the input scanline + 1 int y0In, y1In, y0Out, y1Out; int x0In, x1In, x0Out, x1Out; y0Out = outblk.uly; y1Out = y0Out + outblk.h - 1; x0Out = outblk.ulx; x1Out = x0Out + outblk.w - 1; y0In = y0Out / hfactor; y1In = y1Out / hfactor; x0In = x0Out / wfactor; x1In = x1Out / wfactor; // Calculate the requested height and width, requesting an extra // row and or for upsampled channels. int reqW = x1In - x0In + 1; int reqH = y1In - y0In + 1; // Initialize general input and output indexes int kOut = - 1; int kIn = - 1; int yIn; switch (outblk.DataType) { case DataBlk.TYPE_INT: DataBlkInt inblkInt = new DataBlkInt(x0In, y0In, reqW, reqH); inblkInt = (DataBlkInt) src.getInternCompData(inblkInt, c); dataInt[c] = inblkInt.DataInt; // Reference the working array int[] outdataInt = (int[]) outblk.Data; // Create data array if necessary if (outdataInt == null || outdataInt.Length != outblk.w * outblk.h) { outdataInt = new int[outblk.h * outblk.w]; outblk.Data = outdataInt; } // The nitty-gritty. for (int yOut = y0Out; yOut <= y1Out; ++yOut) { yIn = yOut / hfactor; leftedgeIn = inblkInt.offset + (yIn - y0In) * inblkInt.scanw; rightedgeIn = leftedgeIn + inblkInt.w; leftedgeOut = outblk.offset + (yOut - y0Out) * outblk.scanw; rightedgeOut = leftedgeOut + outblk.w; kIn = leftedgeIn; kOut = leftedgeOut; if ((x0Out & 0x1) == 1) { // first is odd do the pixel once. outdataInt[kOut++] = dataInt[c][kIn++]; } if ((x1Out & 0x1) == 0) { // last is even adjust loop bounds rightedgeOut--; } while (kOut < rightedgeOut) { outdataInt[kOut++] = dataInt[c][kIn]; outdataInt[kOut++] = dataInt[c][kIn++]; } if ((x1Out & 0x1) == 0) { // last is even do the pixel once. outdataInt[kOut++] = dataInt[c][kIn]; } } outblk.progressive = inblkInt.progressive; break; case DataBlk.TYPE_FLOAT: DataBlkFloat inblkFloat = new DataBlkFloat(x0In, y0In, reqW, reqH); inblkFloat = (DataBlkFloat) src.getInternCompData(inblkFloat, c); dataFloat[c] = inblkFloat.DataFloat; // Reference the working array float[] outdataFloat = (float[]) outblk.Data; // Create data array if necessary if (outdataFloat == null || outdataFloat.Length != outblk.w * outblk.h) { outdataFloat = new float[outblk.h * outblk.w]; outblk.Data = outdataFloat; } // The nitty-gritty. for (int yOut = y0Out; yOut <= y1Out; ++yOut) { yIn = yOut / hfactor; leftedgeIn = inblkFloat.offset + (yIn - y0In) * inblkFloat.scanw; rightedgeIn = leftedgeIn + inblkFloat.w; leftedgeOut = outblk.offset + (yOut - y0Out) * outblk.scanw; rightedgeOut = leftedgeOut + outblk.w; kIn = leftedgeIn; kOut = leftedgeOut; if ((x0Out & 0x1) == 1) { // first is odd do the pixel once. outdataFloat[kOut++] = dataFloat[c][kIn++]; } if ((x1Out & 0x1) == 0) { // last is even adjust loop bounds rightedgeOut--; } while (kOut < rightedgeOut) { outdataFloat[kOut++] = dataFloat[c][kIn]; outdataFloat[kOut++] = dataFloat[c][kIn++]; } if ((x1Out & 0x1) == 0) { // last is even do the pixel once. outdataFloat[kOut++] = dataFloat[c][kIn]; } } outblk.progressive = inblkFloat.progressive; break; case DataBlk.TYPE_SHORT: case DataBlk.TYPE_BYTE: default: // Unsupported output type. throw new System.ArgumentException("invalid source datablock " + "type"); } return outblk; }
/// <summary>General utility used by ctors </summary> private void initialize() { this.pl = csMap.pl; this.ncomps = src.NumComps; shiftValueArray = new int[ncomps]; maxValueArray = new int[ncomps]; fixedPtBitsArray = new int[ncomps]; srcBlk = new DataBlk[ncomps]; inInt = new DataBlkInt[ncomps]; inFloat = new DataBlkFloat[ncomps]; workInt = new DataBlkInt[ncomps]; workFloat = new DataBlkFloat[ncomps]; dataInt = new int[ncomps][]; dataFloat = new float[ncomps][]; workDataInt = new int[ncomps][]; workDataFloat = new float[ncomps][]; dataInt = new int[ncomps][]; dataFloat = new float[ncomps][]; /* For each component, get a reference to the pixel data and * set up working DataBlks for both integer and float output. */ for (int i = 0; i < ncomps; ++i) { shiftValueArray[i] = 1 << (src.getNomRangeBits(i) - 1); maxValueArray[i] = (1 << src.getNomRangeBits(i)) - 1; fixedPtBitsArray[i] = src.getFixedPoint(i); inInt[i] = new DataBlkInt(); inFloat[i] = new DataBlkFloat(); workInt[i] = new DataBlkInt(); workInt[i].progressive = inInt[i].progressive; workFloat[i] = new DataBlkFloat(); workFloat[i].progressive = inFloat[i].progressive; } }
/// <summary>General utility used by ctors </summary> private void initialize() { tempInt = new DataBlkInt[ncomps]; tempFloat = new DataBlkFloat[ncomps]; /* For each component, get the maximum data value, a reference * to the pixel data and set up working and temporary DataBlks * for both integer and float output. */ for (int i = 0; i < ncomps; ++i) { tempInt[i] = new DataBlkInt(); tempFloat[i] = new DataBlkFloat(); } }
/// <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; }