/** * This function 'fixes' the source's color model. Right now it just selects if it should have one * or two bands based on if the source had an alpha channel. */ protected static ColorModel fixColorModel(CachableRed src) { ColorModel cm = src.getColorModel(); if (cm != null) { if (cm.hasAlpha()) return GraphicsUtil.Linear_sRGB_Unpre; return GraphicsUtil.Linear_sRGB; } else { // No ColorModel so try to make some intelligent // decisions based just on the number of bands... // 1 bands -> replicated into RGB // 2 bands -> Band 0 replicated into RGB & Band 1 -> alpha premult // 3 bands -> sRGB (not-linear?) // 4 bands -> sRGB premult (not-linear?) SampleModel sm = src.getSampleModel(); switch (sm.getNumBands()) { case 1: return GraphicsUtil.Linear_sRGB; case 2: return GraphicsUtil.Linear_sRGB_Unpre; case 3: return GraphicsUtil.Linear_sRGB; } return GraphicsUtil.Linear_sRGB_Unpre; } }
/** * This function 'fixes' the source's sample model. Right now it just selects if it should have 3 * or 4 bands based on if the source had an alpha channel. */ protected static SampleModel fixSampleModel(CachableRed src) { SampleModel sm = src.getSampleModel(); ColorModel cm = src.getColorModel(); int width = sm.getWidth(); int height = sm.getHeight(); boolean alpha = false; if (cm != null) alpha = cm.hasAlpha(); else { switch (sm.getNumBands()) { case 1: case 3: alpha = false; break; default: alpha = true; break; } } if (alpha) return new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, sm.getWidth(), sm.getHeight(), new int[] {0xFF0000, 0xFF00, 0xFF, 0xFF000000}); else return new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, sm.getWidth(), sm.getHeight(), new int[] {0xFF0000, 0xFF00, 0xFF}); }
public AffineRed(CachableRed src, AffineTransform src2me, RenderingHints hints) { super(); // We _must_ call init... this.src2me = src2me; this.hints = hints; try { me2src = src2me.createInverse(); } catch (NoninvertibleTransformException nite) { me2src = null; } // Calculate my bounds by applying the affine transform to // my input data..codec/ Rectangle srcBounds = src.getBounds(); // srcBounds.grow(-1,-1); Rectangle myBounds; myBounds = src2me.createTransformedShape(srcBounds).getBounds(); // If the output buffer is not premultiplied in certain cases it // fails to properly divide out the Alpha (it always does // the affine on premultiplied data), hence you get ugly // back aliasing effects... ColorModel cm = fixColorModel(src); // fix my sample model so it makes sense given my size. SampleModel sm = fixSampleModel(src, cm, myBounds); Point2D pt = new Point2D.Float(src.getTileGridXOffset(), src.getTileGridYOffset()); pt = src2me.transform(pt, null); // Finish initializing our base class... init(src, myBounds, cm, sm, (int) pt.getX(), (int) pt.getY(), null); }
protected static ColorModel fixColorModel(CachableRed src) { ColorModel cm = src.getColorModel(); if (cm.hasAlpha()) { if (!cm.isAlphaPremultiplied()) cm = GraphicsUtil.coerceColorModel(cm, true); return cm; } ColorSpace cs = cm.getColorSpace(); int b = src.getSampleModel().getNumBands() + 1; if (b == 4) { int[] masks = new int[4]; for (int i = 0; i < b - 1; i++) masks[i] = 0xFF0000 >> (8 * i); masks[3] = 0xFF << (8 * (b - 1)); return new DirectColorModel( cs, 8 * b, masks[0], masks[1], masks[2], masks[3], true, DataBuffer.TYPE_INT); } int[] bits = new int[b]; for (int i = 0; i < b; i++) bits[i] = 8; return new ComponentColorModel( cs, bits, true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_INT); }
public WritableRaster copyData(WritableRaster wr) { // Get my source. CachableRed src = (CachableRed) getSources().get(0); Rectangle srcR = src.getBounds(); Rectangle wrR = wr.getBounds(); if (wrR.intersects(srcR)) { Rectangle r = wrR.intersection(srcR); // Limit the raster I send to my source to his rect. WritableRaster srcWR; srcWR = wr.createWritableChild(r.x, r.y, r.width, r.height, r.x, r.y, null); src.copyData(srcWR); } if (padMode == PadMode.ZERO_PAD) { handleZero(wr); } else if (padMode == PadMode.REPLICATE) { handleReplicate(wr); } else if (padMode == PadMode.WRAP) { handleWrap(wr); } return wr; }
protected static ColorModel fixColorModel(CachableRed src) { ColorModel cm = src.getColorModel(); int b = src.getSampleModel().getNumBands(); int[] masks = new int[4]; switch (b) { case 1: masks[0] = 0xFF; break; case 2: masks[0] = 0x00FF; masks[3] = 0xFF00; break; case 3: masks[0] = 0xFF0000; masks[1] = 0x00FF00; masks[2] = 0x0000FF; break; case 4: masks[0] = 0x00FF0000; masks[1] = 0x0000FF00; masks[2] = 0x000000FF; masks[3] = 0xFF000000; break; default: throw new IllegalArgumentException( "GaussianBlurRed8Bit only supports one to four band images"); } ColorSpace cs = cm.getColorSpace(); return new DirectColorModel( cs, 8 * b, masks[0], masks[1], masks[2], masks[3], true, DataBuffer.TYPE_INT); }
/** * Multiply the alpha of one image with a mask image. The size of the resultant image is the * intersection of the two image bounds. If you want the end image to be the size of one or the * other please use the PadRed operator. * * @param src The image to convert to multiply the alpha of * @param alpha The mask image to multiply the alpha channel of src with. */ public MultiplyAlphaRed(CachableRed src, CachableRed alpha) { super( makeList(src, alpha), makeBounds(src, alpha), fixColorModel(src), fixSampleModel(src), src.getTileGridXOffset(), src.getTileGridYOffset(), null); }
/** * Construct an instance of TranslateRed * * @param xloc The new x coordinate of cr.getMinX(). * @param yloc The new y coordinate of cr.getMinY(). */ public TranslateRed(CachableRed cr, int xloc, int yloc) { super( cr, new Rectangle(xloc, yloc, cr.getWidth(), cr.getHeight()), cr.getColorModel(), cr.getSampleModel(), cr.getTileGridXOffset() + xloc - cr.getMinX(), cr.getTileGridYOffset() + yloc - cr.getMinY(), null); deltaX = xloc - cr.getMinX(); deltaY = yloc - cr.getMinY(); }
/** * Construct a blurred version of <tt>src</tt>, by blurring with a gaussian kernel with standard * Deviation of <tt>stdDev</tt> pixels. * * @param src The source image to blur * @param stdDevX The Standard Deviation of the Gaussian kernel in X * @param stdDevY The Standard Deviation of the Gaussian kernel in Y * @param rh Rendering hints. */ public GaussianBlurRed8Bit(CachableRed src, double stdDevX, double stdDevY, RenderingHints rh) { super(); // Remember to call super.init() this.stdDevX = stdDevX; this.stdDevY = stdDevY; this.hints = rh; xinset = surroundPixels(stdDevX, rh); yinset = surroundPixels(stdDevY, rh); Rectangle myBounds = src.getBounds(); myBounds.x += xinset; myBounds.y += yinset; myBounds.width -= 2 * xinset; myBounds.height -= 2 * yinset; if ((myBounds.width <= 0) || (myBounds.height <= 0)) { myBounds.width = 0; myBounds.height = 0; } ColorModel cm = fixColorModel(src); SampleModel sm = src.getSampleModel(); int tw = sm.getWidth(); int th = sm.getHeight(); if (tw > myBounds.width) tw = myBounds.width; if (th > myBounds.height) th = myBounds.height; sm = cm.createCompatibleSampleModel(tw, th); init( src, myBounds, cm, sm, src.getTileGridXOffset() + xinset, src.getTileGridYOffset() + yinset, null); boolean highQuality = ((hints != null) && RenderingHints.VALUE_RENDER_QUALITY.equals(hints.get(RenderingHints.KEY_RENDERING))); // System.out.println("StdDev: " + stdDevX + "x" + stdDevY); if ((xinset != 0) && ((stdDevX < 2) || highQuality)) convOp[0] = new ConvolveOp(makeQualityKernelX(xinset * 2 + 1)); else dX = (int) Math.floor(DSQRT2PI * stdDevX + 0.5f); if ((yinset != 0) && ((stdDevY < 2) || highQuality)) convOp[1] = new ConvolveOp(makeQualityKernelY(yinset * 2 + 1)); else dY = (int) Math.floor(DSQRT2PI * stdDevY + 0.5f); }
public static ColorModel fixColorModel(CachableRed src) { ColorModel cm = src.getColorModel(); if (cm.hasAlpha()) return cm; int b = src.getSampleModel().getNumBands() + 1; int[] bits = new int[b]; for (int i = 0; i < b; i++) bits[i] = 8; ColorSpace cs = cm.getColorSpace(); return new ComponentColorModel( cs, bits, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); }
/** * Construct a luminace image from src. * * @param src The image to convert to a luminance image */ public Any2LsRGBRed(CachableRed src) { super( src, src.getBounds(), fixColorModel(src), fixSampleModel(src), src.getTileGridXOffset(), src.getTileGridYOffset(), null); ColorModel srcCM = src.getColorModel(); if (srcCM == null) return; ColorSpace srcCS = srcCM.getColorSpace(); if (srcCS == ColorSpace.getInstance(ColorSpace.CS_sRGB)) srcIssRGB = true; }
public static SampleModel fixSampleModel(CachableRed src) { ColorModel cm = src.getColorModel(); SampleModel srcSM = src.getSampleModel(); if (cm.hasAlpha()) return srcSM; int w = srcSM.getWidth(); int h = srcSM.getHeight(); int b = srcSM.getNumBands() + 1; int[] offsets = new int[b]; for (int i = 0; i < b; i++) offsets[i] = i; // Really should check DataType range in srcSM... return new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, w, h, b, w * b, offsets); }
/** * Construct A Rendered Pad operation. If the pad is smaller than the original image size then * this devolves to a Crop. * * @param src The image to pad/crop * @param bounds The bounds of the result (same coord system as src). * @param padMode The pad mode to use (currently ignored). * @param hints The hints to use for drawing 'pad' area. */ public PadRed(CachableRed src, Rectangle bounds, PadMode padMode, RenderingHints hints) { super(src, bounds, src.getColorModel(), fixSampleModel(src, bounds), bounds.x, bounds.y, null); this.padMode = padMode; if (DEBUG) { System.out.println( "Src: " + src + " Bounds: " + bounds + " Off: " + src.getTileGridXOffset() + ", " + src.getTileGridYOffset()); } this.hints = hints; }
/** * This function 'fixes' the source's sample model. right now it just ensures that the sample * model isn't much larger than my width. */ protected static SampleModel fixSampleModel(CachableRed src, Rectangle bounds) { int defSz = AbstractTiledRed.getDefaultTileSize(); SampleModel sm = src.getSampleModel(); int w = sm.getWidth(); if (w < defSz) w = defSz; if (w > bounds.width) w = bounds.width; int h = sm.getHeight(); if (h < defSz) h = defSz; if (h > bounds.height) h = bounds.height; // System.out.println("Pad SMSz: " + w + "x" + h); return sm.createCompatibleSampleModel(w, h); }
/** * This function 'fixes' the source's sample model. right now it just ensures that the sample * model isn't much larger than my width. */ protected SampleModel fixSampleModel(CachableRed src, ColorModel cm, Rectangle bounds) { SampleModel sm = src.getSampleModel(); int defSz = AbstractTiledRed.getDefaultTileSize(); int w = sm.getWidth(); if (w < defSz) w = defSz; if (w > bounds.width) w = bounds.width; int h = sm.getHeight(); if (h < defSz) h = defSz; if (h > bounds.height) h = bounds.height; if ((w <= 0) || (h <= 0)) { w = 1; h = 1; } return cm.createCompatibleSampleModel(w, h); }
protected void handleReplicate(WritableRaster wr) { // Get my source. CachableRed src = (CachableRed) getSources().get(0); Rectangle srcR = src.getBounds(); Rectangle wrR = wr.getBounds(); int x = wrR.x; int y = wrR.y; int width = wrR.width; int height = wrR.height; Rectangle r; { // Calculate an intersection that makes some sense // even when the rects don't really intersect // (The x and y ranges will be correct if they // overlap in one dimension even if they don't // intersect in both dimensions). int minX = (srcR.x > x) ? srcR.x : x; int maxX = (((srcR.x + srcR.width - 1) < (x + width - 1)) ? (srcR.x + srcR.width - 1) : (x + width - 1)); int minY = (srcR.y > y) ? srcR.y : y; int maxY = (((srcR.y + srcR.height - 1) < (y + height - 1)) ? (srcR.y + srcR.height - 1) : (y + height - 1)); int x0 = minX; int w = maxX - minX + 1; int y0 = minY; int h = maxY - minY + 1; if (w < 0) { x0 = 0; w = 0; } if (h < 0) { y0 = 0; h = 0; } r = new Rectangle(x0, y0, w, h); } // We split the edge drawing up into four parts. // // +-----------------------------+ // | 3 | 1 | 4 | // | +---------------+ | // / / / / // / / src / / // / / / / // / / / / // | +---------------+ | // | | 2 | | // +-----------------------------+ // // Draw #1 if (y < srcR.y) { int repW = r.width; int repX = r.x; int wrX = r.x; int wrY = y; if (x + width - 1 <= srcR.x) { // we are off to the left of src. so set repX to the // left most pixel... repW = 1; repX = srcR.x; wrX = x + width - 1; } else if (x >= srcR.x + srcR.width) { // we are off to the right of src, so set repX to // the right most pixel repW = 1; repX = srcR.x + srcR.width - 1; wrX = x; } // This fills the top row of section 1 from src (we // go to src instead of getting the data from wr because // in some cases wr will be completely off the top of src WritableRaster wr1 = wr.createWritableChild(wrX, wrY, repW, 1, repX, srcR.y, null); src.copyData(wr1); wrY++; int endY = srcR.y; if (y + height < endY) endY = y + height; if (wrY < endY) { int[] pixels = wr.getPixels(wrX, wrY - 1, repW, 1, (int[]) null); while (wrY < srcR.y) { wr.setPixels(wrX, wrY, repW, 1, pixels); wrY++; } } } // Draw #2 if ((y + height) > (srcR.y + srcR.height)) { int repW = r.width; int repX = r.x; int repY = srcR.y + srcR.height - 1; int wrX = r.x; int wrY = srcR.y + srcR.height; if (wrY < y) wrY = y; if (x + width <= srcR.x) { // we are off to the left of src. so set repX to the // left most pixel... repW = 1; repX = srcR.x; wrX = x + width - 1; } else if (x >= srcR.x + srcR.width) { // we are off to the right of src, so set repX to // the right most pixel repW = 1; repX = srcR.x + srcR.width - 1; wrX = x; } if (DEBUG) { System.out.println("wr: " + wr.getBounds()); System.out.println("req: [" + wrX + ", " + wrY + ", " + repW + ", 1]"); } // First we get the top row of pixels from src. (we // go to src instead of getting the data from wr because // in some cases wr will be completely off the bottom of src). WritableRaster wr1 = wr.createWritableChild(wrX, wrY, repW, 1, repX, repY, null); // This fills the top row of section 2 from src src.copyData(wr1); wrY++; int endY = y + height; if (wrY < endY) { // This fills the rest of section 2 from the first line. int[] pixels = wr.getPixels(wrX, wrY - 1, repW, 1, (int[]) null); while (wrY < endY) { wr.setPixels(wrX, wrY, repW, 1, pixels); wrY++; } } } // Draw #3 if (x < srcR.x) { // We are garunteed that we have a column of pixels down // the edge of 1 and src. We simply replicate this column // out to the edges of 2. int wrX = srcR.x; if (x + width <= srcR.x) { wrX = x + width - 1; } int xLoc = x; int[] pixels = wr.getPixels(wrX, y, 1, height, (int[]) null); while (xLoc < wrX) { wr.setPixels(xLoc, y, 1, height, pixels); xLoc++; } } // Draw #4 if (x + width > srcR.x + srcR.width) { // We are garunteed that we have a column of pixels down // the edge of 1 and src. We simply replicate this column // out to the edges of 3. int wrX = srcR.x + srcR.width - 1; if (x >= srcR.x + srcR.width) { wrX = x; } int xLoc = wrX + 1; int endX = x + width - 1; int[] pixels = wr.getPixels(wrX, y, 1, height, (int[]) null); while (xLoc < endX) { wr.setPixels(xLoc, y, 1, height, pixels); xLoc++; } } }
public void genRect(WritableRaster wr) { if (me2src == null) return; Rectangle srcR = me2src.createTransformedShape(wr.getBounds()).getBounds(); // System.out.println("Affine wrR: " + wr.getBounds()); // System.out.println("Affine srcR: " + srcR); // Outset by two pixels so we get context for interpolation... srcR.setBounds(srcR.x - 1, srcR.y - 1, srcR.width + 2, srcR.height + 2); // Don't try and get data from src that it doesn't have... CachableRed src = (CachableRed) getSources().get(0); // Raster srcRas = src.getData(srcR); if (!srcR.intersects(src.getBounds())) return; Raster srcRas = src.getData(srcR.intersection(src.getBounds())); if (srcRas == null) return; // This works around the problem that the buffered ops // completely ignore the coords of the Rasters passed in. AffineTransform aff = (AffineTransform) src2me.clone(); // Translate what is at 0,0 (which will be what our current // minX/Y is) to our current minX,minY. aff.concatenate(AffineTransform.getTranslateInstance(srcRas.getMinX(), srcRas.getMinY())); Point2D srcPt = new Point2D.Float(wr.getMinX(), wr.getMinY()); srcPt = me2src.transform(srcPt, null); Point2D destPt = new Point2D.Double(srcPt.getX() - srcRas.getMinX(), srcPt.getY() - srcRas.getMinY()); destPt = aff.transform(destPt, null); // Translate what will be at minX,minY to zero, zero // which where java2d will think the real minX,minY is. aff.preConcatenate(AffineTransform.getTranslateInstance(-destPt.getX(), -destPt.getY())); AffineTransformOp op = new AffineTransformOp(aff, hints); BufferedImage srcBI, myBI; ColorModel srcCM = src.getColorModel(); ColorModel myCM = getColorModel(); WritableRaster srcWR = (WritableRaster) srcRas; // If the output buffer is not premultiplied in certain cases // it fails to properly divide out the Alpha (it always does // the affine on premultiplied data). We help it out by // premultiplying for it. srcCM = GraphicsUtil.coerceData(srcWR, srcCM, true); srcBI = new BufferedImage( srcCM, srcWR.createWritableTranslatedChild(0, 0), srcCM.isAlphaPremultiplied(), null); myBI = new BufferedImage( myCM, wr.createWritableTranslatedChild(0, 0), myCM.isAlphaPremultiplied(), null); op.filter(srcBI, myBI); // if ((count % 40) == 0) { // org.apache.batik.ImageDisplay.showImage("Src: " , srcBI); // org.apache.batik.ImageDisplay.showImage("Dst: " , myBI); // } // count++; }
public static Rectangle makeBounds(CachableRed src1, CachableRed src2) { Rectangle r1 = src1.getBounds(); Rectangle r2 = src2.getBounds(); return r1.intersection(r2); }
public WritableRaster copyData(WritableRaster wr) { // Get my source. CachableRed srcRed = (CachableRed) getSources().get(0); CachableRed alphaRed = (CachableRed) getSources().get(1); if (is_INT_PACK_BYTE_COMP(srcRed.getSampleModel(), alphaRed.getSampleModel())) return INT_PACK_BYTE_COMP_Impl(wr); ColorModel cm = srcRed.getColorModel(); if (cm.hasAlpha()) { // Already has alpha channel so we use it. srcRed.copyData(wr); Rectangle rgn = wr.getBounds(); if (rgn.intersects(alphaRed.getBounds())) rgn = rgn.intersection(alphaRed.getBounds()); else return wr; int[] wrData = null; int[] alphaData = null; Raster r = alphaRed.getData(rgn); int w = rgn.width; final int bands = wr.getSampleModel().getNumBands(); if (cm.isAlphaPremultiplied()) { for (int y = rgn.y; y < rgn.y + rgn.height; y++) { wrData = wr.getPixels(rgn.x, y, w, 1, wrData); alphaData = r.getSamples(rgn.x, y, w, 1, 0, alphaData); int i = 0, a, b; // 4 is the most common case. // 2 is probably next most common... switch (bands) { case 2: for (int x = 0; x < alphaData.length; x++) { a = alphaData[x] & 0xFF; wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; } break; case 4: for (int x = 0; x < alphaData.length; x++) { a = alphaData[x] & 0xFF; wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; } break; default: for (int x = 0; x < alphaData.length; x++) { a = alphaData[x] & 0xFF; for (b = 0; b < bands; b++) { wrData[i] = ((wrData[i] & 0xFF) * a) >> 8; ++i; } } } wr.setPixels(rgn.x, y, w, 1, wrData); } } else { int b = srcRed.getSampleModel().getNumBands() - 1; for (int y = rgn.y; y < rgn.y + rgn.height; y++) { wrData = wr.getSamples(rgn.x, y, w, 1, b, wrData); alphaData = r.getSamples(rgn.x, y, w, 1, 0, alphaData); for (int i = 0; i < wrData.length; i++) { wrData[i] = ((wrData[i] & 0xFF) * (alphaData[i] & 0xFF)) >> 8; } wr.setSamples(rgn.x, y, w, 1, b, wrData); } } return wr; } // No alpha in source, so we hide the alpha channel in wr and // have our source fill wr with color info... int[] bands = new int[wr.getNumBands() - 1]; for (int i = 0; i < bands.length; i++) bands[i] = i; WritableRaster subWr; subWr = wr.createWritableChild( wr.getMinX(), wr.getMinY(), wr.getWidth(), wr.getHeight(), wr.getMinX(), wr.getMinY(), bands); srcRed.copyData(subWr); Rectangle rgn = wr.getBounds(); rgn = rgn.intersection(alphaRed.getBounds()); bands = new int[] {wr.getNumBands() - 1}; subWr = wr.createWritableChild(rgn.x, rgn.y, rgn.width, rgn.height, rgn.x, rgn.y, bands); alphaRed.copyData(subWr); return wr; }
public WritableRaster copyData(WritableRaster wr) { // Get my source. CachableRed src = (CachableRed) getSources().get(0); ColorModel srcCM = src.getColorModel(); SampleModel srcSM = src.getSampleModel(); // Fast case, SRGB source, INT Pack writable raster... if (srcIssRGB && Any2sRGBRed.is_INT_PACK_COMP(wr.getSampleModel())) { src.copyData(wr); if (srcCM.hasAlpha()) GraphicsUtil.coerceData(wr, srcCM, false); Any2sRGBRed.applyLut_INT(wr, sRGBToLsRGBLut); return wr; } if (srcCM == null) { // We don't really know much about this source, let's // guess based on the number of bands... float[][] matrix = null; switch (srcSM.getNumBands()) { case 1: matrix = new float[1][3]; matrix[0][0] = 1; // Red matrix[0][1] = 1; // Grn matrix[0][2] = 1; // Blu break; case 2: matrix = new float[2][4]; matrix[0][0] = 1; // Red matrix[0][1] = 1; // Grn matrix[0][2] = 1; // Blu matrix[1][3] = 1; // Alpha break; case 3: matrix = new float[3][3]; matrix[0][0] = 1; // Red matrix[1][1] = 1; // Grn matrix[2][2] = 1; // Blu break; default: matrix = new float[srcSM.getNumBands()][4]; matrix[0][0] = 1; // Red matrix[1][1] = 1; // Grn matrix[2][2] = 1; // Blu matrix[3][3] = 1; // Alpha break; } Raster srcRas = src.getData(wr.getBounds()); BandCombineOp op = new BandCombineOp(matrix, null); op.filter(srcRas, wr); } else { ColorModel dstCM = getColorModel(); BufferedImage dstBI; if (!dstCM.hasAlpha()) { // No alpha ao we don't have to work around the bug // in the color convert op. dstBI = new BufferedImage( dstCM, wr.createWritableTranslatedChild(0, 0), dstCM.isAlphaPremultiplied(), null); } else { // All this nonsense is to work around the fact that // the Color convert op doesn't properly copy the // Alpha from src to dst. SinglePixelPackedSampleModel dstSM; dstSM = (SinglePixelPackedSampleModel) wr.getSampleModel(); int[] masks = dstSM.getBitMasks(); SampleModel dstSMNoA = new SinglePixelPackedSampleModel( dstSM.getDataType(), dstSM.getWidth(), dstSM.getHeight(), dstSM.getScanlineStride(), new int[] {masks[0], masks[1], masks[2]}); ColorModel dstCMNoA = GraphicsUtil.Linear_sRGB; WritableRaster dstWr; dstWr = Raster.createWritableRaster(dstSMNoA, wr.getDataBuffer(), new Point(0, 0)); dstWr = dstWr.createWritableChild( wr.getMinX() - wr.getSampleModelTranslateX(), wr.getMinY() - wr.getSampleModelTranslateY(), wr.getWidth(), wr.getHeight(), 0, 0, null); dstBI = new BufferedImage(dstCMNoA, dstWr, false, null); } // Divide out alpha if we have it. We need to do this since // the color convert may not be a linear operation which may // lead to out of range values. ColorModel srcBICM = srcCM; WritableRaster srcWr; if ((srcCM.hasAlpha() == true) && (srcCM.isAlphaPremultiplied() != false)) { Rectangle wrR = wr.getBounds(); SampleModel sm = srcCM.createCompatibleSampleModel(wrR.width, wrR.height); srcWr = Raster.createWritableRaster(sm, new Point(wrR.x, wrR.y)); src.copyData(srcWr); srcBICM = GraphicsUtil.coerceData(srcWr, srcCM, false); } else { Raster srcRas = src.getData(wr.getBounds()); srcWr = GraphicsUtil.makeRasterWritable(srcRas); } BufferedImage srcBI; srcBI = new BufferedImage(srcBICM, srcWr.createWritableTranslatedChild(0, 0), false, null); /* * System.out.println("src: " + srcBI.getWidth() + "x" + * srcBI.getHeight()); * System.out.println("dst: " + dstBI.getWidth() + "x" + * dstBI.getHeight()); */ ColorConvertOp op = new ColorConvertOp(null); op.filter(srcBI, dstBI); if (dstCM.hasAlpha()) copyBand( srcWr, srcSM.getNumBands() - 1, wr, getSampleModel().getNumBands() - 1); } return wr; }
public WritableRaster copyData(WritableRaster wr) { // Get my source. CachableRed src = (CachableRed) getSources().get(0); Rectangle r = wr.getBounds(); r.x -= xinset; r.y -= yinset; r.width += 2 * xinset; r.height += 2 * yinset; // System.out.println("Gaussian GenR: " + wr); // System.out.println("SrcReq: " + r); ColorModel srcCM = src.getColorModel(); WritableRaster tmpR1 = null, tmpR2 = null; tmpR1 = srcCM.createCompatibleWritableRaster(r.width, r.height); { WritableRaster fill; fill = tmpR1.createWritableTranslatedChild(r.x, r.y); src.copyData(fill); } if (srcCM.hasAlpha() && !srcCM.isAlphaPremultiplied()) GraphicsUtil.coerceData(tmpR1, srcCM, true); // For the blur box approx we can use dest as our intermediate // otherwise we let it default to null which means we create a new // one... // this lets the Vertical conv know how much is junk, so it // doesn't bother to convolve the top and bottom edges int skipX; // long t1 = System.currentTimeMillis(); if (xinset == 0) { skipX = 0; } else if (convOp[0] != null) { tmpR2 = getColorModel().createCompatibleWritableRaster(r.width, r.height); tmpR2 = convOp[0].filter(tmpR1, tmpR2); skipX = convOp[0].getKernel().getXOrigin(); // Swap them... WritableRaster tmp = tmpR1; tmpR1 = tmpR2; tmpR2 = tmp; } else { if ((dX & 0x01) == 0) { tmpR1 = boxFilterH(tmpR1, tmpR1, 0, 0, dX, dX / 2); tmpR1 = boxFilterH(tmpR1, tmpR1, dX / 2, 0, dX, dX / 2 - 1); tmpR1 = boxFilterH(tmpR1, tmpR1, dX - 1, 0, dX + 1, dX / 2); skipX = dX - 1 + dX / 2; } else { tmpR1 = boxFilterH(tmpR1, tmpR1, 0, 0, dX, dX / 2); tmpR1 = boxFilterH(tmpR1, tmpR1, dX / 2, 0, dX, dX / 2); tmpR1 = boxFilterH(tmpR1, tmpR1, dX - 2, 0, dX, dX / 2); skipX = dX - 2 + dX / 2; } } if (yinset == 0) { tmpR2 = tmpR1; } else if (convOp[1] != null) { if (tmpR2 == null) { tmpR2 = getColorModel().createCompatibleWritableRaster(r.width, r.height); } tmpR2 = convOp[1].filter(tmpR1, tmpR2); } else { if ((dY & 0x01) == 0) { tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, 0, dY, dY / 2); tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY / 2, dY, dY / 2 - 1); tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY - 1, dY + 1, dY / 2); } else { tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, 0, dY, dY / 2); tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY / 2, dY, dY / 2); tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY - 2, dY, dY / 2); } tmpR2 = tmpR1; } // long t2 = System.currentTimeMillis(); // System.out.println("Time: " + (t2-t1) + // (((convOp[0] != null) || (convOp[1] != null))? // " ConvOp":"")); // System.out.println("Rasters WR :" + wr.getBounds()); // System.out.println(" tmp:" + tmpR2.getBounds()); // System.out.println(" bounds:" + getBounds()); // System.out.println(" skipX:" + skipX + // " dx:" + dX + " Dy: " + dY); tmpR2 = tmpR2.createWritableTranslatedChild(r.x, r.y); GraphicsUtil.copyData(tmpR2, wr); return wr; }
public WritableRaster INT_PACK_BYTE_COMP_Impl(WritableRaster wr) { // Get my source. CachableRed srcRed = (CachableRed) getSources().get(0); CachableRed alphaRed = (CachableRed) getSources().get(1); // Already has alpha channel so we use it. srcRed.copyData(wr); Rectangle rgn = wr.getBounds(); rgn = rgn.intersection(alphaRed.getBounds()); Raster r = alphaRed.getData(rgn); ComponentSampleModel csm; csm = (ComponentSampleModel) r.getSampleModel(); final int alpScanStride = csm.getScanlineStride(); DataBufferByte alpDB = (DataBufferByte) r.getDataBuffer(); final int alpBase = (alpDB.getOffset() + csm.getOffset( rgn.x - r.getSampleModelTranslateX(), rgn.y - r.getSampleModelTranslateY())); // Access the pixel data array final byte[] alpPixels = alpDB.getBankData()[0]; SinglePixelPackedSampleModel sppsm; sppsm = (SinglePixelPackedSampleModel) wr.getSampleModel(); final int srcScanStride = sppsm.getScanlineStride(); DataBufferInt srcDB = (DataBufferInt) wr.getDataBuffer(); final int srcBase = (srcDB.getOffset() + sppsm.getOffset( rgn.x - wr.getSampleModelTranslateX(), rgn.y - wr.getSampleModelTranslateY())); // Access the pixel data array final int[] srcPixels = srcDB.getBankData()[0]; ColorModel cm = srcRed.getColorModel(); if (cm.isAlphaPremultiplied()) { // For alpha premult we need to multiply all comps. for (int y = 0; y < rgn.height; y++) { int sp = srcBase + y * srcScanStride; int ap = alpBase + y * alpScanStride; int end = sp + rgn.width; while (sp < end) { int a = ((int) alpPixels[ap++]) & 0xFF; final int pix = srcPixels[sp]; srcPixels[sp] = ((((((pix >>> 24)) * a) & 0xFF00) << 16) | (((((pix >>> 16) & 0xFF) * a) & 0xFF00) << 8) | (((((pix >>> 8) & 0xFF) * a) & 0xFF00)) | (((((pix) & 0xFF) * a) & 0xFF00) >> 8)); sp++; } } } else { // For non-alpha premult we only need to multiply alpha. for (int y = 0; y < rgn.height; y++) { int sp = srcBase + y * srcScanStride; int ap = alpBase + y * alpScanStride; int end = sp + rgn.width; while (sp < end) { int a = ((int) alpPixels[ap++]) & 0xFF; int sa = srcPixels[sp] >>> 24; srcPixels[sp] = ((((sa * a) & 0xFF00) << 16) | srcPixels[sp] & 0x00FFFFFF); sp++; } } } return wr; }
protected void handleZero(WritableRaster wr) { // Get my source. CachableRed src = (CachableRed) getSources().get(0); Rectangle srcR = src.getBounds(); Rectangle wrR = wr.getBounds(); ZeroRecter zr = ZeroRecter.getZeroRecter(wr); // area rect (covers the area left to handle). Rectangle ar = new Rectangle(wrR.x, wrR.y, wrR.width, wrR.height); // draw rect (used for calls to zeroRect); Rectangle dr = new Rectangle(wrR.x, wrR.y, wrR.width, wrR.height); // We split the edge drawing up into four parts. // // +-----------------------------+ // | 1 | 2 | // | +---------------+------| // / / /4 / // / / / / // / / / / // / / / / // | +---------------+------| // | | 3 | // +-----------------------------+ // // We update our x,y, width, height as we go along so // we 'forget' about the parts we have already painted... // Draw #1 if (DEBUG) { System.out.println("WrR: " + wrR + " srcR: " + srcR); // g2d.setColor(new Color(255,0,0,128)); } if (ar.x < srcR.x) { int w = srcR.x - ar.x; if (w > ar.width) w = ar.width; // g2d.fillRect(x, y, w, height); dr.width = w; zr.zeroRect(dr); ar.x += w; ar.width -= w; } // Draw #2 if (DEBUG) { System.out.println( "WrR: [" + ar.x + "," + ar.y + "," + ar.width + "," + ar.height + "] s rcR: " + srcR); // g2d.setColor(new Color(0,0,255,128)); } if (ar.y < srcR.y) { int h = srcR.y - ar.y; if (h > ar.height) h = ar.height; // g2d.fillRect(x, y, width, h); dr.x = ar.x; dr.y = ar.y; dr.width = ar.width; dr.height = h; zr.zeroRect(dr); ar.y += h; ar.height -= h; } // Draw #3 if (DEBUG) { System.out.println( "WrR: [" + ar.x + "," + ar.y + "," + ar.width + "," + ar.height + "] srcR: " + srcR); // g2d.setColor(new Color(0,255,0,128)); } if (ar.y + ar.height > srcR.y + srcR.height) { int h = (ar.y + ar.height) - (srcR.y + srcR.height); if (h > ar.height) h = ar.height; int y0 = ar.y + ar.height - h; // the +/-1 cancel (?) // g2d.fillRect(x, y0, width, h); dr.x = ar.x; dr.y = y0; dr.width = ar.width; dr.height = h; zr.zeroRect(dr); ar.height -= h; } // Draw #4 if (DEBUG) { System.out.println( "WrR: [" + ar.x + "," + ar.y + "," + ar.width + "," + ar.height + "] srcR: " + srcR); // g2d.setColor(new Color(255,255,0,128)); } if (ar.x + ar.width > srcR.x + srcR.width) { int w = (ar.x + ar.width) - (srcR.x + srcR.width); if (w > ar.width) w = ar.width; int x0 = ar.x + ar.width - w; // the +/-1 cancel (?) // g2d.fillRect(x0, y, w, height); dr.x = x0; dr.y = ar.y; dr.width = w; dr.height = ar.height; zr.zeroRect(dr); ar.width -= w; } }