private BufferedImage CreateCompatibleDestImage(BufferedImage src, ColorModel destCM, ColorSpace destCS) { BufferedImage image; if (destCM == null) { ColorModel srcCM = src.ColorModel; int nbands = destCS.NumComponents; bool hasAlpha = srcCM.HasAlpha(); if (hasAlpha) { nbands += 1; } int[] nbits = new int[nbands]; for (int i = 0; i < nbands; i++) { nbits[i] = 8; } destCM = new ComponentColorModel(destCS, nbits, hasAlpha, srcCM.AlphaPremultiplied, srcCM.Transparency, DataBuffer.TYPE_BYTE); } int w = src.Width; int h = src.Height; image = new BufferedImage(destCM, destCM.CreateCompatibleWritableRaster(w, h), destCM.AlphaPremultiplied, null); return(image); }
/// <summary> /// Creates a zeroed destination image with the correct size and number of /// bands. If destCM is <code>null</code>, an appropriate /// <code>ColorModel</code> will be used. </summary> /// <param name="src"> Source image for the filter operation. </param> /// <param name="destCM"> the destination's <code>ColorModel</code>, which /// can be <code>null</code>. </param> /// <returns> a filtered destination <code>BufferedImage</code>. </returns> public virtual BufferedImage CreateCompatibleDestImage(BufferedImage src, ColorModel destCM) { BufferedImage image; int w = src.Width; int h = src.Height; int transferType = DataBuffer.TYPE_BYTE; if (destCM == null) { ColorModel cm = src.ColorModel; Raster raster = src.Raster; if (cm is ComponentColorModel) { DataBuffer db = raster.DataBuffer; bool hasAlpha = cm.HasAlpha(); bool isPre = cm.AlphaPremultiplied; int trans = cm.Transparency; int[] nbits = null; if (Ltable is ByteLookupTable) { if (db.DataType == db.TYPE_USHORT) { // Dst raster should be of type byte if (hasAlpha) { nbits = new int[2]; if (trans == cm.BITMASK) { nbits[1] = 1; } else { nbits[1] = 8; } } else { nbits = new int[1]; } nbits[0] = 8; } // For byte, no need to change the cm } else if (Ltable is ShortLookupTable) { transferType = DataBuffer.TYPE_USHORT; if (db.DataType == db.TYPE_BYTE) { if (hasAlpha) { nbits = new int[2]; if (trans == cm.BITMASK) { nbits[1] = 1; } else { nbits[1] = 16; } } else { nbits = new int[1]; } nbits[0] = 16; } } if (nbits != null) { cm = new ComponentColorModel(cm.ColorSpace, nbits, hasAlpha, isPre, trans, transferType); } } image = new BufferedImage(cm, cm.CreateCompatibleWritableRaster(w, h), cm.AlphaPremultiplied, null); } else { image = new BufferedImage(destCM, destCM.CreateCompatibleWritableRaster(w, h), destCM.AlphaPremultiplied, null); } return(image); }
/// <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); }
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> /// 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); }