/// <summary> /// Creates a zeroed destination Raster with the correct size and number of /// bands, given this source. </summary> /// <param name="src"> the specified <code>Raster</code> </param> /// <returns> a <code>WritableRaster</code> with the correct size and number /// of bands from the specified <code>src</code> </returns> /// <exception cref="IllegalArgumentException"> if this <code>ColorConvertOp</code> /// was created without sufficient information to define the /// <code>dst</code> and <code>src</code> color spaces </exception> public virtual WritableRaster CreateCompatibleDestRaster(Raster src) { int ncomponents; if (CSList != null) { /* non-ICC case */ if (CSList.Length != 2) { throw new IllegalArgumentException("Destination ColorSpace is undefined"); } ncomponents = CSList[1].NumComponents; } else { /* ICC case */ int nProfiles = ProfileList.Length; if (nProfiles < 2) { throw new IllegalArgumentException("Destination ColorSpace is undefined"); } ncomponents = ProfileList[nProfiles - 1].NumComponents; } WritableRaster dest = Raster.CreateInterleavedRaster(DataBuffer.TYPE_BYTE, src.Width, src.Height, ncomponents, new Point(src.MinX, src.MinY)); return(dest); }
/// <summary> /// Transforms the source <CODE>Raster</CODE> and stores the results in /// the destination <CODE>Raster</CODE>. This operation performs the /// transform band by band. /// <para> /// If the destination <CODE>Raster</CODE> is null, a new /// <CODE>Raster</CODE> is created. /// An <CODE>IllegalArgumentException</CODE> may be thrown if the source is /// the same as the destination or if the number of bands in /// the source is not equal to the number of bands in the /// destination. /// </para> /// <para> /// The coordinates of the rectangle returned by /// <code>getBounds2D(Raster)</code> /// are not necessarily the same as the coordinates of the /// <code>WritableRaster</code> returned by this method. If the /// upper-left corner coordinates of rectangle are negative then /// this part of the rectangle is not drawn. If the coordinates /// of the rectangle are positive then the filtered image is drawn at /// that position in the destination <code>Raster</code>. /// </para> /// <para> /// </para> /// </summary> /// <param name="src"> The <CODE>Raster</CODE> to transform. </param> /// <param name="dst"> The <CODE>Raster</CODE> in which to store the results of the /// transformation. /// </param> /// <returns> The transformed <CODE>Raster</CODE>. /// </returns> /// <exception cref="ImagingOpException"> if the raster cannot be transformed /// because of a data-processing error that might be /// caused by an invalid image format, tile format, or /// image-processing operation, or any other unsupported /// operation. </exception> public WritableRaster Filter(Raster src, WritableRaster dst) { if (src == null) { throw new NullPointerException("src image is null"); } if (dst == null) { dst = CreateCompatibleDestRaster(src); } if (src == dst) { throw new IllegalArgumentException("src image cannot be the " + "same as the dst image"); } if (src.NumBands != dst.NumBands) { throw new IllegalArgumentException("Number of src bands (" + src.NumBands + ") does not match number of " + " dst bands (" + dst.NumBands + ")"); } if (ImagingLib.filter(this, src, dst) == null) { throw new ImagingOpException("Unable to transform src image"); } return(dst); }
private void ShortFilter(ShortLookupTable lookup, Raster src, WritableRaster dst, int width, int height, int numBands) { int band; int[] srcPix = null; // Find the ref to the table and the offset short[][] table = lookup.Table; int offset = lookup.Offset; int tidx; int step = 1; // Check if it is one lookup applied to all bands if (table.Length == 1) { step = 0; } int x = 0; int y = 0; int index; int maxShort = (1 << 16) - 1; // Loop through the data for (y = 0; y < height; y++) { tidx = 0; for (band = 0; band < numBands; band++, tidx += step) { // Find data for this band, scanline srcPix = src.GetSamples(0, y, width, 1, band, srcPix); for (x = 0; x < width; x++) { index = srcPix[x] - offset; if (index < 0 || index > maxShort) { throw new IllegalArgumentException("index out of range " + index + " x is " + x + "srcPix[x]=" + srcPix[x] + " offset=" + offset); } // Do the lookup srcPix[x] = table[tidx][index]; } // Put it back dst.SetSamples(0, y, width, 1, band, srcPix); } } }
/// <summary> /// Creates a zeroed destination image with the correct size and number /// of bands. If destCM is null, an appropriate ColorModel will be used. </summary> /// <param name="src"> Source image for the filter operation. </param> /// <param name="destCM"> ColorModel of the destination. Can be null. </param> /// <returns> a destination <code>BufferedImage</code> with the correct /// size and number of bands. </returns> public virtual BufferedImage CreateCompatibleDestImage(BufferedImage src, ColorModel destCM) { BufferedImage image; int w = src.Width; int h = src.Height; WritableRaster wr = null; if (destCM == null) { destCM = src.ColorModel; // Not much support for ICM if (destCM is IndexColorModel) { destCM = ColorModel.RGBdefault; } else { /* Create destination image as similar to the source * as it possible... */ wr = src.Data.CreateCompatibleWritableRaster(w, h); } } if (wr == null) { /* This is the case when destination color model * was explicitly specified (and it may be not compatible * with source raster structure) or source is indexed image. * We should use destination color model to create compatible * destination raster here. */ wr = destCM.CreateCompatibleWritableRaster(w, h); } image = new BufferedImage(destCM, wr, destCM.AlphaPremultiplied, null); return(image); }
/// <summary> /// Performs a convolution on Rasters. Each band of the source Raster /// will be convolved. /// The source and destination must have the same number of bands. /// If the destination Raster is null, a new Raster will be created. /// The IllegalArgumentException may be thrown if the source is /// the same as the destination. </summary> /// <param name="src"> the source <code>Raster</code> to filter </param> /// <param name="dst"> the destination <code>WritableRaster</code> for the /// filtered <code>src</code> </param> /// <returns> the filtered <code>WritableRaster</code> </returns> /// <exception cref="NullPointerException"> if <code>src</code> is <code>null</code> </exception> /// <exception cref="ImagingOpException"> if <code>src</code> and <code>dst</code> /// do not have the same number of bands </exception> /// <exception cref="ImagingOpException"> if <code>src</code> cannot be filtered </exception> /// <exception cref="IllegalArgumentException"> if <code>src</code> equals /// <code>dst</code> </exception> public WritableRaster Filter(Raster src, WritableRaster dst) { if (dst == null) { dst = CreateCompatibleDestRaster(src); } else if (src == dst) { throw new IllegalArgumentException("src image cannot be the " + "same as the dst image"); } else if (src.NumBands != dst.NumBands) { throw new ImagingOpException("Different number of bands in src " + " and dst Rasters"); } if (ImagingLib.filter(this, src, dst) == null) { throw new ImagingOpException("Unable to convolve src image"); } return(dst); }
/// <summary> /// Performs a lookup operation on a <code>BufferedImage</code>. /// If the color model in the source image is not the same as that /// in the destination image, the pixels will be converted /// in the destination. If the destination image is <code>null</code>, /// a <code>BufferedImage</code> will be created with an appropriate /// <code>ColorModel</code>. An <code>IllegalArgumentException</code> /// might be thrown if the number of arrays in the /// <code>LookupTable</code> does not meet the restrictions /// stated in the class comment above, or if the source image /// has an <code>IndexColorModel</code>. </summary> /// <param name="src"> the <code>BufferedImage</code> to be filtered </param> /// <param name="dst"> the <code>BufferedImage</code> in which to /// store the results of the filter operation </param> /// <returns> the filtered <code>BufferedImage</code>. </returns> /// <exception cref="IllegalArgumentException"> if the number of arrays in the /// <code>LookupTable</code> does not meet the restrictions /// described in the class comments, or if the source image /// has an <code>IndexColorModel</code>. </exception> public BufferedImage Filter(BufferedImage src, BufferedImage dst) { ColorModel srcCM = src.ColorModel; int numBands = srcCM.NumColorComponents; ColorModel dstCM; if (srcCM is IndexColorModel) { throw new IllegalArgumentException("LookupOp cannot be " + "performed on an indexed image"); } int numComponents = Ltable.NumComponents; if (numComponents != 1 && numComponents != srcCM.NumComponents && numComponents != srcCM.NumColorComponents) { throw new IllegalArgumentException("Number of arrays in the " + " lookup table (" + numComponents + " is not compatible with the " + " src image: " + src); } bool needToConvert = false; int width = src.Width; int height = src.Height; if (dst == null) { dst = CreateCompatibleDestImage(src, null); dstCM = srcCM; } else { if (width != dst.Width) { throw new IllegalArgumentException("Src width (" + width + ") not equal to dst width (" + dst.Width + ")"); } if (height != dst.Height) { throw new IllegalArgumentException("Src height (" + height + ") not equal to dst height (" + dst.Height + ")"); } dstCM = dst.ColorModel; if (srcCM.ColorSpace.Type != dstCM.ColorSpace.Type) { needToConvert = true; dst = CreateCompatibleDestImage(src, null); } } BufferedImage origDst = dst; if (ImagingLib.filter(this, src, dst) == null) { // Do it the slow way WritableRaster srcRaster = src.Raster; WritableRaster dstRaster = dst.Raster; if (srcCM.HasAlpha()) { if (numBands - 1 == numComponents || numComponents == 1) { int minx = srcRaster.MinX; int miny = srcRaster.MinY; int[] bands = new int[numBands - 1]; for (int i = 0; i < numBands - 1; i++) { bands[i] = i; } srcRaster = srcRaster.CreateWritableChild(minx, miny, srcRaster.Width, srcRaster.Height, minx, miny, bands); } } if (dstCM.HasAlpha()) { int dstNumBands = dstRaster.NumBands; if (dstNumBands - 1 == numComponents || numComponents == 1) { int minx = dstRaster.MinX; int miny = dstRaster.MinY; int[] bands = new int[numBands - 1]; for (int i = 0; i < numBands - 1; i++) { bands[i] = i; } dstRaster = dstRaster.CreateWritableChild(minx, miny, dstRaster.Width, dstRaster.Height, minx, miny, bands); } } Filter(srcRaster, dstRaster); } if (needToConvert) { // ColorModels are not the same ColorConvertOp ccop = new ColorConvertOp(Hints); ccop.Filter(dst, origDst); } return(origDst); }
/// <summary> /// Performs a lookup operation on a <code>Raster</code>. /// If the destination <code>Raster</code> is <code>null</code>, /// a new <code>Raster</code> will be created. /// The <code>IllegalArgumentException</code> might be thrown /// if the source <code>Raster</code> and the destination /// <code>Raster</code> do not have the same /// number of bands or if the number of arrays in the /// <code>LookupTable</code> does not meet the /// restrictions stated in the class comment above. </summary> /// <param name="src"> the source <code>Raster</code> to filter </param> /// <param name="dst"> the destination <code>WritableRaster</code> for the /// filtered <code>src</code> </param> /// <returns> the filtered <code>WritableRaster</code>. </returns> /// <exception cref="IllegalArgumentException"> if the source and destinations /// rasters do not have the same number of bands, or the /// number of arrays in the <code>LookupTable</code> does /// not meet the restrictions described in the class comments. /// </exception> public WritableRaster Filter(Raster src, WritableRaster dst) { int numBands = src.NumBands; int dstLength = dst.NumBands; int height = src.Height; int width = src.Width; int[] srcPix = new int[numBands]; // Create a new destination Raster, if needed if (dst == null) { dst = CreateCompatibleDestRaster(src); } else if (height != dst.Height || width != dst.Width) { throw new IllegalArgumentException("Width or height of Rasters do not " + "match"); } dstLength = dst.NumBands; if (numBands != dstLength) { throw new IllegalArgumentException("Number of channels in the src (" + numBands + ") does not match number of channels" + " in the destination (" + dstLength + ")"); } int numComponents = Ltable.NumComponents; if (numComponents != 1 && numComponents != src.NumBands) { throw new IllegalArgumentException("Number of arrays in the " + " lookup table (" + numComponents + " is not compatible with the " + " src Raster: " + src); } if (ImagingLib.filter(this, src, dst) != null) { return(dst); } // Optimize for cases we know about if (Ltable is ByteLookupTable) { ByteFilter((ByteLookupTable)Ltable, src, dst, width, height, numBands); } else if (Ltable is ShortLookupTable) { ShortFilter((ShortLookupTable)Ltable, src, dst, width, height, numBands); } else { // Not one we recognize so do it slowly int sminX = src.MinX; int sY = src.MinY; int dminX = dst.MinX; int dY = dst.MinY; for (int y = 0; y < height; y++, sY++, dY++) { int sX = sminX; int dX = dminX; for (int x = 0; x < width; x++, sX++, dX++) { // Find data for all bands at this x,y position src.GetPixel(sX, sY, srcPix); // Lookup the data for all bands at this x,y position Ltable.LookupPixel(srcPix, srcPix); // Put it back for all bands dst.SetPixel(dX, dY, srcPix); } } } return(dst); }
private BufferedImage NonICCBIFilter(BufferedImage src, ColorSpace srcColorSpace, BufferedImage dst, ColorSpace dstColorSpace) { int w = src.Width; int h = src.Height; ICC_ColorSpace ciespace = (ICC_ColorSpace)ColorSpace.GetInstance(ColorSpace.CS_CIEXYZ); if (dst == null) { dst = CreateCompatibleDestImage(src, null); dstColorSpace = dst.ColorModel.ColorSpace; } else { if ((h != dst.Height) || (w != dst.Width)) { throw new IllegalArgumentException("Width or height of BufferedImages do not match"); } } Raster srcRas = src.Raster; WritableRaster dstRas = dst.Raster; ColorModel srcCM = src.ColorModel; ColorModel dstCM = dst.ColorModel; int srcNumComp = srcCM.NumColorComponents; int dstNumComp = dstCM.NumColorComponents; bool dstHasAlpha = dstCM.HasAlpha(); bool needSrcAlpha = srcCM.HasAlpha() && dstHasAlpha; ColorSpace[] list; if ((CSList == null) && (ProfileList.Length != 0)) { /* possible non-ICC src, some profiles, possible non-ICC dst */ bool nonICCSrc, nonICCDst; ICC_Profile srcProfile, dstProfile; if (!(srcColorSpace is ICC_ColorSpace)) { nonICCSrc = true; srcProfile = ciespace.Profile; } else { nonICCSrc = false; srcProfile = ((ICC_ColorSpace)srcColorSpace).Profile; } if (!(dstColorSpace is ICC_ColorSpace)) { nonICCDst = true; dstProfile = ciespace.Profile; } else { nonICCDst = false; dstProfile = ((ICC_ColorSpace)dstColorSpace).Profile; } /* make a new transform if needed */ if ((ThisTransform == null) || (ThisSrcProfile != srcProfile) || (ThisDestProfile != dstProfile)) { UpdateBITransform(srcProfile, dstProfile); } // process per scanline float maxNum = 65535.0f; // use 16-bit precision in CMM ColorSpace cs; int iccSrcNumComp; if (nonICCSrc) { cs = ciespace; iccSrcNumComp = 3; } else { cs = srcColorSpace; iccSrcNumComp = srcNumComp; } float[] srcMinVal = new float[iccSrcNumComp]; float[] srcInvDiffMinMax = new float[iccSrcNumComp]; for (int i = 0; i < srcNumComp; i++) { srcMinVal[i] = cs.GetMinValue(i); srcInvDiffMinMax[i] = maxNum / (cs.GetMaxValue(i) - srcMinVal[i]); } int iccDstNumComp; if (nonICCDst) { cs = ciespace; iccDstNumComp = 3; } else { cs = dstColorSpace; iccDstNumComp = dstNumComp; } float[] dstMinVal = new float[iccDstNumComp]; float[] dstDiffMinMax = new float[iccDstNumComp]; for (int i = 0; i < dstNumComp; i++) { dstMinVal[i] = cs.GetMinValue(i); dstDiffMinMax[i] = (cs.GetMaxValue(i) - dstMinVal[i]) / maxNum; } float[] dstColor; if (dstHasAlpha) { int size = ((dstNumComp + 1) > 3) ? (dstNumComp + 1) : 3; dstColor = new float[size]; } else { int size = (dstNumComp > 3) ? dstNumComp : 3; dstColor = new float[size]; } short[] srcLine = new short[w * iccSrcNumComp]; short[] dstLine = new short[w * iccDstNumComp]; Object pixel; float[] color; float[] alpha = null; if (needSrcAlpha) { alpha = new float[w]; } int idx; // process each scanline for (int y = 0; y < h; y++) { // convert src scanline pixel = null; color = null; idx = 0; for (int x = 0; x < w; x++) { pixel = srcRas.GetDataElements(x, y, pixel); color = srcCM.GetNormalizedComponents(pixel, color, 0); if (needSrcAlpha) { alpha[x] = color[srcNumComp]; } if (nonICCSrc) { color = srcColorSpace.ToCIEXYZ(color); } for (int i = 0; i < iccSrcNumComp; i++) { srcLine[idx++] = (short)((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + 0.5f); } } // color convert srcLine to dstLine ThisTransform.colorConvert(srcLine, dstLine); // convert dst scanline pixel = null; idx = 0; for (int x = 0; x < w; x++) { for (int i = 0; i < iccDstNumComp; i++) { dstColor[i] = ((float)(dstLine[idx++] & 0xffff)) * dstDiffMinMax[i] + dstMinVal[i]; } if (nonICCDst) { color = srcColorSpace.FromCIEXYZ(dstColor); for (int i = 0; i < dstNumComp; i++) { dstColor[i] = color[i]; } } if (needSrcAlpha) { dstColor[dstNumComp] = alpha[x]; } else if (dstHasAlpha) { dstColor[dstNumComp] = 1.0f; } pixel = dstCM.GetDataElements(dstColor, 0, pixel); dstRas.SetDataElements(x, y, pixel); } } } else { /* possible non-ICC src, possible CSList, possible non-ICC dst */ // process per pixel int numCS; if (CSList == null) { numCS = 0; } else { numCS = CSList.Length; } float[] dstColor; if (dstHasAlpha) { dstColor = new float[dstNumComp + 1]; } else { dstColor = new float[dstNumComp]; } Object spixel = null; Object dpixel = null; float[] color = null; float[] tmpColor; // process each pixel for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { spixel = srcRas.GetDataElements(x, y, spixel); color = srcCM.GetNormalizedComponents(spixel, color, 0); tmpColor = srcColorSpace.ToCIEXYZ(color); for (int i = 0; i < numCS; i++) { tmpColor = CSList[i].FromCIEXYZ(tmpColor); tmpColor = CSList[i].ToCIEXYZ(tmpColor); } tmpColor = dstColorSpace.FromCIEXYZ(tmpColor); for (int i = 0; i < dstNumComp; i++) { dstColor[i] = tmpColor[i]; } if (needSrcAlpha) { dstColor[dstNumComp] = color[srcNumComp]; } else if (dstHasAlpha) { dstColor[dstNumComp] = 1.0f; } dpixel = dstCM.GetDataElements(dstColor, 0, dpixel); dstRas.SetDataElements(x, y, dpixel); } } } return(dst); }
/// <summary> /// Constructs a WritableRaster with the given SampleModel, DataBuffer, /// and parent. /// </summary> public WritableRaster(SampleModel @sampleModel, DataBuffer @dataBuffer, Rectangle @aRegion, Point @sampleModelTranslate, WritableRaster @parent) : base(sampleModel, null) { }
/// <summary> /// ColorConverts the image data in the source Raster. /// If the destination Raster is null, a new Raster will be created. /// The number of bands in the source and destination Rasters must /// meet the requirements explained above. The constructor used to /// create this ColorConvertOp must have provided enough information /// to define both source and destination color spaces. See above. /// Otherwise, an exception is thrown. </summary> /// <param name="src"> the source <code>Raster</code> to be converted </param> /// <param name="dest"> the destination <code>WritableRaster</code>, /// or <code>null</code> </param> /// <returns> <code>dest</code> color converted from <code>src</code> /// or a new, converted <code>WritableRaster</code> /// if <code>dest</code> is <code>null</code> </returns> /// <exception cref="IllegalArgumentException"> if the number of source or /// destination bands is incorrect, the source or destination /// color spaces are undefined, or this op was constructed /// with one of the constructors that applies only to /// operations on BufferedImages. </exception> public WritableRaster Filter(Raster src, WritableRaster dest) { if (CSList != null) { /* non-ICC case */ return(NonICCRasterFilter(src, dest)); } int nProfiles = ProfileList.Length; if (nProfiles < 2) { throw new IllegalArgumentException("Source or Destination ColorSpace is undefined"); } if (src.NumBands != ProfileList[0].NumComponents) { throw new IllegalArgumentException("Numbers of source Raster bands and source color space " + "components do not match"); } if (dest == null) { dest = CreateCompatibleDestRaster(src); } else { if (src.Height != dest.Height || src.Width != dest.Width) { throw new IllegalArgumentException("Width or height of Rasters do not match"); } if (dest.NumBands != ProfileList[nProfiles - 1].NumComponents) { throw new IllegalArgumentException("Numbers of destination Raster bands and destination " + "color space components do not match"); } } /* make a new transform if needed */ if (ThisRasterTransform == null) { int i1, whichTrans, renderState; ColorTransform[] theTransforms; /* make the transform list */ theTransforms = new ColorTransform [nProfiles]; /* initialize transform get loop */ if (ProfileList[0].ProfileClass == ICC_Profile.CLASS_OUTPUT) { /* if first profile is a printer * render as colorimetric */ renderState = ICC_Profile.IcRelativeColorimetric; } else { renderState = ICC_Profile.IcPerceptual; /* render any other * class perceptually */ } whichTrans = ColorTransform.In; PCMM mdl = CMSManager.Module; /* get the transforms from each profile */ for (i1 = 0; i1 < nProfiles; i1++) { if (i1 == nProfiles - 1) // last profile? { whichTrans = ColorTransform.Out; // get output transform } else // check for abstract profile { if ((whichTrans == ColorTransform.Simulation) && (ProfileList[i1].ProfileClass == ICC_Profile.CLASS_ABSTRACT)) { renderState = ICC_Profile.IcPerceptual; whichTrans = ColorTransform.In; } } theTransforms[i1] = mdl.createTransform(ProfileList[i1], renderState, whichTrans); /* get this profile's rendering intent to select transform * from next profile */ renderState = GetRenderingIntent(ProfileList[i1]); /* "middle" profiles use simulation transform */ whichTrans = ColorTransform.Simulation; } /* make the net transform */ ThisRasterTransform = mdl.createTransform(theTransforms); } int srcTransferType = src.TransferType; int dstTransferType = dest.TransferType; if ((srcTransferType == DataBuffer.TYPE_FLOAT) || (srcTransferType == DataBuffer.TYPE_DOUBLE) || (dstTransferType == DataBuffer.TYPE_FLOAT) || (dstTransferType == DataBuffer.TYPE_DOUBLE)) { if (SrcMinVals == null) { GetMinMaxValsFromProfiles(ProfileList[0], ProfileList[nProfiles - 1]); } /* color convert the raster */ ThisRasterTransform.colorConvert(src, dest, SrcMinVals, SrcMaxVals, DstMinVals, DstMaxVals); } else { /* color convert the raster */ ThisRasterTransform.colorConvert(src, dest); } return(dest); }
/// <summary> /// Returns a <code>Raster</code> representing the alpha channel of an /// image, extracted from the input <code>Raster</code>, provided that /// pixel values of this <code>ColorModel</code> represent color and /// alpha information as separate spatial bands (e.g. /// </summary> public WritableRaster getAlphaRaster(WritableRaster @raster) { return(default(WritableRaster)); }
/// <summary> /// Returns a <code>Raster</code> representing the alpha channel of an /// image, extracted from the input <code>Raster</code>, provided that /// pixel values of this <code>ColorModel</code> represent color and /// alpha information as separate spatial bands (e.g. /// </summary> public WritableRaster getAlphaRaster(WritableRaster @raster) { return default(WritableRaster); }
/// <summary> /// Constructs a new <code>BufferedImage</code> with a specified /// <code>ColorModel</code> and <code>Raster</code>. /// </summary> public BufferedImage(ColorModel @cm, WritableRaster @raster, bool @isRasterPremultiplied, Hashtable @properties) { }
/// <summary> /// Computes an arbitrary rectangular region of the /// <code>BufferedImage</code> and copies it into a specified /// <code>WritableRaster</code>. /// </summary> public WritableRaster copyData(WritableRaster @outRaster) { return(default(WritableRaster)); }
/// <summary> /// Rescales the source BufferedImage. /// If the color model in the source image is not the same as that /// in the destination image, the pixels will be converted /// in the destination. If the destination image is null, /// a BufferedImage will be created with the source ColorModel. /// An IllegalArgumentException may be thrown if the number of /// scaling factors/offsets in this object does not meet the /// restrictions stated in the class comments above, or if the /// source image has an IndexColorModel. </summary> /// <param name="src"> the <code>BufferedImage</code> to be filtered </param> /// <param name="dst"> the destination for the filtering operation /// or <code>null</code> </param> /// <returns> the filtered <code>BufferedImage</code>. </returns> /// <exception cref="IllegalArgumentException"> if the <code>ColorModel</code> /// of <code>src</code> is an <code>IndexColorModel</code>, /// or if the number of scaling factors and offsets in this /// <code>RescaleOp</code> do not meet the requirements /// stated in the class comments. </exception> public BufferedImage Filter(BufferedImage src, BufferedImage dst) { ColorModel srcCM = src.ColorModel; ColorModel dstCM; int numBands = srcCM.NumColorComponents; if (srcCM is IndexColorModel) { throw new IllegalArgumentException("Rescaling cannot be " + "performed on an indexed image"); } if (Length != 1 && Length != numBands && Length != srcCM.NumComponents) { throw new IllegalArgumentException("Number of scaling constants " + "does not equal the number of" + " of color or color/alpha " + " components"); } bool needToConvert = false; // Include alpha if (Length > numBands && srcCM.HasAlpha()) { Length = numBands + 1; } int width = src.Width; int height = src.Height; if (dst == null) { dst = CreateCompatibleDestImage(src, null); dstCM = srcCM; } else { if (width != dst.Width) { throw new IllegalArgumentException("Src width (" + width + ") not equal to dst width (" + dst.Width + ")"); } if (height != dst.Height) { throw new IllegalArgumentException("Src height (" + height + ") not equal to dst height (" + dst.Height + ")"); } dstCM = dst.ColorModel; if (srcCM.ColorSpace.Type != dstCM.ColorSpace.Type) { needToConvert = true; dst = CreateCompatibleDestImage(src, null); } } BufferedImage origDst = dst; // // Try to use a native BI rescale operation first // if (ImagingLib.filter(this, src, dst) == null) { // // Native BI rescale failed - convert to rasters // WritableRaster srcRaster = src.Raster; WritableRaster dstRaster = dst.Raster; if (srcCM.HasAlpha()) { if (numBands - 1 == Length || Length == 1) { int minx = srcRaster.MinX; int miny = srcRaster.MinY; int[] bands = new int[numBands - 1]; for (int i = 0; i < numBands - 1; i++) { bands[i] = i; } srcRaster = srcRaster.CreateWritableChild(minx, miny, srcRaster.Width, srcRaster.Height, minx, miny, bands); } } if (dstCM.HasAlpha()) { int dstNumBands = dstRaster.NumBands; if (dstNumBands - 1 == Length || Length == 1) { int minx = dstRaster.MinX; int miny = dstRaster.MinY; int[] bands = new int[numBands - 1]; for (int i = 0; i < numBands - 1; i++) { bands[i] = i; } dstRaster = dstRaster.CreateWritableChild(minx, miny, dstRaster.Width, dstRaster.Height, minx, miny, bands); } } // // Call the raster filter method // Filter(srcRaster, dstRaster); } if (needToConvert) { // ColorModels are not the same ColorConvertOp ccop = new ColorConvertOp(Hints); ccop.Filter(dst, origDst); } return(origDst); }
/// <summary> /// Transforms the <CODE>Raster</CODE> using the matrix specified in the /// constructor. An <CODE>IllegalArgumentException</CODE> may be thrown if /// the number of bands in the source or destination is incompatible with /// the matrix. See the class comments for more details. /// <para> /// If the destination is null, it will be created with a number of bands /// equalling the number of rows in the matrix. No exception is thrown /// if the operation causes a data overflow. /// /// </para> /// </summary> /// <param name="src"> The <CODE>Raster</CODE> to be filtered. </param> /// <param name="dst"> The <CODE>Raster</CODE> in which to store the results /// of the filter operation. /// </param> /// <returns> The filtered <CODE>Raster</CODE>. /// </returns> /// <exception cref="IllegalArgumentException"> If the number of bands in the /// source or destination is incompatible with the matrix. </exception> public virtual WritableRaster Filter(Raster src, WritableRaster dst) { int nBands = src.NumBands; if (Ncols != nBands && Ncols != (nBands + 1)) { throw new IllegalArgumentException("Number of columns in the " + "matrix (" + Ncols + ") must be equal to the number" + " of bands ([+1]) in src (" + nBands + ")."); } if (dst == null) { dst = CreateCompatibleDestRaster(src); } else if (Nrows != dst.NumBands) { throw new IllegalArgumentException("Number of rows in the " + "matrix (" + Nrows + ") must be equal to the number" + " of bands ([+1]) in dst (" + nBands + ")."); } if (ImagingLib.filter(this, src, dst) != null) { return(dst); } int[] pixel = null; int[] dstPixel = new int[dst.NumBands]; float accum; int sminX = src.MinX; int sY = src.MinY; int dminX = dst.MinX; int dY = dst.MinY; int sX; int dX; if (Ncols == nBands) { for (int y = 0; y < src.Height; y++, sY++, dY++) { dX = dminX; sX = sminX; for (int x = 0; x < src.Width; x++, sX++, dX++) { pixel = src.GetPixel(sX, sY, pixel); for (int r = 0; r < Nrows; r++) { accum = 0.0f; for (int c = 0; c < Ncols; c++) { accum += Matrix_Renamed[r][c] * pixel[c]; } dstPixel[r] = (int)accum; } dst.SetPixel(dX, dY, dstPixel); } } } else { // Need to add constant for (int y = 0; y < src.Height; y++, sY++, dY++) { dX = dminX; sX = sminX; for (int x = 0; x < src.Width; x++, sX++, dX++) { pixel = src.GetPixel(sX, sY, pixel); for (int r = 0; r < Nrows; r++) { accum = 0.0f; for (int c = 0; c < nBands; c++) { accum += Matrix_Renamed[r][c] * pixel[c]; } dstPixel[r] = (int)(accum + Matrix_Renamed[r][nBands]); } dst.SetPixel(dX, dY, dstPixel); } } } return(dst); }
/// <summary> /// Computes an arbitrary rectangular region of the /// <code>BufferedImage</code> and copies it into a specified /// <code>WritableRaster</code>. /// </summary> public WritableRaster copyData(WritableRaster @outRaster) { return default(WritableRaster); }
/// <summary> /// Forces the raster data to match the state specified in the /// <code>isAlphaPremultiplied</code> variable, assuming the data is /// currently correctly described by this <code>ColorModel</code>. /// </summary> public ColorModel coerceData(WritableRaster @raster, bool @isAlphaPremultiplied) { return(default(ColorModel)); }
/* color convert a Raster - handles byte, ushort, int, short, float, * or double transferTypes */ private WritableRaster NonICCRasterFilter(Raster src, WritableRaster dst) { if (CSList.Length != 2) { throw new IllegalArgumentException("Destination ColorSpace is undefined"); } if (src.NumBands != CSList[0].NumComponents) { throw new IllegalArgumentException("Numbers of source Raster bands and source color space " + "components do not match"); } if (dst == null) { dst = CreateCompatibleDestRaster(src); } else { if (src.Height != dst.Height || src.Width != dst.Width) { throw new IllegalArgumentException("Width or height of Rasters do not match"); } if (dst.NumBands != CSList[1].NumComponents) { throw new IllegalArgumentException("Numbers of destination Raster bands and destination " + "color space components do not match"); } } if (SrcMinVals == null) { GetMinMaxValsFromColorSpaces(CSList[0], CSList[1]); } SampleModel srcSM = src.SampleModel; SampleModel dstSM = dst.SampleModel; bool srcIsFloat, dstIsFloat; int srcTransferType = src.TransferType; int dstTransferType = dst.TransferType; if ((srcTransferType == DataBuffer.TYPE_FLOAT) || (srcTransferType == DataBuffer.TYPE_DOUBLE)) { srcIsFloat = true; } else { srcIsFloat = false; } if ((dstTransferType == DataBuffer.TYPE_FLOAT) || (dstTransferType == DataBuffer.TYPE_DOUBLE)) { dstIsFloat = true; } else { dstIsFloat = false; } int w = src.Width; int h = src.Height; int srcNumBands = src.NumBands; int dstNumBands = dst.NumBands; float[] srcScaleFactor = null; float[] dstScaleFactor = null; if (!srcIsFloat) { srcScaleFactor = new float[srcNumBands]; for (int i = 0; i < srcNumBands; i++) { if (srcTransferType == DataBuffer.TYPE_SHORT) { srcScaleFactor[i] = (SrcMaxVals[i] - SrcMinVals[i]) / 32767.0f; } else { srcScaleFactor[i] = (SrcMaxVals[i] - SrcMinVals[i]) / ((float)((1 << srcSM.GetSampleSize(i)) - 1)); } } } if (!dstIsFloat) { dstScaleFactor = new float[dstNumBands]; for (int i = 0; i < dstNumBands; i++) { if (dstTransferType == DataBuffer.TYPE_SHORT) { dstScaleFactor[i] = 32767.0f / (DstMaxVals[i] - DstMinVals[i]); } else { dstScaleFactor[i] = ((float)((1 << dstSM.GetSampleSize(i)) - 1)) / (DstMaxVals[i] - DstMinVals[i]); } } } int ys = src.MinY; int yd = dst.MinY; int xs, xd; float sample; float[] color = new float[srcNumBands]; float[] tmpColor; ColorSpace srcColorSpace = CSList[0]; ColorSpace dstColorSpace = CSList[1]; // process each pixel for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline xs = src.MinX; xd = dst.MinX; for (int x = 0; x < w; x++, xs++, xd++) { for (int i = 0; i < srcNumBands; i++) { sample = src.GetSampleFloat(xs, ys, i); if (!srcIsFloat) { sample = sample * srcScaleFactor[i] + SrcMinVals[i]; } color[i] = sample; } tmpColor = srcColorSpace.ToCIEXYZ(color); tmpColor = dstColorSpace.FromCIEXYZ(tmpColor); for (int i = 0; i < dstNumBands; i++) { sample = tmpColor[i]; if (!dstIsFloat) { sample = (sample - DstMinVals[i]) * dstScaleFactor[i]; } dst.SetSample(xd, yd, i, sample); } } } return(dst); }
/// <summary> /// Transforms the source <CODE>BufferedImage</CODE> and stores the results /// in the destination <CODE>BufferedImage</CODE>. /// If the color models for the two images do not match, a color /// conversion into the destination color model is performed. /// If the destination image is null, /// a <CODE>BufferedImage</CODE> is created with the source /// <CODE>ColorModel</CODE>. /// <para> /// The coordinates of the rectangle returned by /// <code>getBounds2D(BufferedImage)</code> /// are not necessarily the same as the coordinates of the /// <code>BufferedImage</code> returned by this method. If the /// upper-left corner coordinates of the rectangle are /// negative then this part of the rectangle is not drawn. If the /// upper-left corner coordinates of the rectangle are positive /// then the filtered image is drawn at that position in the /// destination <code>BufferedImage</code>. /// </para> /// <para> /// An <CODE>IllegalArgumentException</CODE> is thrown if the source is /// the same as the destination. /// /// </para> /// </summary> /// <param name="src"> The <CODE>BufferedImage</CODE> to transform. </param> /// <param name="dst"> The <CODE>BufferedImage</CODE> in which to store the results /// of the transformation. /// </param> /// <returns> The filtered <CODE>BufferedImage</CODE>. </returns> /// <exception cref="IllegalArgumentException"> if <code>src</code> and /// <code>dst</code> are the same </exception> /// <exception cref="ImagingOpException"> if the image cannot be transformed /// because of a data-processing error that might be /// caused by an invalid image format, tile format, or /// image-processing operation, or any other unsupported /// operation. </exception> public BufferedImage Filter(BufferedImage src, BufferedImage dst) { if (src == null) { throw new NullPointerException("src image is null"); } if (src == dst) { throw new IllegalArgumentException("src image cannot be the " + "same as the dst image"); } bool needToConvert = false; ColorModel srcCM = src.ColorModel; ColorModel dstCM; BufferedImage origDst = dst; if (dst == null) { dst = CreateCompatibleDestImage(src, null); dstCM = srcCM; origDst = dst; } else { dstCM = dst.ColorModel; if (srcCM.ColorSpace.Type != dstCM.ColorSpace.Type) { int type = Xform.Type; bool needTrans = ((type & (Xform.TYPE_MASK_ROTATION | Xform.TYPE_GENERAL_TRANSFORM)) != 0); if (!needTrans && type != Xform.TYPE_TRANSLATION && type != Xform.TYPE_IDENTITY) { double[] mtx = new double[4]; Xform.GetMatrix(mtx); // Check out the matrix. A non-integral scale will force ARGB // since the edge conditions can't be guaranteed. needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]); } if (needTrans && srcCM.Transparency == java.awt.Transparency_Fields.OPAQUE) { // Need to convert first ColorConvertOp ccop = new ColorConvertOp(Hints); BufferedImage tmpSrc = null; int sw = src.Width; int sh = src.Height; if (dstCM.Transparency == java.awt.Transparency_Fields.OPAQUE) { tmpSrc = new BufferedImage(sw, sh, BufferedImage.TYPE_INT_ARGB); } else { WritableRaster r = dstCM.CreateCompatibleWritableRaster(sw, sh); tmpSrc = new BufferedImage(dstCM, r, dstCM.AlphaPremultiplied, null); } src = ccop.Filter(src, tmpSrc); } else { needToConvert = true; dst = CreateCompatibleDestImage(src, null); } } } if (InterpolationType_Renamed != TYPE_NEAREST_NEIGHBOR && dst.ColorModel is IndexColorModel) { dst = new BufferedImage(dst.Width, dst.Height, BufferedImage.TYPE_INT_ARGB); } if (ImagingLib.filter(this, src, dst) == null) { throw new ImagingOpException("Unable to transform src image"); } if (needToConvert) { ColorConvertOp ccop = new ColorConvertOp(Hints); ccop.Filter(dst, origDst); } else if (origDst != dst) { java.awt.Graphics2D g = origDst.CreateGraphics(); try { g.Composite = AlphaComposite.Src; g.DrawImage(dst, 0, 0, null); } finally { g.Dispose(); } } return(origDst); }
/// <summary> /// Rescales the pixel data in the source Raster. /// If the destination Raster is null, a new Raster will be created. /// The source and destination must have the same number of bands. /// Otherwise, an IllegalArgumentException is thrown. /// Note that the number of scaling factors/offsets in this object must /// meet the restrictions stated in the class comments above. /// Otherwise, an IllegalArgumentException is thrown. </summary> /// <param name="src"> the <code>Raster</code> to be filtered </param> /// <param name="dst"> the destination for the filtering operation /// or <code>null</code> </param> /// <returns> the filtered <code>WritableRaster</code>. </returns> /// <exception cref="IllegalArgumentException"> if <code>src</code> and /// <code>dst</code> do not have the same number of bands, /// or if the number of scaling factors and offsets in this /// <code>RescaleOp</code> do not meet the requirements /// stated in the class comments. </exception> public WritableRaster Filter(Raster src, WritableRaster dst) { int numBands = src.NumBands; int width = src.Width; int height = src.Height; int[] srcPix = null; int step = 0; int tidx = 0; // Create a new destination Raster, if needed if (dst == null) { dst = CreateCompatibleDestRaster(src); } else if (height != dst.Height || width != dst.Width) { throw new IllegalArgumentException("Width or height of Rasters do not " + "match"); } else if (numBands != dst.NumBands) { // Make sure that the number of bands are equal throw new IllegalArgumentException("Number of bands in src " + numBands + " does not equal number of bands in dest " + dst.NumBands); } // Make sure that the arrays match // Make sure that the low/high/constant arrays match if (Length != 1 && Length != src.NumBands) { throw new IllegalArgumentException("Number of scaling constants " + "does not equal the number of" + " of bands in the src raster"); } // // Try for a native raster rescale first // if (ImagingLib.filter(this, src, dst) != null) { return(dst); } // // Native raster rescale failed. // Try to see if a lookup operation can be used // if (CanUseLookup(src, dst)) { int srcNgray = (1 << SrcNbits); int dstNgray = (1 << DstNbits); if (dstNgray == 256) { ByteLookupTable lut = CreateByteLut(ScaleFactors, Offsets, numBands, srcNgray); LookupOp op = new LookupOp(lut, Hints); op.Filter(src, dst); } else { ShortLookupTable lut = CreateShortLut(ScaleFactors, Offsets, numBands, srcNgray); LookupOp op = new LookupOp(lut, Hints); op.Filter(src, dst); } } else { // // Fall back to the slow code // if (Length > 1) { step = 1; } int sminX = src.MinX; int sY = src.MinY; int dminX = dst.MinX; int dY = dst.MinY; int sX; int dX; // // Determine bits per band to determine maxval for clamps. // The min is assumed to be zero. // REMIND: This must change if we ever support signed data types. // int nbits; int[] dstMax = new int[numBands]; int[] dstMask = new int[numBands]; SampleModel dstSM = dst.SampleModel; for (int z = 0; z < numBands; z++) { nbits = dstSM.GetSampleSize(z); dstMax[z] = (1 << nbits) - 1; dstMask[z] = ~(dstMax[z]); } int val; for (int y = 0; y < height; y++, sY++, dY++) { dX = dminX; sX = sminX; for (int x = 0; x < width; x++, sX++, dX++) { // Get data for all bands at this x,y position srcPix = src.GetPixel(sX, sY, srcPix); tidx = 0; for (int z = 0; z < numBands; z++, tidx += step) { val = (int)(srcPix[z] * ScaleFactors[tidx] + Offsets[tidx]); // Clamp if ((val & dstMask[z]) != 0) { if (val < 0) { val = 0; } else { val = dstMax[z]; } } srcPix[z] = val; } // Put it back for all bands dst.SetPixel(dX, dY, srcPix); } } } return(dst); }
/// <summary> /// Forces the raster data to match the state specified in the /// <code>isAlphaPremultiplied</code> variable, assuming the data is /// currently correctly described by this <code>ColorModel</code>. /// </summary> public ColorModel coerceData(WritableRaster @raster, bool @isAlphaPremultiplied) { return default(ColorModel); }