/// ************************************************************************** /// /// $Id: Resampler.java,v 1.2 2002/08/08 14:07:31 grosbois Exp $ /// /// Copyright Eastman Kodak Company, 343 State Street, Rochester, NY 14650 /// $Date $ /// *************************************************************************** /// using System; using CSJ2K.j2k.util; using CSJ2K.j2k.image; namespace CSJ2K.Color { /// This class resamples the components of an image so that /// all have the same number of samples. The current implementation /// only handles the case of 2:1 upsampling. /// /// /// /// /// 1.0 /// /// Bruce A. Kern /// public class Resampler:ColorSpaceMapper { //UPGRADE_NOTE: Final was removed from the declaration of 'minCompSubsX '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" private int minCompSubsX; //UPGRADE_NOTE: Final was removed from the declaration of 'minCompSubsY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" private int minCompSubsY; //UPGRADE_NOTE: Final was removed from the declaration of 'maxCompSubsX '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" private int maxCompSubsX; //UPGRADE_NOTE: Final was removed from the declaration of 'maxCompSubsY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" private int maxCompSubsY; //UPGRADE_NOTE: Final was removed from the declaration of 'wspan '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" //UPGRADE_NOTE: Final was removed from the declaration of 'hspan '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal int wspan = 0; internal int hspan = 0; /// Factory method for creating instances of this class. /// -- source of image data /// /// -- provides colorspace info /// /// Resampler instance /// public static new BlkImgDataSrc createInstance(BlkImgDataSrc src, ColorSpace csMap) { return new Resampler(src, csMap); } /// Ctor resamples a BlkImgDataSrc so that all components /// have the same number of samples. /// /// Note the present implementation does only two to one /// respampling in either direction (row, column). /// /// /// -- Source of image data /// /// -- provides colorspace info /// protected internal Resampler(BlkImgDataSrc src, ColorSpace csMap):base(src, csMap) { int c; // Calculate the minimum and maximum subsampling factor // across all channels. int minX = src.getCompSubsX(0); int minY = src.getCompSubsY(0); int maxX = minX; int maxY = minY; for (c = 1; c < ncomps; ++c) { minX = System.Math.Min(minX, src.getCompSubsX(c)); minY = System.Math.Min(minY, src.getCompSubsY(c)); maxX = System.Math.Max(maxX, src.getCompSubsX(c)); maxY = System.Math.Max(maxY, src.getCompSubsY(c)); } // Throw an exception for other than 2:1 sampling. if ((maxX != 1 && maxX != 2) || (maxY != 1 && maxY != 2)) { throw new ColorSpaceException("Upsampling by other than 2:1 not" + " supported"); } minCompSubsX = minX; minCompSubsY = minY; maxCompSubsX = maxX; maxCompSubsY = maxY; /* end Resampler ctor */ } /// 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". /// ///

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. /// ///

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. /// ///

The returned data has its 'progressive' attribute set to that of the /// input data. /// ///

/// 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. /// /// /// The index of the component from which to get the data. Only 0 /// and 3 are valid. /// /// /// The requested DataBlk /// /// /// /// 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; } /// Return an appropriate String representation of this Resampler instance. public override System.String ToString() { System.Text.StringBuilder rep = new System.Text.StringBuilder("[Resampler: ncomps= " + ncomps); System.Text.StringBuilder body = new System.Text.StringBuilder(" "); for (int i = 0; i < ncomps; ++i) { body.Append(eol); body.Append("comp["); body.Append(i); body.Append("] xscale= "); body.Append(imgdatasrc.getCompSubsX(i)); body.Append(", yscale= "); body.Append(imgdatasrc.getCompSubsY(i)); } rep.Append(ColorSpace.indent(" ", body)); return rep.Append("]").ToString(); } /// 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". /// ///

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. /// ///

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. /// ///

The returned data has its 'progressive' attribute set to that of the /// input data. /// ///

/// 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. /// /// /// The index of the component from which to get the data. Only 0 /// and 3 are valid. /// /// /// The requested DataBlk /// /// /// /// /// public override DataBlk getCompData(DataBlk outblk, int c) { return getInternCompData(outblk, c); } /// Returns the height in pixels of the specified component in the /// overall image. /// public override int getCompImgHeight(int c) { return src.getCompImgHeight(c) * src.getCompSubsY(c); } /// Returns the width in pixels of the specified component in the /// overall image. /// public override int getCompImgWidth(int c) { return src.getCompImgWidth(c) * src.getCompSubsX(c); } /// Returns the component subsampling factor in the horizontal /// direction, for the specified component. /// public override int getCompSubsX(int c) { return 1; } /// Returns the component subsampling factor in the vertical /// direction, for the specified component. /// public override int getCompSubsY(int c) { return 1; } /// Returns the height in pixels of the specified tile-component. public override int getTileCompHeight(int t, int c) { return src.getTileCompHeight(t, c) * src.getCompSubsY(c); } /// Returns the width in pixels of the specified tile-component.. public override int getTileCompWidth(int t, int c) { return src.getTileCompWidth(t, c) * src.getCompSubsX(c); } /* end class Resampler */ } }