/// <summary> Copy constructor. Creates a DataBlkInt which is the copy of the /// DataBlkInt given as paramter. /// /// </summary> /// <param name="DataBlkInt">the object to be copied. /// /// </param> public DataBlkInt(DataBlkInt 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_array = new int[this.w * this.h]; for (int i = 0; i < this.h; i++) { Array.Copy(src.data_array, i * src.scanw, this.data_array, i * this.scanw, this.w); } }
/// <summary> Returns, in the blk argument, the 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>After being read the coefficients are level shifted by subtracting /// 2^(nominal bit range - 1)<p> /// /// <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>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 always has its 'progressive' attribute unset /// (i.e. false).</p> /// /// <p>When an I/O exception is encountered the JJ2KExceptionHandler is /// used. The exception is passed to its handleException method. The action /// that is taken depends on the action that has been registered in /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details.</p> /// /// </summary> /// <param name="blk">Its coordinates and dimensions specify the area to /// return. 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. Only 0 /// is valid. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getCompData"> /// </seealso> /// <seealso cref="JJ2KExceptionHandler"> /// /// </seealso> public override DataBlk getInternCompData(DataBlk blk, int c) { int k, j, i, mi; // counters int levShift = 1 << (bitDepth - 1); // Check component index if (c != 0) throw new System.ArgumentException(); // Check type of block provided as an argument if (blk.DataType != DataBlk.TYPE_INT) { if (intBlk == null) intBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); else { intBlk.ulx = blk.ulx; intBlk.uly = blk.uly; intBlk.w = blk.w; intBlk.h = blk.h; } blk = intBlk; } // Get data array int[] barr = (int[]) blk.Data; if (barr == null || barr.Length < blk.w * blk.h * packBytes) { barr = new int[blk.w * blk.h]; blk.Data = barr; } int paddingLength = (32 - bitDepth); if (buf == null || buf.Length < packBytes * blk.w) { buf = new byte[packBytes * blk.w]; } try { switch (packBytes) { // Switch between one of the 3 byte packet type case 1: // Samples packed into 1 byte // Read line by line mi = blk.uly + blk.h; if (isSigned) { for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + i * w + blk.ulx, System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w); for (k = (i - blk.uly) * blk.w + blk.w - 1, j = blk.w - 1; j >= 0; k--) barr[k] = (((buf[j--] & 0xFF) << paddingLength) >> paddingLength); } } else { // Not signed for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + i * w + blk.ulx, System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w); for (k = (i - blk.uly) * blk.w + blk.w - 1, j = blk.w - 1; j >= 0; k--) barr[k] = (SupportClass.URShift(((buf[j--] & 0xFF) << paddingLength), paddingLength)) - levShift; } } break; case 2: // Samples packed into 2 bytes // Read line by line mi = blk.uly + blk.h; if (isSigned) { for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + 2 * (i * w + blk.ulx), System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w << 1); switch (byteOrder) { case CSJ2K.j2k.io.EndianType_Fields.LITTLE_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 1) - 1; j >= 0; k--) { barr[k] = ((((buf[j--] & 0xFF) << 8) | (buf[j--] & 0xFF)) << paddingLength) >> paddingLength; } break; case CSJ2K.j2k.io.EndianType_Fields.BIG_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 1) - 1; j >= 0; k--) { barr[k] = (((buf[j--] & 0xFF) | ((buf[j--] & 0xFF) << 8)) << paddingLength) >> paddingLength; } break; default: throw new System.ApplicationException("Internal JJ2000 bug"); } } } else { // If not signed for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + 2 * (i * w + blk.ulx), System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w << 1); switch (byteOrder) { case CSJ2K.j2k.io.EndianType_Fields.LITTLE_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 1) - 1; j >= 0; k--) { barr[k] = (SupportClass.URShift(((((buf[j--] & 0xFF) << 8) | (buf[j--] & 0xFF)) << paddingLength), paddingLength)) - levShift; } break; case CSJ2K.j2k.io.EndianType_Fields.BIG_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 1) - 1; j >= 0; k--) { barr[k] = (SupportClass.URShift((((buf[j--] & 0xFF) | ((buf[j--] & 0xFF) << 8)) << paddingLength), paddingLength)) - levShift; } break; default: throw new System.ApplicationException("Internal JJ2000 bug"); } } } break; case 4: // Samples packed into 4 bytes // Read line by line mi = blk.uly + blk.h; if (isSigned) { for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + 4 * (i * w + blk.ulx), System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w << 2); switch (byteOrder) { case CSJ2K.j2k.io.EndianType_Fields.LITTLE_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 2) - 1; j >= 0; k--) { barr[k] = ((((buf[j--] & 0xFF) << 24) | ((buf[j--] & 0xFF) << 16) | ((buf[j--] & 0xFF) << 8) | (buf[j--] & 0xFF)) << paddingLength) >> paddingLength; } break; case CSJ2K.j2k.io.EndianType_Fields.BIG_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 2) - 1; j >= 0; k--) { barr[k] = (((buf[j--] & 0xFF) | ((buf[j--] & 0xFF) << 8) | ((buf[j--] & 0xFF) << 16) | ((buf[j--] & 0xFF) << 24)) << paddingLength) >> paddingLength; } break; default: throw new System.ApplicationException("Internal JJ2000 bug"); } } } else { for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + 4 * (i * w + blk.ulx), System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w << 2); switch (byteOrder) { case CSJ2K.j2k.io.EndianType_Fields.LITTLE_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 2) - 1; j >= 0; k--) { barr[k] = (SupportClass.URShift(((((buf[j--] & 0xFF) << 24) | ((buf[j--] & 0xFF) << 16) | ((buf[j--] & 0xFF) << 8) | (buf[j--] & 0xFF)) << paddingLength), paddingLength)) - levShift; } break; case CSJ2K.j2k.io.EndianType_Fields.BIG_ENDIAN: for (k = (i - blk.uly) * blk.w + blk.w - 1, j = (blk.w << 2) - 1; j >= 0; k--) { barr[k] = (SupportClass.URShift((((buf[j--] & 0xFF) | ((buf[j--] & 0xFF) << 8) | ((buf[j--] & 0xFF) << 16) | ((buf[j--] & 0xFF) << 24)) << paddingLength), paddingLength)) - levShift; } break; default: throw new System.ApplicationException("Internal JJ2000 bug"); } } } break; default: throw new System.IO.IOException("PGX supports only bit-depth between" + " 1 and 31"); } } catch (System.IO.IOException e) { JJ2KExceptionHandler.handleException(e); } // Turn off the progressive attribute blk.progressive = false; // Set buffer attributes blk.offset = 0; blk.scanw = blk.w; return blk; }
/// <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; }
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 == 4 ? 4 : 3); // **** Copy to Bitmap **** PixelFormat pixelFormat; switch (numComps) { case 1: pixelFormat = PixelFormat.Format24bppRgb; break; case 3: pixelFormat = PixelFormat.Format24bppRgb; break; case 4: 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; byte[] rowvalues = new byte[width * bytesPerPixel]; 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 * bytesPerPixel; 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: rowvalues[offset + 0] = (byte)tmp[3]; rowvalues[offset + 1] = (byte)tmp[2]; rowvalues[offset + 2] = (byte)tmp[1]; rowvalues[offset + 3] = (byte)tmp[0]; break; } } BitmapData dstdata = dst.LockBits( new System.Drawing.Rectangle(tOffx, tOffy + l, width, 1), ImageLockMode.ReadWrite, pixelFormat); IntPtr ptr = dstdata.Scan0; System.Runtime.InteropServices.Marshal.Copy(rowvalues, 0, ptr, rowvalues.Length); dst.UnlockBits(dstdata); } } } return dst; }
/// <summary> Returns, in the blk argument, the 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> After being read the coefficients are level shifted by subtracting /// 2^(nominal bit range - 1) /// /// <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>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 always has its 'progressive' attribute unset /// (i.e. false). /// /// <P>When an I/O exception is encountered the JJ2KExceptionHandler is /// used. The exception is passed to its handleException method. The action /// that is taken depends on the action that has been registered in /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details. /// /// <P>This method implements buffering for the 3 components: When the /// first one is asked, all the 3 components are read and stored until they /// are needed. /// /// </summary> /// <param name="blk">Its coordinates and dimensions specify the area to /// return. 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. Only 0, /// 1 and 3 are valid. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getCompData"> /// /// </seealso> /// <seealso cref="JJ2KExceptionHandler"> /// /// </seealso> public override DataBlk getInternCompData(DataBlk blk, int c) { // Check component index if (c < 0 || c > 2) throw new System.ArgumentException(); // Check type of block provided as an argument if (blk.DataType != DataBlk.TYPE_INT) { if (intBlk == null) intBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); else { intBlk.ulx = blk.ulx; intBlk.uly = blk.uly; intBlk.w = blk.w; intBlk.h = blk.h; } blk = intBlk; } // If asking a component for the first time for this block, read all of the components if ((barr == 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 i; int[] red, green, blue, alpha; int componentCount = (image.PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3; barr = new int[componentCount][]; // Reset data arrays if needed if (barr[c] == null || barr[c].Length < blk.w * blk.h) { barr[c] = new int[blk.w * blk.h]; } blk.Data = barr[c]; i = (c + 1) % 3; if (barr[i] == null || barr[i].Length < blk.w * blk.h) { barr[i] = new int[blk.w * blk.h]; } i = (c + 2) % 3; if (barr[i] == null || barr[i].Length < blk.w * blk.h) { barr[i] = new int[blk.w * blk.h]; } if (componentCount == 4) { if (barr[3] == null || barr[3].Length < blk.w * blk.h) barr[3] = new int[blk.w * blk.h]; } // set attributes of the DataBlk used for buffering dbi.ulx = blk.ulx; dbi.uly = blk.uly; dbi.w = blk.w; dbi.h = blk.h; red = barr[0]; green = barr[1]; blue = barr[2]; alpha = (componentCount == 4) ? barr[3] : null; Bitmap bitmap = (Bitmap)image; BitmapData data = bitmap.LockBits(new Rectangle(blk.ulx, blk.uly, blk.w, blk.h), ImageLockMode.ReadOnly, (componentCount == 3) ? PixelFormat.Format24bppRgb : PixelFormat.Format32bppArgb); unsafe { byte* ptr = (byte*)data.Scan0.ToPointer(); int k = 0; for (int j = 0; j < blk.w * blk.h; j++) { blue[k] = ((byte)*(ptr + 0) & 0xFF) - 128; green[k] = ((byte)*(ptr + 1) & 0xFF) - 128; red[k] = ((byte)*(ptr + 2) & 0xFF) - 128; if (componentCount == 4) alpha[k] = ((byte)*(ptr + 3) & 0xFF) - 128; ++k; ptr += 3; } } bitmap.UnlockBits(data); barr[0] = red; barr[1] = green; barr[2] = blue; if (componentCount == 4) barr[3] = alpha; // Set buffer attributes blk.Data = barr[c]; blk.offset = 0; blk.scanw = blk.w; } else { //Asking for the 2nd or 3rd (or 4th) block component blk.Data = barr[c]; blk.offset = (blk.ulx - dbi.ulx) * dbi.w + blk.ulx - dbi.ulx; blk.scanw = dbi.scanw; } // Turn off the progressive attribute blk.progressive = false; return blk; }
/// <summary> Closes the underlying file or netwrok connection to where the data is /// written. Any call to other methods of the class become illegal after a /// call to this one. /// /// </summary> /// <exception cref="IOException">If an I/O error occurs. /// /// </exception> public override void close() { int i; // Finish writing the file, writing 0s at the end if the data at end // has not been written. if (out_Renamed.Length != 3 * w * h + offset) { // Goto end of file out_Renamed.Seek(out_Renamed.Length, System.IO.SeekOrigin.Begin); // Fill with 0s n all the components for (i = 3 * w * h + offset - (int) out_Renamed.Length; i > 0; i--) { out_Renamed.WriteByte((System.Byte) 0); } } out_Renamed.Dispose(); src = null; out_Renamed = null; db = null; }
/// <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> 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> Returns the specified code-block in the current tile for the specified /// component, as a copy (see below). /// /// <P>The returned code-block may be progressive, which is indicated by /// the 'progressive' variable of the returned 'DataBlk' object. If a /// code-block is progressive it means that in a later request to this /// method for the same code-block it is possible to retrieve data which is /// a better approximation, since meanwhile more data to decode for the /// code-block could have been received. If the code-block is not /// progressive then later calls to this method for the same code-block /// will return the exact same data values. /// /// <P>The data returned by this method is always a copy of the internal /// data of this object, if any, and it can be modified "in place" without /// any problems after being returned. The 'offset' of the returned data is /// 0, and the 'scanw' is the same as the code-block width. See the /// 'DataBlk' class. /// /// <P>The 'ulx' and 'uly' members of the returned 'DataBlk' object /// contain the coordinates of the top-left corner of the block, with /// respect to the tile, not the subband. /// /// </summary> /// <param name="c">The component for which to return the next code-block. /// /// </param> /// <param name="m">The vertical index of the code-block to return, in the /// specified subband. /// /// </param> /// <param name="n">The horizontal index of the code-block to return, in the /// specified subband. /// /// </param> /// <param name="sb">The subband in which the code-block to return is. /// /// </param> /// <param name="cblk">If non-null this object will be used to return the new /// code-block. If null a new one will be allocated and returned. If the /// "data" array of the object is non-null it will be reused, if possible, /// to return the data. /// /// </param> /// <returns> The next code-block in the current tile for component 'n', or /// null if all code-blocks for the current tile have been returned. /// /// </returns> /// <seealso cref="DataBlk"> /// /// </seealso> public override DataBlk getCodeBlock(int c, int m, int n, SubbandSyn sb, DataBlk cblk) { //long stime = 0L; // Start time for timed sections int[] zc_lut; // The ZC lookup table to use int[] out_data; // The outupt data buffer int npasses; // The number of coding passes to perform int curbp; // The current magnitude bit-plane (starts at 30) bool error; // Error indicator int tslen; // Length of first terminated segment int tsidx; // Index of current terminated segment ByteInputBuffer in_Renamed = null; bool isterm; // Get the code-block to decode srcblk = src.getCodeBlock(c, m, n, sb, 1, - 1, srcblk); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // Retrieve options from decSpec options = ((System.Int32) decSpec.ecopts.getTileCompVal(tIdx, c)); // Reset state ArrayUtil.intArraySet(state, 0); // Initialize output code-block if (cblk == null) cblk = new DataBlkInt(); cblk.progressive = srcblk.prog; cblk.ulx = srcblk.ulx; cblk.uly = srcblk.uly; cblk.w = srcblk.w; cblk.h = srcblk.h; cblk.offset = 0; cblk.scanw = cblk.w; out_data = (int[]) cblk.Data; if (out_data == null || out_data.Length < srcblk.w * srcblk.h) { out_data = new int[srcblk.w * srcblk.h]; cblk.Data = out_data; } else { // Set data values to 0 ArrayUtil.intArraySet(out_data, 0); } if (srcblk.nl <= 0 || srcblk.nTrunc <= 0) { // 0 layers => no data to decode => return all 0s return cblk; } // Get the length of the first terminated segment tslen = (srcblk.tsLengths == null)?srcblk.dl:srcblk.tsLengths[0]; tsidx = 0; // Initialize for decoding npasses = srcblk.nTrunc; if (mq == null) { in_Renamed = new ByteInputBuffer(srcblk.data, 0, tslen); mq = new MQDecoder(in_Renamed, NUM_CTXTS, MQ_INIT); } else { // We always start by an MQ segment mq.nextSegment(srcblk.data, 0, tslen); mq.resetCtxts(); } error = false; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0) { if (bin == null) { if (in_Renamed == null) in_Renamed = mq.ByteInputBuffer; bin = new ByteToBitInput(in_Renamed); } } // Choose correct ZC lookup table for global orientation switch (sb.orientation) { case Subband.WT_ORIENT_HL: zc_lut = ZC_LUT_HL; break; case Subband.WT_ORIENT_LH: case Subband.WT_ORIENT_LL: zc_lut = ZC_LUT_LH; break; case Subband.WT_ORIENT_HH: zc_lut = ZC_LUT_HH; break; default: throw new System.ApplicationException("JJ2000 internal error"); } // NOTE: we don't currently detect which is the last magnitude // bit-plane so that 'isterm' is true for the last pass of it. Doing // so would aid marginally in error detection with the predictable // error resilient MQ termination. However, determining which is the // last magnitude bit-plane is quite hard (due to ROI, quantization, // etc.) and in any case the predictable error resilient termination // used without the arithmetic coding bypass and/or regular // termination modes is almost useless. // Loop on bit-planes and passes curbp = 30 - srcblk.skipMSBP; // Check for maximum number of bitplanes quit condition if (mQuit != - 1 && (mQuit * 3 - 2) < npasses) { npasses = mQuit * 3 - 2; } // First bit-plane has only the cleanup pass if (curbp >= 0 && npasses > 0) { isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP) >= curbp); error = cleanuppass(cblk, mq, curbp, state, zc_lut, isterm); npasses--; if (!error || !doer) curbp--; } // Other bit-planes have the three coding passes if (!error || !doer) { while (curbp >= 0 && npasses > 0) { if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (curbp < 31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP)) { // Use bypass decoding mode (only all bit-planes // after the first 4 bit-planes). // Here starts a new raw segment bin.setByteArray(null, - 1, srcblk.tsLengths[++tsidx]); isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0; error = rawSigProgPass(cblk, bin, curbp, state, isterm); npasses--; if (npasses <= 0 || (error && doer)) break; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Start a new raw segment bin.setByteArray(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP > curbp)); error = rawMagRefPass(cblk, bin, curbp, state, isterm); } else { // Do not use bypass decoding mode if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Here starts a new MQ segment mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0; error = sigProgPass(cblk, mq, curbp, state, zc_lut, isterm); npasses--; if (npasses <= 0 || (error && doer)) break; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Here starts a new MQ segment mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP > curbp)); error = magRefPass(cblk, mq, curbp, state, isterm); } npasses--; if (npasses <= 0 || (error && doer)) break; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (curbp < 31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP))) { // Here starts a new MQ segment mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP) >= curbp); error = cleanuppass(cblk, mq, curbp, state, zc_lut, isterm); npasses--; if (error && doer) break; // Goto next bit-plane curbp--; } } // If an error ocurred conceal it if (error && doer) { if (verber) { FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Error detected at bit-plane " + curbp + " in code-block (" + m + "," + n + "), sb_idx " + sb.sbandIdx + ", res. level " + sb.resLvl + ". Concealing..."); } conceal(cblk, curbp); } #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif // Return decoded block return cblk; }
/// <summary>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> This functions gets a DataBlk with the size of the current code-block /// and fills it with the ROI mask. The lowest scaling value in the mask /// for this code-block is returned by the function to be used for /// modifying the rate distortion estimations. /// /// </summary> /// <param name="db">The data block that is to be filled with the mask /// /// </param> /// <param name="sb">The root of the current subband tree /// /// </param> /// <param name="magbits">The number of magnitude bits in this code-block /// /// </param> /// <param name="c">Component number /// /// </param> /// <returns> Whether or not a mask was needed for this tile /// </returns> public abstract bool getROIMask(DataBlkInt db, Subband sb, int magbits, int c);
/// <summary> Writes the data of the specified area to the file, coordinates are /// relative to the current tile of the source. Before writing, the /// coefficients are limited to the nominal range. /// /// <p>This method may not be called concurrently from different /// threads.</p> /// /// <p>If the data returned from the BlkImgDataSrc source is progressive, /// then it is requested over and over until it is not progressive /// anymore.</p> /// /// </summary> /// <param name="ulx">The horizontal coordinate of the upper-left corner of the /// area to write, relative to the current tile. /// /// </param> /// <param name="uly">The vertical coordinate of the upper-left corner of the area /// to write, relative to the current tile. /// /// </param> /// <param name="width">The width of the area to write. /// /// </param> /// <param name="height">The height of the area to write. /// /// </param> /// <exception cref="IOException">If an I/O error occurs. /// /// </exception> public override void write(int ulx, int uly, int w, int h) { int k, i, j; int fracbits = fb; // In local variable for faster access int tOffx, tOffy; // Active tile offset in the X and Y direction // Initialize db db.ulx = ulx; db.uly = uly; db.w = w; db.h = h; // Get the current active tile offset //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'" tOffx = src.getCompULX(c) - (int) System.Math.Ceiling(src.ImgULX / (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'" tOffy = src.getCompULY(c) - (int) System.Math.Ceiling(src.ImgULY / (double) src.getCompSubsY(c)); // Check the array size if (db.data_array != null && db.data_array.Length < w * h) { // A new one will be allocated by getInternCompData() db.data_array = null; } // Request the data and make sure it is not // progressive do { db = (DataBlkInt) src.getInternCompData(db, c); } while (db.progressive); // variables used during coeff saturation int tmp, maxVal = (1 << src.getNomRangeBits(c)) - 1; // If nominal bitdepth greater than 8, calculate down shift int downShift = src.getNomRangeBits(c) - 8; if (downShift < 0) { downShift = 0; } // Check line buffer if (buf == null || buf.Length < w) { buf = new byte[w]; // Expand buffer } // Write line by line for (i = 0; i < h; i++) { // Skip to beggining of line in file out_Renamed.Seek(this.offset + this.w * (uly + tOffy + i) + ulx + tOffx, System.IO.SeekOrigin.Begin); // Write all bytes in the line if (fracbits == 0) { for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; j--, k--) { tmp = db.data_array[k] + levShift; buf[j] = (byte) (((tmp < 0)?0:((tmp > maxVal)?maxVal:tmp)) >> downShift); } } else { for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; j--, k--) { tmp = (db.data_array[k] >> fracbits) + levShift; buf[j] = (byte) (((tmp < 0)?0:((tmp > maxVal)?maxVal:tmp)) >> downShift); } } out_Renamed.Write(buf, 0, w); } }
/// <summary> Returns, in the blk argument, the 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> After being read the coefficients are level shifted by subtracting /// 2^(nominal bit range - 1) /// /// <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>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 always has its 'progressive' attribute unset /// (i.e. false). /// /// <P>When an I/O exception is encountered the JJ2KExceptionHandler is /// used. The exception is passed to its handleException method. The action /// that is taken depends on the action that has been registered in /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details. /// /// <P>This method implements buffering for the 3 components: When the /// first one is asked, all the 3 components are read and stored until they /// are needed. /// /// </summary> /// <param name="blk">Its coordinates and dimensions specify the area to /// return. 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. Only 0, /// 1 and 3 are valid. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getCompData"> /// /// </seealso> /// <seealso cref="JJ2KExceptionHandler"> /// /// </seealso> public override DataBlk getInternCompData(DataBlk blk, int c) { // Check component index if (c < 0 || c > 2) throw new System.ArgumentException(); // Check type of block provided as an argument if (blk.DataType != DataBlk.TYPE_INT) { if (intBlk == null) intBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); else { intBlk.ulx = blk.ulx; intBlk.uly = blk.uly; intBlk.w = blk.w; intBlk.h = blk.h; } blk = intBlk; } // If asking a component for the first time for this block, read the 3 // components if ((barr[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, j, i, mi; int[] red, green, blue; // Reset data arrays if needed if (barr[c] == null || barr[c].Length < blk.w * blk.h) { barr[c] = new int[blk.w * blk.h]; } blk.Data = barr[c]; i = (c + 1) % 3; if (barr[i] == null || barr[i].Length < blk.w * blk.h) { barr[i] = new int[blk.w * blk.h]; } i = (c + 2) % 3; if (barr[i] == null || barr[i].Length < blk.w * blk.h) { barr[i] = new int[blk.w * blk.h]; } // set attributes of the DataBlk used for buffering dbi.ulx = blk.ulx; dbi.uly = blk.uly; dbi.w = blk.w; dbi.h = blk.h; // Check line buffer if (buf == null || buf.Length < 3 * blk.w) { buf = new byte[3 * blk.w]; } red = barr[0]; green = barr[1]; blue = barr[2]; try { // Read line by line mi = blk.uly + blk.h; for (i = blk.uly; i < mi; i++) { // Reposition in input offset takes care of // header offset in_Renamed.Seek(offset + i * 3 * w + 3 * blk.ulx, System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, 3 * blk.w); for (k = (i - blk.uly) * blk.w + blk.w - 1, j = 3 * blk.w - 1; j >= 0; k--) { // Read every third sample blue[k] = (((byte) buf[j--]) & 0xFF) - DC_OFFSET; green[k] = (((byte) buf[j--]) & 0xFF) - DC_OFFSET; red[k] = (((byte) buf[j--]) & 0xFF) - DC_OFFSET; } } } catch (System.IO.IOException e) { JJ2KExceptionHandler.handleException(e); } barr[0] = red; barr[1] = green; barr[2] = blue; // Set buffer attributes blk.Data = barr[c]; blk.offset = 0; blk.scanw = blk.w; } else { //Asking for the 2nd or 3rd block component blk.Data = barr[c]; blk.offset = (blk.ulx - dbi.ulx) * dbi.w + blk.ulx - dbi.ulx; blk.scanw = dbi.scanw; } // Turn off the progressive attribute blk.progressive = false; return blk; }
/// <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 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 forward component transformation to obtain requested component /// from specified block of data. Whatever the type of requested DataBlk, /// it always returns a DataBlkInt. /// /// </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 forwRCT(DataBlk blk, int c) { int k, k0, k1, k2, mink, i; int w = blk.w; //width of output block int h = blk.h; //height of ouput block int[] outdata; //array of output data //If asking for Yr, Ur or Vr do transform if (c >= 0 && c <= 2) { // Check that request data type is int if (blk.DataType != DataBlk.TYPE_INT) { if (outBlk == null || outBlk.DataType != DataBlk.TYPE_INT) { outBlk = new DataBlkInt(); } outBlk.w = w; outBlk.h = h; outBlk.ulx = blk.ulx; outBlk.uly = blk.uly; blk = outBlk; } //Reference to output block data array outdata = (int[]) blk.Data; //Create data array of blk if necessary if (outdata == null || outdata.Length < h * w) { outdata = new int[h * w]; blk.Data = outdata; } // Block buffers for input RGB data int[] data0, data1, bdata; // input data arrays if (block0 == null) block0 = new DataBlkInt(); if (block1 == null) block1 = new DataBlkInt(); if (block2 == null) block2 = new DataBlkInt(); block0.w = block1.w = block2.w = blk.w; block0.h = block1.h = block2.h = blk.h; block0.ulx = block1.ulx = block2.ulx = blk.ulx; block0.uly = block1.uly = block2.uly = blk.uly; //Fill in buffer blocks (to be read only) // Returned blocks may have different size and position block0 = (DataBlkInt) src.getInternCompData(block0, 0); data0 = (int[]) block0.Data; block1 = (DataBlkInt) src.getInternCompData(block1, 1); data1 = (int[]) block1.Data; block2 = (DataBlkInt) src.getInternCompData(block2, 2); bdata = (int[]) block2.Data; // Set the progressiveness of the output data blk.progressive = block0.progressive || block1.progressive || block2.progressive; blk.offset = 0; blk.scanw = w; //Perform conversion // Initialize general indexes k = w * h - 1; k0 = block0.offset + (h - 1) * block0.scanw + w - 1; k1 = block1.offset + (h - 1) * block1.scanw + w - 1; k2 = block2.offset + (h - 1) * block2.scanw + w - 1; switch (c) { case 0: //RGB to Yr conversion for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--, k1--, k2--) { // Use int arithmetic with 12 fractional bits // and rounding outdata[k] = (data0[k] + 2 * data1[k] + bdata[k]) >> 2; // Same as / 4 } // Jump to beggining of previous line in input k0 -= (block0.scanw - w); k1 -= (block1.scanw - w); k2 -= (block2.scanw - w); } break; case 1: //RGB to Ur conversion for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k1--, k2--) { // Use int arithmetic with 12 fractional bits // and rounding outdata[k] = bdata[k2] - data1[k1]; } // Jump to beggining of previous line in input k1 -= (block1.scanw - w); k2 -= (block2.scanw - w); } break; case 2: //RGB to Vr conversion for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--, k1--) { // Use int arithmetic with 12 fractional bits // and rounding outdata[k] = data0[k0] - data1[k1]; } // Jump to beggining of previous line in input k0 -= (block0.scanw - w); k1 -= (block1.scanw - w); } break; } } else if (c >= 3) { // Requesting a component which is not Y, Ur or Vr => // just pass the data return src.getInternCompData(blk, c); } else { // Requesting a non valid component index throw new System.ArgumentException(); } return blk; }
public DataBlk getCompData(DataBlk blk, int c) { var newBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); return this.getInternCompData(newBlk, c); }
/// <summary> Apply forward 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 forwICT(DataBlk blk, int c) { int k, k0, k1, k2, mink, i; int w = blk.w; //width of output block int h = blk.h; //height of ouput block float[] outdata; //array of output data if (blk.DataType != DataBlk.TYPE_FLOAT) { if (outBlk == null || outBlk.DataType != DataBlk.TYPE_FLOAT) { outBlk = new DataBlkFloat(); } outBlk.w = w; outBlk.h = h; outBlk.ulx = blk.ulx; outBlk.uly = blk.uly; blk = outBlk; } //Reference to output block data array outdata = (float[]) blk.Data; //Create data array of blk if necessary if (outdata == null || outdata.Length < w * h) { outdata = new float[h * w]; blk.Data = outdata; } //If asking for Y, Cb or Cr do transform if (c >= 0 && c <= 2) { int[] data0, data1, data2; // input data arrays if (block0 == null) { block0 = new DataBlkInt(); } if (block1 == null) { block1 = new DataBlkInt(); } if (block2 == null) { block2 = new DataBlkInt(); } block0.w = block1.w = block2.w = blk.w; block0.h = block1.h = block2.h = blk.h; block0.ulx = block1.ulx = block2.ulx = blk.ulx; block0.uly = block1.uly = block2.uly = blk.uly; // Returned blocks may have different size and position block0 = (DataBlkInt) src.getInternCompData(block0, 0); data0 = (int[]) block0.Data; block1 = (DataBlkInt) src.getInternCompData(block1, 1); data1 = (int[]) block1.Data; block2 = (DataBlkInt) src.getInternCompData(block2, 2); data2 = (int[]) block2.Data; // Set the progressiveness of the output data blk.progressive = block0.progressive || block1.progressive || block2.progressive; blk.offset = 0; blk.scanw = w; //Perform conversion // Initialize general indexes k = w * h - 1; k0 = block0.offset + (h - 1) * block0.scanw + w - 1; k1 = block1.offset + (h - 1) * block1.scanw + w - 1; k2 = block2.offset + (h - 1) * block2.scanw + w - 1; switch (c) { case 0: //RGB to Y conversion for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--, k1--, k2--) { outdata[k] = 0.299f * data0[k0] + 0.587f * data1[k1] + 0.114f * data2[k2]; } // Jump to beggining of previous line in input k0 -= (block0.scanw - w); k1 -= (block1.scanw - w); k2 -= (block2.scanw - w); } break; case 1: //RGB to Cb conversion for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--, k1--, k2--) { outdata[k] = (- 0.16875f) * data0[k0] - 0.33126f * data1[k1] + 0.5f * data2[k2]; } // Jump to beggining of previous line in input k0 -= (block0.scanw - w); k1 -= (block1.scanw - w); k2 -= (block2.scanw - w); } break; case 2: //RGB to Cr conversion for (i = h - 1; i >= 0; i--) { for (mink = k - w; k > mink; k--, k0--, k1--, k2--) { outdata[k] = 0.5f * data0[k0] - 0.41869f * data1[k1] - 0.08131f * data2[k2]; } // Jump to beggining of previous line in input k0 -= (block0.scanw - w); k1 -= (block1.scanw - w); k2 -= (block2.scanw - w); } break; } } else if (c >= 3) { // Requesting a component which is not Y, Cb or Cr => // just pass the data // Variables DataBlkInt indb = new DataBlkInt(blk.ulx, blk.uly, w, h); int[] indata; // input data array // Get the input data // (returned block may be larger than requested one) src.getInternCompData(indb, c); indata = (int[]) indb.Data; // Copy the data converting from int to float 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'" outdata[k] = (float) indata[k0]; } // Jump to beggining of next line in input k0 += indb.w - w; } // Set the progressivity blk.progressive = indb.progressive; blk.offset = 0; blk.scanw = w; return blk; } else { // Requesting a non valid component index throw new System.ArgumentException(); } return blk; }
/// <summary> Writes the data of the specified area to the file, coordinates are /// relative to the current tile of the source. Before writing, the /// coefficients are limited to the nominal range. /// /// <p>This method may not be called concurrently from different /// threads.</p> /// /// <p>If the data returned from the BlkImgDataSrc source is progressive, /// then it is requested over and over until it is not progressive /// anymore.</p> /// /// </summary> /// <param name="ulx">The horizontal coordinate of the upper-left corner of the /// area to write, relative to the current tile. /// /// </param> /// <param name="uly">The vertical coordinate of the upper-left corner of the area /// to write, relative to the current tile. /// /// </param> /// <param name="width">The width of the area to write. /// /// </param> /// <param name="height">The height of the area to write. /// /// </param> /// <exception cref="IOException">If an I/O error occurs. /// /// </exception> public override void write(int ulx, int uly, int w, int h) { int k, j, i, c; // In local variables for faster access int fracbits; // variables used during coeff saturation int shift, tmp, maxVal; int tOffx, tOffy; // Active tile offset in the X and Y direction // Active tiles in all components have same offset since they are at // same resolution (PPM does not support anything 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'" tOffx = src.getCompULX(cps[0]) - (int) System.Math.Ceiling(src.ImgULX / (double) src.getCompSubsX(cps[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'" tOffy = src.getCompULY(cps[0]) - (int) System.Math.Ceiling(src.ImgULY / (double) src.getCompSubsY(cps[0])); // Check the array size if (db.data_array != null && db.data_array.Length < w) { // A new one will be allocated by getInternCompData() db.data_array = null; } // Check the line buffer if (buf == null || buf.Length < 3 * w) { buf = new byte[3 * w]; } // Write the data to the file // Write line by line for (i = 0; i < h; i++) { // Write into buffer first loop over the three components and // write for each for (c = 0; c < 3; c++) { maxVal = (1 << src.getNomRangeBits(cps[c])) - 1; shift = levShift[c]; // Initialize db db.ulx = ulx; db.uly = uly + i; db.w = w; db.h = 1; // Request the data and make sure it is not progressive do { db = (DataBlkInt) src.getInternCompData(db, cps[c]); } while (db.progressive); // Get the fracbits value fracbits = fb[c]; // Write all bytes in the line if (fracbits == 0) { for (k = db.offset + w - 1, j = 3 * w - 1 + c - 2; j >= 0; k--) { tmp = db.data_array[k] + shift; buf[j] = (byte) ((tmp < 0)?0:((tmp > maxVal)?maxVal:tmp)); j -= 3; } } else { for (k = db.offset + w - 1, j = 3 * w - 1 + c - 2; j >= 0; k--) { tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + shift; buf[j] = (byte) ((tmp < 0)?0:((tmp > maxVal)?maxVal:tmp)); j -= 3; } } } // Write buffer into file out_Renamed.Seek(offset + 3 * (this.w * (uly + tOffy + i) + ulx + tOffx), System.IO.SeekOrigin.Begin); out_Renamed.Write(buf, 0, 3 * w); } }
/// <summary> Writes the data of the specified area to the file, coordinates are /// relative to the current tile of the source. Before writing, the /// coefficients are limited to the nominal range and packed into 1,2 or 4 /// bytes (according to the bit-depth). /// /// <p>If the data is unisigned, level shifting is applied adding 2^(bit /// depth - 1)</p> /// /// <p>This method may not be called concurrently from different /// threads.</p> /// /// <p>If the data returned from the BlkImgDataSrc source is progressive, /// then it is requested over and over until it is not progressive /// anymore.</p> /// /// </summary> /// <param name="ulx">The horizontal coordinate of the upper-left corner of the /// area to write, relative to the current tile. /// /// </param> /// <param name="uly">The vertical coordinate of the upper-left corner of the area /// to write, relative to the current tile. /// /// </param> /// <param name="width">The width of the area to write. /// /// </param> /// <param name="height">The height of the area to write. /// /// </param> /// <exception cref="IOException">If an I/O error occurs. /// /// </exception> public override void write(int ulx, int uly, int w, int h) { int k, i, j; int fracbits = fb; // In local variable for faster access int tOffx, tOffy; // Active tile offset in the X and Y direction // Initialize db db.ulx = ulx; db.uly = uly; db.w = w; db.h = h; // Get the current active tile offset //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'" tOffx = src.getCompULX(c) - (int) System.Math.Ceiling(src.ImgULX / (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'" tOffy = src.getCompULY(c) - (int) System.Math.Ceiling(src.ImgULY / (double) src.getCompSubsY(c)); // Check the array size if (db.data_array != null && db.data_array.Length < w * h) { // A new one will be allocated by getInternCompData() db.data_array = null; } // Request the data and make sure it is not // progressive do { db = (DataBlkInt) src.getInternCompData(db, c); } while (db.progressive); int tmp; // Check line buffer if (buf == null || buf.Length < packBytes * w) { buf = new byte[packBytes * w]; // Expand buffer } switch (packBytes) { case 1: // Samples packed into 1 byte // Write line by line for (i = 0; i < h; i++) { // Skip to beggining of line in file out_Renamed.Seek(offset + this.w * (uly + tOffy + i) + ulx + tOffx, System.IO.SeekOrigin.Begin); // Write all bytes in the line if (fracbits == 0) { for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; k--) { tmp = db.data_array[k] + levShift; buf[j--] = (byte) ((tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp)); } } else { for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; k--) { tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + levShift; buf[j--] = (byte) ((tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp)); } } out_Renamed.Write(buf, 0, w); } break; case 2: // Samples packed in to 2 bytes (short) // Write line by line for (i = 0; i < h; i++) { // Skip to beggining of line in file out_Renamed.Seek(offset + 2 * (this.w * (uly + tOffy + i) + ulx + tOffx), System.IO.SeekOrigin.Begin); // Write all bytes in the line if (fracbits == 0) { for (k = db.offset + i * db.scanw + w - 1, j = (w << 1) - 1; j >= 0; k--) { tmp = db.data_array[k] + levShift; tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp); buf[j--] = (byte) tmp; // no need for 0xFF mask since // truncation will do it already buf[j--] = (byte) (SupportClass.URShift(tmp, 8)); } } else { for (k = db.offset + i * db.scanw + w - 1, j = (w << 1) - 1; j >= 0; k--) { tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + levShift; tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp); buf[j--] = (byte) tmp; // no need for 0xFF mask since // truncation will do it already buf[j--] = (byte) (SupportClass.URShift(tmp, 8)); } } out_Renamed.Write(buf, 0, w << 1); } break; case 4: // Write line by line for (i = 0; i < h; i++) { // Skip to beggining of line in file out_Renamed.Seek(offset + 4 * (this.w * (uly + tOffy + i) + ulx + tOffx), System.IO.SeekOrigin.Begin); // Write all bytes in the line if (fracbits == 0) { for (k = db.offset + i * db.scanw + w - 1, j = (w << 2) - 1; j >= 0; k--) { tmp = db.data_array[k] + levShift; tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp); buf[j--] = (byte) tmp; // No need to use 0xFF buf[j--] = (byte) (SupportClass.URShift(tmp, 8)); // masks since truncation buf[j--] = (byte) (SupportClass.URShift(tmp, 16)); // will have already the buf[j--] = (byte) (SupportClass.URShift(tmp, 24)); // same effect } } else { for (k = db.offset + i * db.scanw + w - 1, j = (w << 2) - 1; j >= 0; k--) { tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + levShift; tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp); buf[j--] = (byte) tmp; // No need to use 0xFF buf[j--] = (byte) (SupportClass.URShift(tmp, 8)); // masks since truncation buf[j--] = (byte) (SupportClass.URShift(tmp, 16)); // will have already the buf[j--] = (byte) (SupportClass.URShift(tmp, 24)); // same effect } } out_Renamed.Write(buf, 0, w << 2); } break; default: throw new System.IO.IOException("PGX supports only bit-depth between " + "1 and 31"); } }
/// <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> Constructor of the ROI scaler, takes a Quantizer as source of data to /// scale. /// /// </summary> /// <param name="src">The quantizer that is the source of data. /// /// </param> /// <param name="mg">The mask generator that will be used for all components /// /// </param> /// <param name="roi">Flag indicating whether there are rois specified. /// /// </param> /// <param name="sLev">The resolution levels that belong entirely to ROI /// /// </param> /// <param name="uba">Flag indicating whether block aligning is used. /// /// </param> /// <param name="encSpec">The encoder specifications for addition of roi specs /// /// </param> public ROIScaler(Quantizer src, ROIMaskGenerator mg, bool roi, int sLev, bool uba, EncoderSpecs encSpec):base(src) { this.src = src; this.roi = roi; this.useStartLevel = sLev; if (roi) { // If there is no ROI, no need to do this this.mg = mg; roiMask = new DataBlkInt(); calcMaxMagBits(encSpec); blockAligned = uba; } }
/// <summary> This functions gets a DataBlk the size of the current code-block and /// fills this block with the ROI mask. /// /// <P> In order to get the mask for a particular Subband, the subband tree /// is traversed and at each decomposition, the ROI masks are computed. The /// roi bondaries for each subband are stored in the SubbandRectROIMask /// tree. /// /// </summary> /// <param name="db">The data block that is to be filled with the mask /// /// </param> /// <param name="sb">The root of the subband tree to which db belongs /// /// </param> /// <param name="magbits">The max number of magnitude bits in any code-block /// /// </param> /// <param name="c">The component for which to get the mask /// /// </param> /// <returns> Whether or not a mask was needed for this tile /// /// </returns> public override bool getROIMask(DataBlkInt db, Subband sb, int magbits, int c) { int x = db.ulx; int y = db.uly; int w = db.w; int h = db.h; int[] mask = db.DataInt; int i, j, k, r, maxk, maxj; // mink, minj removed int ulx = 0, uly = 0, lrx = 0, lry = 0; int wrap; int maxROI; int[] culxs; int[] culys; int[] clrxs; int[] clrys; SubbandRectROIMask srm; // If the ROI bounds have not been calculated for this tile and // component, do so now. if (!tileMaskMade[c]) { makeMask(sb, magbits, c); tileMaskMade[c] = true; } if (!roiInTile) { return false; } // Find relevant subband mask and get ROI bounds srm = (SubbandRectROIMask) sMasks[c].getSubbandRectROIMask(x, y); culxs = srm.ulxs; culys = srm.ulys; clrxs = srm.lrxs; clrys = srm.lrys; maxROI = culxs.Length - 1; // Make sure that only parts of ROIs within the code-block are used // and make the bounds local to this block the LR bounds are counted // as the distance from the lower right corner of the block x -= srm.ulx; y -= srm.uly; for (r = maxROI; r >= 0; r--) { ulx = culxs[r] - x; if (ulx < 0) { ulx = 0; } else if (ulx >= w) { ulx = w; } uly = culys[r] - y; if (uly < 0) { uly = 0; } else if (uly >= h) { uly = h; } lrx = clrxs[r] - x; if (lrx < 0) { lrx = - 1; } else if (lrx >= w) { lrx = w - 1; } lry = clrys[r] - y; if (lry < 0) { lry = - 1; } else if (lry >= h) { lry = h - 1; } // Add the masks of the ROI i = w * lry + lrx; maxj = (lrx - ulx); wrap = w - maxj - 1; maxk = lry - uly; for (k = maxk; k >= 0; k--) { for (j = maxj; j >= 0; j--, i--) mask[i] = magbits; i -= wrap; } } return true; }
/// <summary> This functions gets a DataBlk the size of the current code-block an /// fills this block with the ROI mask. /// /// <P> In order to get the mask for a particular Subband, the subband tree /// is traversed and at each decomposition, the ROI masks are computed. /// /// <P> The widths of the synthesis filters corresponding to the wavelet /// filters used in the wavelet transform are used to expand the ROI masks /// in the decompositions. /// /// </summary> /// <param name="db">The data block that is to be filled with the mask /// /// </param> /// <param name="sb">The root of the subband tree to which db belongs /// /// </param> /// <param name="magbits">The max number of magnitude bits in any code-block /// /// </param> /// <param name="c">The number of the component /// /// </param> /// <returns> Whether or not a mask was needed for this tile /// /// </returns> public override bool getROIMask(DataBlkInt db, Subband sb, int magbits, int c) { int x = db.ulx; int y = db.uly; int w = db.w; int h = db.h; int tilew = sb.w; int tileh = sb.h; int[] maskData = (int[]) db.Data; int i, j, k, bi, wrap; // If the ROI mask has not been calculated for this tile and // component, do so now. if (!tileMaskMade[c]) { makeMask(sb, magbits, c); tileMaskMade[c] = true; } if (!roiInTile) return false; int[] mask = roiMask[c]; // local copy // Copy relevant part of the ROI mask to the datablock i = (y + h - 1) * tilew + x + w - 1; bi = w * h - 1; wrap = tilew - w; for (j = h; j > 0; j--) { for (k = w; k > 0; k--, i--, bi--) { maskData[bi] = mask[i]; } i -= wrap; } return true; }
/// <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 copy of the internal data, therefore the returned data /// can be modified "in place". /// /// <P> After being read the coefficients are level shifted by subtracting /// 2^(nominal bit range - 1) /// /// <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 unset /// (i.e. false). /// /// <P>When an I/O exception is encountered the JJ2KExceptionHandler is /// used. The exception is passed to its handleException method. The action /// that is taken depends on the action that has been registered in /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details. /// /// </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,1 and 2 are valid. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getInternCompData"> /// /// </seealso> /// <seealso cref="JJ2KExceptionHandler"> /// /// </seealso> public override DataBlk getCompData(DataBlk blk, int c) { // NOTE: can not directly call getInterCompData since that returns // internally buffered data. int ulx, uly, w, h; // Check type of block provided as an argument if (blk.DataType != DataBlk.TYPE_INT) { DataBlkInt tmp = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); blk = tmp; } int[] bakarr = (int[])blk.Data; // Save requested block size ulx = blk.ulx; uly = blk.uly; w = blk.w; h = blk.h; // Force internal data buffer to be different from external blk.Data = null; getInternCompData(blk, c); // Copy the data if (bakarr == null) { bakarr = new int[w * h]; } if (blk.offset == 0 && blk.scanw == w) { // Requested and returned block buffer are the same size // CONVERSION PROBLEM? Array.Copy((System.Array)blk.Data, 0, (System.Array)bakarr, 0, w * h); } else { // Requested and returned block are different for (int i = h - 1; i >= 0; i--) { // copy line by line // CONVERSION PROBLEM? Array.Copy((System.Array)blk.Data, blk.offset + i * blk.scanw, (System.Array)bakarr, i * w, w); } } blk.Data = bakarr; blk.offset = 0; blk.scanw = blk.w; return blk; }
/// <summary> This function generates the ROI mask for one tile-component. /// /// <P> Once the mask is generated in the pixel domain. it is decomposed /// following the same decomposition scheme as the wavelet transform. /// /// </summary> /// <param name="sb">The root of the subband tree used in the decomposition /// /// </param> /// <param name="magbits">The max number of magnitude bits in any code-block /// /// </param> /// <param name="c">component number /// </param> public override void makeMask(Subband sb, int magbits, int c) { int[] mask; // local copy ROI[] rois = this.roi_array; // local copy int i, j, k, r, maxj; // mink, minj removed int lrx, lry; int x, y, w, h; int cx, cy, rad; int wrap; int curScalVal; int tileulx = sb.ulcx; int tileuly = sb.ulcy; int tilew = sb.w; int tileh = sb.h; int lineLen = (tilew > tileh)?tilew:tileh; // Make sure there is a sufficiently large mask buffer if (roiMask[c] == null || (roiMask[c].Length < (tilew * tileh))) { roiMask[c] = new int[tilew * tileh]; mask = roiMask[c]; } else { mask = roiMask[c]; for (i = tilew * tileh - 1; i >= 0; i--) mask[i] = 0; } // Make sure there are sufficiently large line buffers if (maskLineLow == null || (maskLineLow.Length < (lineLen + 1) / 2)) maskLineLow = new int[(lineLen + 1) / 2]; if (maskLineHigh == null || (maskLineHigh.Length < (lineLen + 1) / 2)) maskLineHigh = new int[(lineLen + 1) / 2]; roiInTile = false; // Generate ROIs in pixel domain: for (r = rois.Length - 1; r >= 0; r--) { if (rois[r].comp == c) { curScalVal = magbits; if (rois[r].arbShape) { ImgReaderPGM maskPGM = rois[r].maskPGM; // Local copy if ((src.ImgWidth != maskPGM.ImgWidth) || (src.ImgHeight != maskPGM.ImgHeight)) throw new System.ArgumentException("Input image and" + " ROI mask must " + "have the same " + "size"); x = src.ImgULX; y = src.ImgULY; lrx = x + src.ImgWidth - 1; lry = y + src.ImgHeight - 1; if ((x > tileulx + tilew) || (y > tileuly + tileh) || (lrx < tileulx) || (lry < tileuly)) // Roi not in tile continue; // Check bounds x -= tileulx; lrx -= tileulx; y -= tileuly; lry -= tileuly; int offx = 0; int offy = 0; if (x < 0) { offx = - x; x = 0; } if (y < 0) { offy = - y; y = 0; } w = (lrx > (tilew - 1))?tilew - x:lrx + 1 - x; h = (lry > (tileh - 1))?tileh - y:lry + 1 - y; // Get shape line by line to reduce memory DataBlkInt srcblk = new DataBlkInt(); int mDcOff = - ImgReaderPGM.DC_OFFSET; int nROIcoeff = 0; int[] src_data; srcblk.ulx = offx; srcblk.w = w; srcblk.h = 1; i = (y + h - 1) * tilew + x + w - 1; maxj = w; wrap = tilew - maxj; for (k = h; k > 0; k--) { srcblk.uly = offy + k - 1; srcblk = (DataBlkInt) maskPGM.getInternCompData(srcblk, 0); src_data = srcblk.DataInt; for (j = maxj; j > 0; j--, i--) { if (src_data[j - 1] != mDcOff) { mask[i] = curScalVal; nROIcoeff++; } } i -= wrap; } if (nROIcoeff != 0) { roiInTile = true; } } else if (rois[r].rect) { // Rectangular ROI x = rois[r].ulx; y = rois[r].uly; lrx = rois[r].w + x - 1; lry = rois[r].h + y - 1; if ((x > tileulx + tilew) || (y > tileuly + tileh) || (lrx < tileulx) || (lry < tileuly)) // Roi not in tile continue; roiInTile = true; // Check bounds x -= tileulx; lrx -= tileulx; y -= tileuly; lry -= tileuly; x = (x < 0)?0:x; y = (y < 0)?0:y; w = (lrx > (tilew - 1))?tilew - x:lrx + 1 - x; h = (lry > (tileh - 1))?tileh - y:lry + 1 - y; i = (y + h - 1) * tilew + x + w - 1; maxj = w; wrap = tilew - maxj; for (k = h; k > 0; k--) { for (j = maxj; j > 0; j--, i--) { mask[i] = curScalVal; } i -= wrap; } } else { // Non-rectangular ROI. So far only circular case cx = rois[r].x - tileulx; cy = rois[r].y - tileuly; rad = rois[r].r; i = tileh * tilew - 1; for (k = tileh - 1; k >= 0; k--) { for (j = tilew - 1; j >= 0; j--, i--) { if (((j - cx) * (j - cx) + (k - cy) * (k - cy) < rad * rad)) { mask[i] = curScalVal; roiInTile = true; } } } } } } // If wavelet transform is used if (sb.isNode) { // Decompose the mask according to the subband tree // Calculate size of padded line buffer WaveletFilter vFilter = sb.VerWFilter; WaveletFilter hFilter = sb.HorWFilter; int lvsup = vFilter.SynLowNegSupport + vFilter.SynLowPosSupport; int hvsup = vFilter.SynHighNegSupport + vFilter.SynHighPosSupport; int lhsup = hFilter.SynLowNegSupport + hFilter.SynLowPosSupport; int hhsup = hFilter.SynHighNegSupport + hFilter.SynHighPosSupport; lvsup = (lvsup > hvsup)?lvsup:hvsup; lhsup = (lhsup > hhsup)?lhsup:hhsup; lvsup = (lvsup > lhsup)?lvsup:lhsup; paddedMaskLine = new int[lineLen + lvsup]; if (roiInTile) decomp(sb, tilew, tileh, c); } }
/// <summary> Returns, in the blk argument, the 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> After being read the coefficients are level shifted by subtracting /// 2^(nominal bit range - 1) /// /// <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>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 always has its 'progressive' attribute unset /// (i.e. false). /// /// <P>When an I/O exception is encountered the JJ2KExceptionHandler is /// used. The exception is passed to its handleException method. The action /// that is taken depends on the action that has been registered in /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details. /// /// </summary> /// <param name="blk">Its coordinates and dimensions specify the area to /// return. 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. Only 0 /// is valid. /// /// </param> /// <returns> The requested DataBlk /// /// </returns> /// <seealso cref="getCompData"> /// /// </seealso> /// <seealso cref="JJ2KExceptionHandler"> /// /// </seealso> public override DataBlk getInternCompData(DataBlk blk, int c) { int k, j, i, mi; int[] barr; // Check component index if (c != 0) throw new System.ArgumentException(); // Check type of block provided as an argument if (blk.DataType != DataBlk.TYPE_INT) { if (intBlk == null) intBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); else { intBlk.ulx = blk.ulx; intBlk.uly = blk.uly; intBlk.w = blk.w; intBlk.h = blk.h; } blk = intBlk; } // Get data array barr = (int[]) blk.Data; if (barr == null || barr.Length < blk.w * blk.h) { barr = new int[blk.w * blk.h]; blk.Data = barr; } // Check line buffer if (buf == null || buf.Length < blk.w) { buf = new byte[blk.w]; } try { // Read line by line mi = blk.uly + blk.h; for (i = blk.uly; i < mi; i++) { // Reposition in input in_Renamed.Seek(offset + i * w + blk.ulx, System.IO.SeekOrigin.Begin); in_Renamed.Read(buf, 0, blk.w); for (k = (i - blk.uly) * blk.w + blk.w - 1, j = blk.w - 1; j >= 0; j--, k--) { barr[k] = (((int) buf[j]) & 0xFF) - DC_OFFSET; } } } catch (System.IO.IOException e) { JJ2KExceptionHandler.handleException(e); } // Turn off the progressive attribute blk.progressive = false; // Set buffer attributes blk.offset = 0; blk.scanw = blk.w; return blk; }
/// <summary> Copy constructor. Creates a DataBlkInt which is the copy of the /// DataBlkInt given as paramter. /// /// </summary> /// <param name="DataBlkInt">the object to be copied. /// /// </param> public DataBlkInt(DataBlkInt 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_array = new int[this.w * this.h]; for (int i = 0; i < this.h; i++) Array.Copy(src.data_array, i * src.scanw, this.data_array, i * this.scanw, this.w); }