0001: /*
0002:
0003: Copyright 2001-2004 The Apache Software Foundation
0004:
0005: Licensed under the Apache License, Version 2.0 (the "License");
0006: you may not use this file except in compliance with the License.
0007: You may obtain a copy of the License at
0008:
0009: http://www.apache.org/licenses/LICENSE-2.0
0010:
0011: Unless required by applicable law or agreed to in writing, software
0012: distributed under the License is distributed on an "AS IS" BASIS,
0013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: See the License for the specific language governing permissions and
0015: limitations under the License.
0016:
0017: */
0018: package com.xoetrope.batik.ext.awt.image;
0019:
0020: import java.awt.Composite;
0021: import java.awt.Graphics2D;
0022: import java.awt.GraphicsConfiguration;
0023: import java.awt.GraphicsDevice;
0024: import java.awt.Point;
0025: import java.awt.Rectangle;
0026: import java.awt.RenderingHints;
0027: import java.awt.Shape;
0028: import java.awt.color.ColorSpace;
0029: import java.awt.geom.AffineTransform;
0030: import java.awt.geom.Rectangle2D;
0031: import java.awt.image.BufferedImage;
0032: import java.awt.image.ColorModel;
0033: import java.awt.image.ComponentSampleModel;
0034: import java.awt.image.DataBuffer;
0035: import java.awt.image.DataBufferByte;
0036: import java.awt.image.DataBufferInt;
0037: import java.awt.image.DataBufferShort;
0038: import java.awt.image.DataBufferUShort;
0039: import java.awt.image.DirectColorModel;
0040: import java.awt.image.Raster;
0041: import java.awt.image.RenderedImage;
0042: import java.awt.image.SampleModel;
0043: import java.awt.image.SinglePixelPackedSampleModel;
0044: import java.awt.image.WritableRaster;
0045: import java.awt.image.renderable.RenderContext;
0046: import java.awt.image.renderable.RenderableImage;
0047: import java.lang.ref.Reference;
0048: import java.lang.ref.WeakReference;
0049:
0050: //import org.apache.batik.ext.awt.RenderingHintsKeyExt;
0051: //import org.apache.batik.ext.awt.image.renderable.PaintRable;
0052: //import org.apache.batik.ext.awt.image.rendered.AffineRed;
0053: //import org.apache.batik.ext.awt.image.rendered.Any2LsRGBRed;
0054: //import org.apache.batik.ext.awt.image.rendered.Any2sRGBRed;
0055: //import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;
0056: //import org.apache.batik.ext.awt.image.rendered.CachableRed;
0057: //import org.apache.batik.ext.awt.image.rendered.FormatRed;
0058: //import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed;
0059: //import org.apache.batik.ext.awt.image.rendered.TranslateRed;
0060:
0061: /**
0062: * Set of utility methods for Graphics.
0063: * These generally bypass broken methods in Java2D or provide tweaked
0064: * implementations.
0065: *
0066: * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
0067: * @version $Id: GraphicsUtil.java,v 1.2 2006/08/31 09:28:43 val Exp $
0068: */
0069: public class GraphicsUtil {
0070:
0071: public static AffineTransform IDENTITY = new AffineTransform();
0072:
0073: // /**
0074: // * Draws <tt>ri</tt> into <tt>g2d</tt>. It does this be
0075: // * requesting tiles from <tt>ri</tt> and drawing them individually
0076: // * in <tt>g2d</tt> it also takes care of some colorspace and alpha
0077: // * issues.
0078: // * @param g2d The Graphics2D to draw into.
0079: // * @param ri The image to be drawn.
0080: // */
0081: // public static void drawImage(Graphics2D g2d,
0082: // RenderedImage ri) {
0083: // drawImage(g2d, wrap(ri));
0084: // }
0085: //
0086: // /**
0087: // * Draws <tt>cr</tt> into <tt>g2d</tt>. It does this be
0088: // * requesting tiles from <tt>ri</tt> and drawing them individually
0089: // * in <tt>g2d</tt> it also takes care of some colorspace and alpha
0090: // * issues.
0091: // * @param g2d The Graphics2D to draw into.
0092: // * @param cr The image to be drawn.
0093: // */
0094: // public static void drawImage(Graphics2D g2d,
0095: // CachableRed cr) {
0096: //
0097: // // System.out.println("DrawImage G: " + g2d);
0098: //
0099: // AffineTransform at = null;
0100: // while (true) {
0101: // if (cr instanceof AffineRed) {
0102: // AffineRed ar = (AffineRed)cr;
0103: // if (at == null)
0104: // at = ar.getTransform();
0105: // else
0106: // at.concatenate(ar.getTransform());
0107: // cr = ar.getSource();
0108: // continue;
0109: // } else if (cr instanceof TranslateRed) {
0110: // TranslateRed tr = (TranslateRed)cr;
0111: // // System.out.println("testing Translate");
0112: // int dx = tr.getDeltaX();
0113: // int dy = tr.getDeltaY();
0114: // if (at == null)
0115: // at = AffineTransform.getTranslateInstance(dx, dy);
0116: // else
0117: // at.translate(dx, dy);
0118: // cr = tr.getSource();
0119: // continue;
0120: // }
0121: // break;
0122: // }
0123: // AffineTransform g2dAt = g2d.getTransform();
0124: // if ((at == null) || (at.isIdentity()))
0125: // at = g2dAt;
0126: // else
0127: // at.preConcatenate(g2dAt);
0128: //
0129: // ColorModel srcCM = cr.getColorModel();
0130: // ColorSpace g2dCS = getDestinationColorSpace(g2d);
0131: // ColorModel g2dCM = getDestinationColorModel(g2d);
0132: // if (g2dCS == null)
0133: // // Assume device is sRGB
0134: // g2dCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0135: // ColorModel drawCM = g2dCM;
0136: // if ((g2dCM == null) || !g2dCM.hasAlpha()) {
0137: // // If we can't find out about our device or the device
0138: // // does not support alpha just use SRGB unpremultiplied
0139: // // (Just because this seems to work for us).
0140: // drawCM = sRGB_Unpre;
0141: // }
0142: //
0143: // if (cr instanceof BufferedImageCachableRed) {
0144: // // There is a huge win if we can use the BI directly here.
0145: // // This results in something like a 10x performance gain
0146: // // for images, the best thing is this is the common case.
0147: // if (g2dCS.equals(srcCM.getColorSpace()) &&
0148: // drawCM.equals(srcCM)) {
0149: // // System.err.println("Fast Case");
0150: // g2d.setTransform(at);
0151: // BufferedImageCachableRed bicr;
0152: // bicr = (BufferedImageCachableRed)cr;
0153: // g2d.drawImage(bicr.getBufferedImage(),
0154: // bicr.getMinX(), bicr.getMinY(), null);
0155: // g2d.setTransform(g2dAt);
0156: // return;
0157: // }
0158: // }
0159: //
0160: // // Scaling down so do it before color conversion.
0161: // double determinant = at.getDeterminant();
0162: // if (!at.isIdentity() && (determinant <= 1.0)) {
0163: // if (at.getType() != AffineTransform.TYPE_TRANSLATION)
0164: // cr = new AffineRed(cr, at, g2d.getRenderingHints());
0165: // else {
0166: // int xloc = cr.getMinX() + (int)at.getTranslateX();
0167: // int yloc = cr.getMinY() + (int)at.getTranslateY();
0168: // cr = new TranslateRed(cr, xloc, yloc);
0169: // }
0170: // }
0171: //
0172: // if (g2dCS != srcCM.getColorSpace()) {
0173: // // System.out.println("srcCS: " + srcCM.getColorSpace());
0174: // // System.out.println("g2dCS: " + g2dCS);
0175: // // System.out.println("sRGB: " +
0176: // // ColorSpace.getInstance(ColorSpace.CS_sRGB));
0177: // // System.out.println("LsRGB: " +
0178: // // ColorSpace.getInstance
0179: // // (ColorSpace.CS_LINEAR_RGB));
0180: // if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_sRGB))
0181: // cr = convertTosRGB(cr);
0182: // else if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
0183: // cr = convertToLsRGB(cr);
0184: // }
0185: // srcCM = cr.getColorModel();
0186: // if (!drawCM.equals(srcCM))
0187: // cr = FormatRed.construct(cr, drawCM);
0188: //
0189: // // Scaling up so do it after color conversion.
0190: // if (!at.isIdentity() && (determinant > 1.0))
0191: // cr = new AffineRed(cr, at, g2d.getRenderingHints());
0192: //
0193: // // Now CR is in device space, so clear the g2d transform.
0194: // g2d.setTransform(IDENTITY);
0195: //
0196: // // Ugly Hack alert. This Makes it use our SrcOver implementation
0197: // // Which doesn't seem to have as many bugs as the JDK one when
0198: // // going between different src's and destinations (of course it's
0199: // // also a lot slower).
0200: // Composite g2dComposite = g2d.getComposite();
0201: // if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) ==
0202: // RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING) {
0203: // if (SVGComposite.OVER.equals(g2dComposite)) {
0204: // g2d.setComposite(SVGComposite.OVER);
0205: // }
0206: // }
0207: // Rectangle crR = cr.getBounds();
0208: // Shape clip = g2d.getClip();
0209: //
0210: // try {
0211: // Rectangle clipR;
0212: // if (clip == null) {
0213: // clip = crR;
0214: // clipR = crR;
0215: // } else {
0216: // clipR = clip.getBounds();
0217: //
0218: // if (clipR.intersects(crR) == false)
0219: // return; // Nothing to draw...
0220: // clipR = clipR.intersection(crR);
0221: // }
0222: //
0223: // Rectangle gcR = getDestinationBounds(g2d);
0224: // // System.out.println("ClipRects: " + clipR + " -> " + gcR);
0225: // if (gcR != null) {
0226: // if (clipR.intersects(gcR) == false)
0227: // return; // Nothing to draw...
0228: // clipR = clipR.intersection(gcR);
0229: // }
0230: //
0231: // // System.out.println("Starting Draw: " + cr);
0232: // // long startTime = System.currentTimeMillis();
0233: //
0234: // boolean useDrawRenderedImage = false;
0235: //
0236: // srcCM = cr.getColorModel();
0237: // SampleModel srcSM = cr.getSampleModel();
0238: // if ((srcSM.getWidth()*srcSM.getHeight()) >=
0239: // (clipR.width*clipR.height))
0240: // // if srcSM tiles are around the clip size
0241: // // then just draw the renderedImage
0242: // useDrawRenderedImage = true;
0243: //
0244: // Object atpHint = g2d.getRenderingHint
0245: // (RenderingHintsKeyExt.KEY_AVOID_TILE_PAINTING);
0246: //
0247: // if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_ON)
0248: // useDrawRenderedImage = true; //for PDF and PS transcoders
0249: //
0250: // if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_OFF)
0251: // useDrawRenderedImage = false;
0252: //
0253: //
0254: // WritableRaster wr;
0255: // if (useDrawRenderedImage) {
0256: // // This can be significantly faster but can also
0257: // // require much more memory, so we only use it when
0258: // // the clip size is smaller than the tile size.
0259: // Raster r = cr.getData(clipR);
0260: // wr = ((WritableRaster)r).createWritableChild
0261: // (clipR.x, clipR.y, clipR.width, clipR.height,
0262: // 0, 0, null);
0263: //
0264: // BufferedImage bi = new BufferedImage
0265: // (srcCM, wr, srcCM.isAlphaPremultiplied(), null);
0266: //
0267: // // Any of the drawImage calls that take an
0268: // // Affine are prone to the 'CGGStackRestore: gstack
0269: // // underflow' bug on Mac OS X. This should work
0270: // // around that problem.
0271: // g2d.drawImage(bi, clipR.x, clipR.y, null);
0272: // } else {
0273: // // Use tiles to draw image...
0274: // wr = Raster.createWritableRaster(srcSM, new Point(0,0));
0275: // BufferedImage bi = new BufferedImage
0276: // (srcCM, wr, srcCM.isAlphaPremultiplied(), null);
0277: //
0278: // int xt0 = cr.getMinTileX();
0279: // int xt1 = xt0+cr.getNumXTiles();
0280: // int yt0 = cr.getMinTileY();
0281: // int yt1 = yt0+cr.getNumYTiles();
0282: // int tw = srcSM.getWidth();
0283: // int th = srcSM.getHeight();
0284: //
0285: // Rectangle tR = new Rectangle(0,0,tw,th);
0286: // Rectangle iR = new Rectangle(0,0,0,0);
0287: //
0288: // if (false) {
0289: // System.err.println("SrcCM: " + srcCM);
0290: // System.err.println("CR: " + cr);
0291: // System.err.println("CRR: " + crR + " TG: [" +
0292: // xt0 +"," +
0293: // yt0 +"," +
0294: // xt1 +"," +
0295: // yt1 +"] Off: " +
0296: // cr.getTileGridXOffset() +"," +
0297: // cr.getTileGridYOffset());
0298: // }
0299: //
0300: // int yloc = yt0*th+cr.getTileGridYOffset();
0301: // int skip = (clipR.y-yloc)/th;
0302: // if (skip <0) skip = 0;
0303: // yt0+=skip;
0304: //
0305: // int xloc = xt0*tw+cr.getTileGridXOffset();
0306: // skip = (clipR.x-xloc)/tw;
0307: // if (skip <0) skip = 0;
0308: // xt0+=skip;
0309: //
0310: // int endX = clipR.x+clipR.width-1;
0311: // int endY = clipR.y+clipR.height-1;
0312: //
0313: // if (false) {
0314: // System.out.println("clipR: " + clipR + " TG: [" +
0315: // xt0 +"," +
0316: // yt0 +"," +
0317: // xt1 +"," +
0318: // yt1 +"] Off: " +
0319: // cr.getTileGridXOffset() +"," +
0320: // cr.getTileGridYOffset());
0321: // }
0322: //
0323: //
0324: // yloc = yt0*th+cr.getTileGridYOffset();
0325: // int minX = xt0*tw+cr.getTileGridXOffset();
0326: // int xStep = tw;
0327: // xloc = minX;
0328: // for (int y=yt0; y<yt1; y++, yloc += th) {
0329: // if (yloc > endY) break;
0330: // for (int x=xt0; x<xt1; x++, xloc+=xStep) {
0331: // if ((xloc<minX) || (xloc > endX)) break;
0332: // tR.x = xloc;
0333: // tR.y = yloc;
0334: // Rectangle2D.intersect(crR, tR, iR);
0335: //
0336: // WritableRaster twr;
0337: // twr = wr.createWritableChild(0, 0,
0338: // iR.width, iR.height,
0339: // iR.x, iR.y, null);
0340: //
0341: // // System.out.println("Generating tile: " + twr);
0342: // cr.copyData(twr);
0343: //
0344: // // Make sure we only draw the region that was written.
0345: // BufferedImage subBI;
0346: // subBI = bi.getSubimage(0, 0, iR.width, iR.height);
0347: //
0348: // if (false) {
0349: // System.out.println("Drawing: " + tR);
0350: // System.out.println("IR: " + iR);
0351: // }
0352: //
0353: // // For some reason using the transform version
0354: // // causes a gStackUnderflow error but if I just
0355: // // use the drawImage with an x & y it works.
0356: // g2d.drawImage(subBI, iR.x, iR.y, null);
0357: // // AffineTransform trans
0358: // // = AffineTransform.getTranslateInstance(iR.x, iR.y);
0359: // // g2d.drawImage(subBI, trans, null);
0360: //
0361: // // String label = "sub [" + x + ", " + y + "]: ";
0362: // // org.ImageDisplay.showImage
0363: // // (label, subBI);
0364: // }
0365: // xStep = -xStep; // Reverse directions.
0366: // xloc += xStep; // Get back in bounds.
0367: // }
0368: // }
0369: // // long endTime = System.currentTimeMillis();
0370: // // System.out.println("Time: " + (endTime-startTime));
0371: //
0372: //
0373: // } finally {
0374: // g2d.setTransform(g2dAt);
0375: // g2d.setComposite(g2dComposite);
0376: // }
0377: //
0378: // // System.out.println("Finished Draw");
0379: // }
0380: //
0381: //
0382: // /**
0383: // * Draws a <tt>Filter</tt> (<tt>RenderableImage</tt>) into a
0384: // * Graphics 2D after taking into account a particular
0385: // * <tt>RenderContext</tt>.<p>
0386: // *
0387: // * This method also attempts to unwind the rendering chain a bit.
0388: // * So it knows about certain operations (like affine, pad,
0389: // * composite), rather than applying each of these operations in
0390: // * turn it accounts for there affects through modifications to the
0391: // * Graphics2D. This avoids generating lots of intermediate images.
0392: // *
0393: // * @param g2d The Graphics to draw into.
0394: // * @param filter The filter to draw
0395: // * @param rc The render context that controls the drawing operation.
0396: // */
0397: // public static void drawImage(Graphics2D g2d,
0398: // RenderableImage filter,
0399: // RenderContext rc) {
0400: //
0401: // AffineTransform origDev = g2d.getTransform();
0402: // Shape origClip = g2d.getClip();
0403: // RenderingHints origRH = g2d.getRenderingHints();
0404: //
0405: // Shape clip = rc.getAreaOfInterest();
0406: // if (clip != null)
0407: // g2d.clip(clip);
0408: // g2d.transform(rc.getTransform());
0409: // g2d.setRenderingHints(rc.getRenderingHints());
0410: //
0411: // drawImage(g2d, filter);
0412: //
0413: // g2d.setTransform(origDev);
0414: // g2d.setClip(origClip);
0415: // g2d.setRenderingHints(origRH);
0416: // }
0417: //
0418: // /**
0419: // * Draws a <tt>Filter</tt> (<tt>RenderableImage</tt>) into a
0420: // * Graphics 2D.<p>
0421: // *
0422: // * This method also attempts to unwind the rendering chain a bit.
0423: // * So it knows about certain operations (like affine, pad,
0424: // * composite), rather than applying each of these operations in
0425: // * turn it accounts for there affects through modifications to the
0426: // * Graphics2D. This avoids generating lots of intermediate images.
0427: // *
0428: // * @param g2d The Graphics to draw into.
0429: // * @param filter The filter to draw
0430: // */
0431: // public static void drawImage(Graphics2D g2d,
0432: // RenderableImage filter) {
0433: // if (filter instanceof PaintRable) {
0434: // PaintRable pr = (PaintRable)filter;
0435: // if (pr.paintRable(g2d))
0436: // // paintRable succeeded so we are done...
0437: // return;
0438: // }
0439: //
0440: // // Get our sources image...
0441: // // System.out.println("UnOpt: " + filter);
0442: // AffineTransform at = g2d.getTransform();
0443: // RenderedImage ri = filter.createRendering
0444: // (new RenderContext(at, g2d.getClip(), g2d.getRenderingHints()));
0445: //
0446: // if (ri == null)
0447: // return;
0448: //
0449: // g2d.setTransform(IDENTITY);
0450: // drawImage(g2d, GraphicsUtil.wrap(ri));
0451: // g2d.setTransform(at);
0452: // }
0453: //
0454: // /**
0455: // * This is a wrapper around the system's
0456: // * BufferedImage.createGraphics that arranges for bi to be stored
0457: // * in a Rendering hint in the returned Graphics2D.
0458: // * This allows for accurate determination of the 'devices' size,
0459: // * and colorspace.
0460: //
0461: // * @param bi The BufferedImage that the returned Graphics should
0462: // * draw into.
0463: // * @return A Graphics2D that draws into BufferedImage with <tt>bi</tt>
0464: // * stored in a rendering hint.
0465: // */
0466: // public static Graphics2D createGraphics(BufferedImage bi,
0467: // RenderingHints hints) {
0468: // Graphics2D g2d = bi.createGraphics();
0469: // if (hints != null)
0470: // g2d.addRenderingHints(hints);
0471: // g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
0472: // new WeakReference(bi));
0473: // g2d.clip(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
0474: // return g2d;
0475: // }
0476: //
0477: //
0478: // public static Graphics2D createGraphics(BufferedImage bi) {
0479: // Graphics2D g2d = bi.createGraphics();
0480: // g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
0481: // new WeakReference(bi));
0482: // g2d.clip(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
0483: // return g2d;
0484: // }
0485: //
0486: //
0487: // public final static boolean WARN_DESTINATION = true;
0488: //
0489: // public static BufferedImage getDestination(Graphics2D g2d) {
0490: // Object o = g2d.getRenderingHint
0491: // (RenderingHintsKeyExt.KEY_BUFFERED_IMAGE);
0492: // if (o != null)
0493: // return (BufferedImage)(((Reference)o).get());
0494: //
0495: // // Check if this is a BufferedImage G2d if so throw an error...
0496: // GraphicsConfiguration gc = g2d.getDeviceConfiguration();
0497: // GraphicsDevice gd = gc.getDevice();
0498: // if (WARN_DESTINATION &&
0499: // (gd.getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) &&
0500: // (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) !=
0501: // RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING))
0502: // // throw new IllegalArgumentException
0503: // System.out.println
0504: // ("Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint");
0505: //
0506: // return null;
0507: // }
0508: //
0509: // public static ColorModel getDestinationColorModel(Graphics2D g2d) {
0510: // BufferedImage bi = getDestination(g2d);
0511: // if (bi != null)
0512: // return bi.getColorModel();
0513: //
0514: // GraphicsConfiguration gc = g2d.getDeviceConfiguration();
0515: //
0516: // // We are going to a BufferedImage but no hint was provided
0517: // // so we can't determine the destination Color Model.
0518: // if (gc.getDevice().getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) {
0519: // if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) ==
0520: // RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING)
0521: // return sRGB_Unpre;
0522: //
0523: // // System.out.println("CM: " + gc.getColorModel());
0524: // // System.out.println("CS: " + gc.getColorModel().getColorSpace());
0525: // return null;
0526: // }
0527: //
0528: // return gc.getColorModel();
0529: // }
0530: //
0531: // public static ColorSpace getDestinationColorSpace(Graphics2D g2d) {
0532: // ColorModel cm = getDestinationColorModel(g2d);
0533: // if (cm != null) return cm.getColorSpace();
0534: //
0535: // return null;
0536: // }
0537: //
0538: // public static Rectangle getDestinationBounds(Graphics2D g2d) {
0539: // BufferedImage bi = getDestination(g2d);
0540: // if (bi != null)
0541: // return new Rectangle(0, 0, bi.getWidth(), bi.getHeight());
0542: //
0543: // GraphicsConfiguration gc = g2d.getDeviceConfiguration();
0544: //
0545: // // We are going to a BufferedImage but no hint was provided
0546: // // so we can't determine the destination bounds.
0547: // if (gc.getDevice().getType() == GraphicsDevice.TYPE_IMAGE_BUFFER)
0548: // return null;
0549: //
0550: // // This is a JDK 1.3ism, so we will just return null...
0551: // // return gc.getBounds();
0552: // return null;
0553: // }
0554: //
0555: //
0556: // /**
0557: // * Standard prebuilt Linear_sRGB color model with no alpha */
0558: // public final static ColorModel Linear_sRGB =
0559: // new DirectColorModel(ColorSpace.getInstance
0560: // (ColorSpace.CS_LINEAR_RGB), 24,
0561: // 0x00FF0000, 0x0000FF00,
0562: // 0x000000FF, 0x0, false,
0563: // DataBuffer.TYPE_INT);
0564: // /**
0565: // * Standard prebuilt Linear_sRGB color model with premultiplied alpha.
0566: // */
0567: // public final static ColorModel Linear_sRGB_Pre =
0568: // new DirectColorModel(ColorSpace.getInstance
0569: // (ColorSpace.CS_LINEAR_RGB), 32,
0570: // 0x00FF0000, 0x0000FF00,
0571: // 0x000000FF, 0xFF000000, true,
0572: // DataBuffer.TYPE_INT);
0573: // /**
0574: // * Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
0575: // */
0576: // public final static ColorModel Linear_sRGB_Unpre =
0577: // new DirectColorModel(ColorSpace.getInstance
0578: // (ColorSpace.CS_LINEAR_RGB), 32,
0579: // 0x00FF0000, 0x0000FF00,
0580: // 0x000000FF, 0xFF000000, false,
0581: // DataBuffer.TYPE_INT);
0582: //
0583: // /**
0584: // * Standard prebuilt sRGB color model with no alpha.
0585: // */
0586: // public final static ColorModel sRGB =
0587: // new DirectColorModel(ColorSpace.getInstance
0588: // (ColorSpace.CS_sRGB), 24,
0589: // 0x00FF0000, 0x0000FF00,
0590: // 0x000000FF, 0x0, false,
0591: // DataBuffer.TYPE_INT);
0592: // /**
0593: // * Standard prebuilt sRGB color model with premultiplied alpha.
0594: // */
0595: // public final static ColorModel sRGB_Pre =
0596: // new DirectColorModel(ColorSpace.getInstance
0597: // (ColorSpace.CS_sRGB), 32,
0598: // 0x00FF0000, 0x0000FF00,
0599: // 0x000000FF, 0xFF000000, true,
0600: // DataBuffer.TYPE_INT);
0601: // /**
0602: // * Standard prebuilt sRGB color model with unpremultiplied alpha.
0603: // */
0604: // public final static ColorModel sRGB_Unpre =
0605: // new DirectColorModel(ColorSpace.getInstance
0606: // (ColorSpace.CS_sRGB), 32,
0607: // 0x00FF0000, 0x0000FF00,
0608: // 0x000000FF, 0xFF000000, false,
0609: // DataBuffer.TYPE_INT);
0610: //
0611: // /**
0612: // * Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
0613: // * based on premult flag.
0614: // * @param premult True if the ColorModel should have premultiplied alpha.
0615: // * @return a ColorMdoel with Linear sRGB colorSpace and
0616: // * the alpha channel set in accordance with
0617: // * <tt>premult</tt>
0618: // */
0619: // public static ColorModel makeLinear_sRGBCM(boolean premult) {
0620: // if (premult)
0621: // return Linear_sRGB_Pre;
0622: // return Linear_sRGB_Unpre;
0623: // }
0624: //
0625: // /**
0626: // * Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
0627: // * @param width The desired width of the BufferedImage
0628: // * @param height The desired height of the BufferedImage
0629: // * @param premult The desired state of alpha premultiplied
0630: // * @return The requested BufferedImage.
0631: // */
0632: // public static BufferedImage makeLinearBufferedImage(int width,
0633: // int height,
0634: // boolean premult) {
0635: // ColorModel cm = makeLinear_sRGBCM(premult);
0636: // WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
0637: // return new BufferedImage(cm, wr, premult, null);
0638: // }
0639: //
0640: // /**
0641: // * This method will return a CacheableRed that has it's data in
0642: // * the linear sRGB colorspace. If <tt>src</tt> is already in
0643: // * linear sRGB then this method does nothing and returns <tt>src</tt>.
0644: // * Otherwise it creates a transform that will convert
0645: // * <tt>src</tt>'s output to linear sRGB and returns that CacheableRed.
0646: // *
0647: // * @param src The image to convert to linear sRGB.
0648: // * @return An equivilant image to <tt>src</tt> who's data is in
0649: // * linear sRGB.
0650: // */
0651: // public static CachableRed convertToLsRGB(CachableRed src) {
0652: // ColorModel cm = src.getColorModel();
0653: // ColorSpace cs = cm.getColorSpace();
0654: // if (cs == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
0655: // return src;
0656: //
0657: // return new Any2LsRGBRed(src);
0658: // }
0659: //
0660: // /**
0661: // * This method will return a CacheableRed that has it's data in
0662: // * the sRGB colorspace. If <tt>src</tt> is already in
0663: // * sRGB then this method does nothing and returns <tt>src</tt>.
0664: // * Otherwise it creates a transform that will convert
0665: // * <tt>src</tt>'s output to sRGB and returns that CacheableRed.
0666: // *
0667: // * @param src The image to convert to sRGB.
0668: // * @return An equivilant image to <tt>src</tt> who's data is in sRGB.
0669: // */
0670: // public static CachableRed convertTosRGB(CachableRed src) {
0671: // ColorModel cm = src.getColorModel();
0672: // ColorSpace cs = cm.getColorSpace();
0673: // if (cs == ColorSpace.getInstance(ColorSpace.CS_sRGB))
0674: // return src;
0675: //
0676: // return new Any2sRGBRed(src);
0677: // }
0678: //
0679: // /**
0680: // * Convertes any RenderedImage to a CacheableRed. <p>
0681: // * If <tt>ri</tt> is already a CacheableRed it casts it down and
0682: // * returns it.<p>
0683: // *
0684: // * In cases where <tt>ri</tt> is not already a CacheableRed it
0685: // * wraps <tt>ri</tt> with a helper class. The wrapped
0686: // * CacheableRed "Pretends" that it has no sources since it has no
0687: // * way of inteligently handling the dependency/dirty region calls
0688: // * if it exposed the source.
0689: // * @param ri The RenderedImage to convert.
0690: // * @return a CacheableRed that contains the same data as ri.
0691: // */
0692: // public static CachableRed wrap(RenderedImage ri) {
0693: // if (ri instanceof CachableRed)
0694: // return (CachableRed) ri;
0695: // if (ri instanceof BufferedImage)
0696: // return new BufferedImageCachableRed((BufferedImage)ri);
0697: // return new RenderedImageCachableRed(ri);
0698: // }
0699: //
0700: // /**
0701: // * An internal optimized version of copyData designed to work on
0702: // * Integer packed data with a SinglePixelPackedSampleModel. Only
0703: // * the region of overlap between src and dst is copied.
0704: // *
0705: // * Calls to this should be preflighted with is_INT_PACK_Data
0706: // * on both src and dest (requireAlpha can be false).
0707: // *
0708: // * @param src The source of the data
0709: // * @param dst The destination for the data.
0710: // */
0711: // public static void copyData_INT_PACK(Raster src, WritableRaster dst) {
0712: // // System.out.println("Fast copyData");
0713: // int x0 = dst.getMinX();
0714: // if (x0 < src.getMinX()) x0 = src.getMinX();
0715: //
0716: // int y0 = dst.getMinY();
0717: // if (y0 < src.getMinY()) y0 = src.getMinY();
0718: //
0719: // int x1 = dst.getMinX()+dst.getWidth()-1;
0720: // if (x1 > src.getMinX()+src.getWidth()-1)
0721: // x1 = src.getMinX()+src.getWidth()-1;
0722: //
0723: // int y1 = dst.getMinY()+dst.getHeight()-1;
0724: // if (y1 > src.getMinY()+src.getHeight()-1)
0725: // y1 = src.getMinY()+src.getHeight()-1;
0726: //
0727: // int width = x1-x0+1;
0728: // int height = y1-y0+1;
0729: //
0730: // SinglePixelPackedSampleModel srcSPPSM;
0731: // srcSPPSM = (SinglePixelPackedSampleModel)src.getSampleModel();
0732: //
0733: // final int srcScanStride = srcSPPSM.getScanlineStride();
0734: // DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer();
0735: // final int [] srcPixels = srcDB.getBankData()[0];
0736: // final int srcBase =
0737: // (srcDB.getOffset() +
0738: // srcSPPSM.getOffset(x0-src.getSampleModelTranslateX(),
0739: // y0-src.getSampleModelTranslateY()));
0740: //
0741: //
0742: // SinglePixelPackedSampleModel dstSPPSM;
0743: // dstSPPSM = (SinglePixelPackedSampleModel)dst.getSampleModel();
0744: //
0745: // final int dstScanStride = dstSPPSM.getScanlineStride();
0746: // DataBufferInt dstDB = (DataBufferInt)dst.getDataBuffer();
0747: // final int [] dstPixels = dstDB.getBankData()[0];
0748: // final int dstBase =
0749: // (dstDB.getOffset() +
0750: // dstSPPSM.getOffset(x0-dst.getSampleModelTranslateX(),
0751: // y0-dst.getSampleModelTranslateY()));
0752: //
0753: // if ((srcScanStride == dstScanStride) &&
0754: // (srcScanStride == width)) {
0755: // // System.out.println("VERY Fast copyData");
0756: //
0757: // System.arraycopy(srcPixels, srcBase, dstPixels, dstBase,
0758: // width*height);
0759: // } else if (width > 128) {
0760: // int srcSP = srcBase;
0761: // int dstSP = dstBase;
0762: // for (int y=0; y<height; y++) {
0763: // System.arraycopy(srcPixels, srcSP, dstPixels, dstSP, width);
0764: // srcSP += srcScanStride;
0765: // dstSP += dstScanStride;
0766: // }
0767: // } else {
0768: // for (int y=0; y<height; y++) {
0769: // int srcSP = srcBase+y*srcScanStride;
0770: // int dstSP = dstBase+y*dstScanStride;
0771: // for (int x=0; x<width; x++)
0772: // dstPixels[dstSP++] = srcPixels[srcSP++];
0773: // }
0774: // }
0775: // }
0776: //
0777: // public static void copyData_FALLBACK(Raster src, WritableRaster dst) {
0778: // // System.out.println("Fallback copyData");
0779: //
0780: // int x0 = dst.getMinX();
0781: // if (x0 < src.getMinX()) x0 = src.getMinX();
0782: //
0783: // int y0 = dst.getMinY();
0784: // if (y0 < src.getMinY()) y0 = src.getMinY();
0785: //
0786: // int x1 = dst.getMinX()+dst.getWidth()-1;
0787: // if (x1 > src.getMinX()+src.getWidth()-1)
0788: // x1 = src.getMinX()+src.getWidth()-1;
0789: //
0790: // int y1 = dst.getMinY()+dst.getHeight()-1;
0791: // if (y1 > src.getMinY()+src.getHeight()-1)
0792: // y1 = src.getMinY()+src.getHeight()-1;
0793: //
0794: // int width = x1-x0+1;
0795: // int [] data = null;
0796: //
0797: // for (int y = y0; y <= y1 ; y++) {
0798: // data = src.getPixels(x0,y,width,1,data);
0799: // dst.setPixels (x0,y,width,1,data);
0800: // }
0801: // }
0802: //
0803: // /**
0804: // * Copies data from one raster to another. Only the region of
0805: // * overlap between src and dst is copied. <tt>Src</tt> and
0806: // * <tt>Dst</tt> must have compatible SampleModels.
0807: // *
0808: // * @param src The source of the data
0809: // * @param dst The destination for the data.
0810: // */
0811: // public static void copyData(Raster src, WritableRaster dst) {
0812: // if (is_INT_PACK_Data(src.getSampleModel(), false) &&
0813: // is_INT_PACK_Data(dst.getSampleModel(), false)) {
0814: // copyData_INT_PACK(src, dst);
0815: // return;
0816: // }
0817: //
0818: // copyData_FALLBACK(src, dst);
0819: // }
0820: //
0821: // /**
0822: // * Creates a new raster that has a <b>copy</b> of the data in
0823: // * <tt>ras</tt>. This is highly optimized for speed. There is
0824: // * no provision for changing any aspect of the SampleModel.
0825: // *
0826: // * This method should be used when you need to change the contents
0827: // * of a Raster that you do not "own" (ie the result of a
0828: // * <tt>getData</tt> call).
0829: // * @param ras The Raster to copy.
0830: // * @return A writable copy of <tt>ras</tt>
0831: // */
0832: // public static WritableRaster copyRaster(Raster ras) {
0833: // return copyRaster(ras, ras.getMinX(), ras.getMinY());
0834: // }
0835: //
0836: //
0837: // /**
0838: // * Creates a new raster that has a <b>copy</b> of the data in
0839: // * <tt>ras</tt>. This is highly optimized for speed. There is
0840: // * no provision for changing any aspect of the SampleModel.
0841: // * However you can specify a new location for the returned raster.
0842: // *
0843: // * This method should be used when you need to change the contents
0844: // * of a Raster that you do not "own" (ie the result of a
0845: // * <tt>getData</tt> call).
0846: // *
0847: // * @param ras The Raster to copy.
0848: // *
0849: // * @param minX The x location for the upper left corner of the
0850: // * returned WritableRaster.
0851: // *
0852: // * @param minY The y location for the upper left corner of the
0853: // * returned WritableRaster.
0854: // *
0855: // * @return A writable copy of <tt>ras</tt>
0856: // */
0857: // public static WritableRaster copyRaster(Raster ras, int minX, int minY) {
0858: // WritableRaster ret = Raster.createWritableRaster
0859: // (ras.getSampleModel(),
0860: // new Point(0,0));
0861: // ret = ret.createWritableChild
0862: // (ras.getMinX()-ras.getSampleModelTranslateX(),
0863: // ras.getMinY()-ras.getSampleModelTranslateY(),
0864: // ras.getWidth(), ras.getHeight(),
0865: // minX, minY, null);
0866: //
0867: // // Use System.arraycopy to copy the data between the two...
0868: // DataBuffer srcDB = ras.getDataBuffer();
0869: // DataBuffer retDB = ret.getDataBuffer();
0870: // if (srcDB.getDataType() != retDB.getDataType()) {
0871: // throw new IllegalArgumentException
0872: // ("New DataBuffer doesn't match original");
0873: // }
0874: // int len = srcDB.getSize();
0875: // int banks = srcDB.getNumBanks();
0876: // int [] offsets = srcDB.getOffsets();
0877: // for (int b=0; b< banks; b++) {
0878: // switch (srcDB.getDataType()) {
0879: // case DataBuffer.TYPE_BYTE: {
0880: // DataBufferByte srcDBT = (DataBufferByte)srcDB;
0881: // DataBufferByte retDBT = (DataBufferByte)retDB;
0882: // System.arraycopy(srcDBT.getData(b), offsets[b],
0883: // retDBT.getData(b), offsets[b], len);
0884: // }
0885: // case DataBuffer.TYPE_INT: {
0886: // DataBufferInt srcDBT = (DataBufferInt)srcDB;
0887: // DataBufferInt retDBT = (DataBufferInt)retDB;
0888: // System.arraycopy(srcDBT.getData(b), offsets[b],
0889: // retDBT.getData(b), offsets[b], len);
0890: // }
0891: // case DataBuffer.TYPE_SHORT: {
0892: // DataBufferShort srcDBT = (DataBufferShort)srcDB;
0893: // DataBufferShort retDBT = (DataBufferShort)retDB;
0894: // System.arraycopy(srcDBT.getData(b), offsets[b],
0895: // retDBT.getData(b), offsets[b], len);
0896: // }
0897: // case DataBuffer.TYPE_USHORT: {
0898: // DataBufferUShort srcDBT = (DataBufferUShort)srcDB;
0899: // DataBufferUShort retDBT = (DataBufferUShort)retDB;
0900: // System.arraycopy(srcDBT.getData(b), offsets[b],
0901: // retDBT.getData(b), offsets[b], len);
0902: // }
0903: // }
0904: // }
0905: //
0906: // return ret;
0907: // }
0908: //
0909: // /**
0910: // * Coerces <tt>ras</tt> to be writable. The returned Raster continues to
0911: // * reference the DataBuffer from ras, so modifications to the returned
0912: // * WritableRaster will be seen in ras.<p>
0913: // *
0914: // * This method should only be used if you need a WritableRaster due to
0915: // * an interface (such as to construct a BufferedImage), but have no
0916: // * intention of modifying the contents of the returned Raster. If
0917: // * you have any doubt about other users of the data in <tt>ras</tt>,
0918: // * use copyRaster (above).
0919: // * @param ras The raster to make writable.
0920: // * @return A Writable version of ras (shares DataBuffer with
0921: // * <tt>ras</tt>).
0922: // */
0923: // public static WritableRaster makeRasterWritable(Raster ras) {
0924: // return makeRasterWritable(ras, ras.getMinX(), ras.getMinY());
0925: // }
0926: //
0927: // /**
0928: // * Coerces <tt>ras</tt> to be writable. The returned Raster continues to
0929: // * reference the DataBuffer from ras, so modifications to the returned
0930: // * WritableRaster will be seen in ras.<p>
0931: // *
0932: // * You can specify a new location for the returned WritableRaster, this
0933: // * is especially useful for constructing BufferedImages which require
0934: // * the Raster to be at (0,0).
0935: // *
0936: // * This method should only be used if you need a WritableRaster due to
0937: // * an interface (such as to construct a BufferedImage), but have no
0938: // * intention of modifying the contents of the returned Raster. If
0939: // * you have any doubt about other users of the data in <tt>ras</tt>,
0940: // * use copyRaster (above).
0941: // *
0942: // * @param ras The raster to make writable.
0943: // *
0944: // * @param minX The x location for the upper left corner of the
0945: // * returned WritableRaster.
0946: // *
0947: // * @param minY The y location for the upper left corner of the
0948: // * returned WritableRaster.
0949: // *
0950: // * @return A Writable version of <tT>ras</tt> with it's upper left
0951: // * hand coordinate set to minX, minY (shares it's DataBuffer
0952: // * with <tt>ras</tt>).
0953: // */
0954: // public static WritableRaster makeRasterWritable(Raster ras,
0955: // int minX, int minY) {
0956: // WritableRaster ret = Raster.createWritableRaster
0957: // (ras.getSampleModel(),
0958: // ras.getDataBuffer(),
0959: // new Point(0,0));
0960: // ret = ret.createWritableChild
0961: // (ras.getMinX()-ras.getSampleModelTranslateX(),
0962: // ras.getMinY()-ras.getSampleModelTranslateY(),
0963: // ras.getWidth(), ras.getHeight(),
0964: // minX, minY, null);
0965: // return ret;
0966: // }
0967: //
0968: /**
0969: * Create a new ColorModel with it's alpha premultiplied state matching
0970: * newAlphaPreMult.
0971: * @param cm The ColorModel to change the alpha premult state of.
0972: * @param newAlphaPreMult The new state of alpha premult.
0973: * @return A new colorModel that has isAlphaPremultiplied()
0974: * equal to newAlphaPreMult.
0975: */
0976: public static ColorModel coerceColorModel(ColorModel cm,
0977: boolean newAlphaPreMult) {
0978: if (cm.isAlphaPremultiplied() == newAlphaPreMult)
0979: return cm;
0980:
0981: // Easiest way to build proper colormodel for new Alpha state...
0982: // Eventually this should switch on known ColorModel types and
0983: // only fall back on this hack when the CM type is unknown.
0984: WritableRaster wr = cm.createCompatibleWritableRaster(1, 1);
0985: return cm.coerceData(wr, newAlphaPreMult);
0986: }
0987:
0988: /**
0989: * Coerces data within a bufferedImage to match newAlphaPreMult,
0990: * Note that this can not change the colormodel of bi so you
0991: *
0992: * @param wr The raster to change the state of.
0993: * @param cm The colormodel currently associated with data in wr.
0994: * @param newAlphaPreMult The desired state of alpha Premult for raster.
0995: * @return A new colormodel that matches newAlphaPreMult.
0996: */
0997: public static ColorModel coerceData(WritableRaster wr,
0998: ColorModel cm, boolean newAlphaPreMult) {
0999:
1000: // System.out.println("CoerceData: " + cm.isAlphaPremultiplied() +
1001: // " Out: " + newAlphaPreMult);
1002: if (cm.hasAlpha() == false)
1003: // Nothing to do no alpha channel
1004: return cm;
1005:
1006: if (cm.isAlphaPremultiplied() == newAlphaPreMult)
1007: // nothing to do alpha state matches...
1008: return cm;
1009:
1010: // System.out.println("CoerceData: " + wr.getSampleModel());
1011:
1012: if (newAlphaPreMult) {
1013: multiplyAlpha(wr);
1014: } else {
1015: divideAlpha(wr);
1016: }
1017:
1018: return coerceColorModel(cm, newAlphaPreMult);
1019: }
1020:
1021: public static void multiplyAlpha(WritableRaster wr) {
1022: if (is_BYTE_COMP_Data(wr.getSampleModel()))
1023: mult_BYTE_COMP_Data(wr);
1024: else if (is_INT_PACK_Data(wr.getSampleModel(), true))
1025: mult_INT_PACK_Data(wr);
1026: else {
1027: int[] pixel = null;
1028: int bands = wr.getNumBands();
1029: float norm = 1f / 255f;
1030: int x0, x1, y0, y1, a, b;
1031: float alpha;
1032: x0 = wr.getMinX();
1033: x1 = x0 + wr.getWidth();
1034: y0 = wr.getMinY();
1035: y1 = y0 + wr.getHeight();
1036: for (int y = y0; y < y1; y++)
1037: for (int x = x0; x < x1; x++) {
1038: pixel = wr.getPixel(x, y, pixel);
1039: a = pixel[bands - 1];
1040: if ((a >= 0) && (a < 255)) {
1041: alpha = a * norm;
1042: for (b = 0; b < bands - 1; b++)
1043: pixel[b] = (int) (pixel[b] * alpha + 0.5f);
1044: wr.setPixel(x, y, pixel);
1045: }
1046: }
1047: }
1048: }
1049:
1050: public static void divideAlpha(WritableRaster wr) {
1051: if (is_BYTE_COMP_Data(wr.getSampleModel()))
1052: divide_BYTE_COMP_Data(wr);
1053: else if (is_INT_PACK_Data(wr.getSampleModel(), true))
1054: divide_INT_PACK_Data(wr);
1055: else {
1056: int x0, x1, y0, y1, a, b;
1057: float ialpha;
1058: int bands = wr.getNumBands();
1059: int[] pixel = null;
1060:
1061: x0 = wr.getMinX();
1062: x1 = x0 + wr.getWidth();
1063: y0 = wr.getMinY();
1064: y1 = y0 + wr.getHeight();
1065: for (int y = y0; y < y1; y++)
1066: for (int x = x0; x < x1; x++) {
1067: pixel = wr.getPixel(x, y, pixel);
1068: a = pixel[bands - 1];
1069: if ((a > 0) && (a < 255)) {
1070: ialpha = 255 / (float) a;
1071: for (b = 0; b < bands - 1; b++)
1072: pixel[b] = (int) (pixel[b] * ialpha + 0.5f);
1073: wr.setPixel(x, y, pixel);
1074: }
1075: }
1076: }
1077: }
1078:
1079: // /**
1080: // * Copies data from one bufferedImage to another paying attention
1081: // * to the state of AlphaPreMultiplied.
1082: // *
1083: // * @param src The source
1084: // * @param dst The destination
1085: // */
1086: // public static void
1087: // copyData(BufferedImage src, BufferedImage dst) {
1088: // Rectangle srcRect = new Rectangle(0, 0,
1089: // src.getWidth(), src.getHeight());
1090: // copyData(src, srcRect, dst, new Point(0,0));
1091: // }
1092: //
1093: //
1094: // /**
1095: // * Copies data from one bufferedImage to another paying attention
1096: // * to the state of AlphaPreMultiplied.
1097: // *
1098: // * @param src The source
1099: // * @param srcRect The Rectangle of source data to be copied
1100: // * @param dst The destination
1101: // * @param destP The Place for the upper left corner of srcRect in dst.
1102: // */
1103: // public static void
1104: // copyData(BufferedImage src, Rectangle srcRect,
1105: // BufferedImage dst, Point destP) {
1106: //
1107: // /*
1108: // if (srcCS != dstCS)
1109: // throw new IllegalArgumentException
1110: // ("Images must be in the same ColorSpace in order "+
1111: // "to copy Data between them");
1112: // */
1113: // boolean srcAlpha = src.getColorModel().hasAlpha();
1114: // boolean dstAlpha = dst.getColorModel().hasAlpha();
1115: //
1116: // // System.out.println("Src has: " + srcAlpha +
1117: // // " is: " + src.isAlphaPremultiplied());
1118: // //
1119: // // System.out.println("Dst has: " + dstAlpha +
1120: // // " is: " + dst.isAlphaPremultiplied());
1121: //
1122: // if (srcAlpha == dstAlpha)
1123: // if ((srcAlpha == false) ||
1124: // (src.isAlphaPremultiplied() == dst.isAlphaPremultiplied())) {
1125: // // They match one another so just copy everything...
1126: // copyData(src.getRaster(), dst.getRaster());
1127: // return;
1128: // }
1129: //
1130: // // System.out.println("Using Slow CopyData");
1131: //
1132: // int [] pixel = null;
1133: // Raster srcR = src.getRaster();
1134: // WritableRaster dstR = dst.getRaster();
1135: // int bands = dstR.getNumBands();
1136: //
1137: // int dx = destP.x-srcRect.x;
1138: // int dy = destP.y-srcRect.y;
1139: //
1140: // int w = srcRect.width;
1141: // int x0 = srcRect.x;
1142: // int y0 = srcRect.y;
1143: // int y1 = y0+srcRect.height-1;
1144: //
1145: // if (!srcAlpha) {
1146: // // Src has no alpha dest does so set alpha to 1.0 everywhere.
1147: // // System.out.println("Add Alpha");
1148: // int [] oPix = new int[bands*w];
1149: // int out = (w*bands)-1; // The 2 skips alpha channel
1150: // while(out >= 0) {
1151: // // Fill alpha channel with 255's
1152: // oPix[out] = 255;
1153: // out -= bands;
1154: // }
1155: //
1156: // int b, in;
1157: // for (int y=y0; y<=y1; y++) {
1158: // pixel = srcR.getPixels(x0,y,w,1,pixel);
1159: // in = w*(bands-1)-1;
1160: // out = (w*bands)-2; // The 2 skips alpha channel on last pix
1161: // switch (bands) {
1162: // case 4:
1163: // while(in >= 0) {
1164: // oPix[out--] = pixel[in--];
1165: // oPix[out--] = pixel[in--];
1166: // oPix[out--] = pixel[in--];
1167: // out--;
1168: // }
1169: // break;
1170: // default:
1171: // while(in >= 0) {
1172: // for (b=0; b<bands-1; b++)
1173: // oPix[out--] = pixel[in--];
1174: // out--;
1175: // }
1176: // }
1177: // dstR.setPixels(x0+dx, y+dy, w, 1, oPix);
1178: // }
1179: // } else if (dstAlpha && dst.isAlphaPremultiplied()) {
1180: // // Src and dest have Alpha but we need to multiply it for dst.
1181: // // System.out.println("Mult Case");
1182: // int a, b, alpha, in, fpNorm = (1<<24)/255, pt5 = 1<<23;
1183: // for (int y=y0; y<=y1; y++) {
1184: // pixel = srcR.getPixels(x0,y,w,1,pixel);
1185: // in=bands*w-1;
1186: // switch (bands) {
1187: // case 4:
1188: // while(in >= 0) {
1189: // a = pixel[in];
1190: // if (a == 255)
1191: // in -= 4;
1192: // else {
1193: // in--;
1194: // alpha = fpNorm*a;
1195: // pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--;
1196: // pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--;
1197: // pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--;
1198: // }
1199: // }
1200: // break;
1201: // default:
1202: // while(in >= 0) {
1203: // a = pixel[in];
1204: // if (a == 255)
1205: // in -= bands;
1206: // else {
1207: // in--;
1208: // alpha = fpNorm*a;
1209: // for (b=0; b<bands-1; b++) {
1210: // pixel[in] = (pixel[in]*alpha+pt5)>>>24;
1211: // in--;
1212: // }
1213: // }
1214: // }
1215: // }
1216: // dstR.setPixels(x0+dx, y+dy, w, 1, pixel);
1217: // }
1218: // } else if (dstAlpha && !dst.isAlphaPremultiplied()) {
1219: // // Src and dest have Alpha but we need to divide it out for dst.
1220: // // System.out.println("Div Case");
1221: // int a, b, ialpha, in, fpNorm = 0x00FF0000, pt5 = 1<<15;
1222: // for (int y=y0; y<=y1; y++) {
1223: // pixel = srcR.getPixels(x0,y,w,1,pixel);
1224: // in=(bands*w)-1;
1225: // switch(bands) {
1226: // case 4:
1227: // while(in >= 0) {
1228: // a = pixel[in];
1229: // if ((a <= 0) || (a >= 255))
1230: // in -= 4;
1231: // else {
1232: // in--;
1233: // ialpha = fpNorm/a;
1234: // pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--;
1235: // pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--;
1236: // pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--;
1237: // }
1238: // }
1239: // break;
1240: // default:
1241: // while(in >= 0) {
1242: // a = pixel[in];
1243: // if ((a <= 0) || (a >= 255))
1244: // in -= bands;
1245: // else {
1246: // in--;
1247: // ialpha = fpNorm/a;
1248: // for (b=0; b<bands-1; b++) {
1249: // pixel[in] = (pixel[in]*ialpha+pt5)>>>16;
1250: // in--;
1251: // }
1252: // }
1253: // }
1254: // }
1255: // dstR.setPixels(x0+dx, y+dy, w, 1, pixel);
1256: // }
1257: // } else if (src.isAlphaPremultiplied()) {
1258: // int [] oPix = new int[bands*w];
1259: // // Src has alpha dest does not so unpremult and store...
1260: // // System.out.println("Remove Alpha, Div Case");
1261: // int a, b, ialpha, in, out, fpNorm = 0x00FF0000, pt5 = 1<<15;
1262: // for (int y=y0; y<=y1; y++) {
1263: // pixel = srcR.getPixels(x0,y,w,1,pixel);
1264: // in = (bands+1)*w -1;
1265: // out = (bands*w)-1;
1266: // while(in >= 0) {
1267: // a = pixel[in]; in--;
1268: // if (a > 0) {
1269: // if (a < 255) {
1270: // ialpha = fpNorm/a;
1271: // for (b=0; b<bands; b++)
1272: // oPix[out--] = (pixel[in--]*ialpha+pt5)>>>16;
1273: // } else
1274: // for (b=0; b<bands; b++)
1275: // oPix[out--] = pixel[in--];
1276: // } else {
1277: // in -= bands;
1278: // for (b=0; b<bands; b++)
1279: // oPix[out--] = 255;
1280: // }
1281: // }
1282: // dstR.setPixels(x0+dx, y+dy, w, 1, oPix);
1283: // }
1284: // } else {
1285: // // Src has unpremult alpha, dest does not have alpha,
1286: // // just copy the color channels over.
1287: // Rectangle dstRect = new Rectangle(destP.x, destP.y,
1288: // srcRect.width, srcRect.height);
1289: // for (int b=0; b<bands; b++)
1290: // copyBand(srcR, srcRect, b,
1291: // dstR, dstRect, b);
1292: // }
1293: // }
1294: //
1295: // public static void copyBand(Raster src, int srcBand,
1296: // WritableRaster dst, int dstBand) {
1297: //
1298: // Rectangle sR = src.getBounds();
1299: // Rectangle dR = dst.getBounds();
1300: // Rectangle cpR = sR.intersection(dR);
1301: //
1302: // copyBand(src, cpR, srcBand, dst, cpR, dstBand);
1303: // }
1304: //
1305: // public static void copyBand(Raster src, Rectangle sR, int sBand,
1306: // WritableRaster dst, Rectangle dR, int dBand) {
1307: // int dy = dR.y -sR.y;
1308: // int dx = dR.x -sR.x;
1309: // sR = sR.intersection(src.getBounds());
1310: // dR = dR.intersection(dst.getBounds());
1311: // int width, height;
1312: // if (dR.width < sR.width) width = dR.width;
1313: // else width = sR.width;
1314: // if (dR.height < sR.height) height = dR.height;
1315: // else height = sR.height;
1316: //
1317: // int x = sR.x+dx;
1318: // int [] samples = null;
1319: // for (int y=sR.y; y< sR.y+height; y++) {
1320: // samples = src.getSamples(sR.x, y, width, 1, sBand, samples);
1321: // dst.setSamples(x, y+dy, width, 1, dBand, samples);
1322: // }
1323: // }
1324:
1325: public static boolean is_INT_PACK_Data(SampleModel sm,
1326: boolean requireAlpha) {
1327: // Check ColorModel is of type DirectColorModel
1328: if (!(sm instanceof SinglePixelPackedSampleModel))
1329: return false;
1330:
1331: // Check transfer type
1332: if (sm.getDataType() != DataBuffer.TYPE_INT)
1333: return false;
1334:
1335: SinglePixelPackedSampleModel sppsm;
1336: sppsm = (SinglePixelPackedSampleModel) sm;
1337:
1338: int[] masks = sppsm.getBitMasks();
1339: if (masks.length == 3) {
1340: if (requireAlpha)
1341: return false;
1342: } else if (masks.length != 4)
1343: return false;
1344:
1345: if (masks[0] != 0x00ff0000)
1346: return false;
1347: if (masks[1] != 0x0000ff00)
1348: return false;
1349: if (masks[2] != 0x000000ff)
1350: return false;
1351: if ((masks.length == 4) && (masks[3] != 0xff000000))
1352: return false;
1353:
1354: return true;
1355: }
1356:
1357: public static boolean is_BYTE_COMP_Data(SampleModel sm) {
1358: // Check ColorModel is of type DirectColorModel
1359: if (!(sm instanceof ComponentSampleModel))
1360: return false;
1361:
1362: // Check transfer type
1363: if (sm.getDataType() != DataBuffer.TYPE_BYTE)
1364: return false;
1365:
1366: return true;
1367: }
1368:
1369: protected static void divide_INT_PACK_Data(WritableRaster wr) {
1370: // System.out.println("Divide Int");
1371:
1372: SinglePixelPackedSampleModel sppsm;
1373: sppsm = (SinglePixelPackedSampleModel) wr.getSampleModel();
1374:
1375: final int width = wr.getWidth();
1376:
1377: final int scanStride = sppsm.getScanlineStride();
1378: DataBufferInt db = (DataBufferInt) wr.getDataBuffer();
1379: final int base = (db.getOffset() + sppsm.getOffset(wr.getMinX()
1380: - wr.getSampleModelTranslateX(), wr.getMinY()
1381: - wr.getSampleModelTranslateY()));
1382: int pixel, a, aFP;
1383: // Access the pixel data array
1384: final int pixels[] = db.getBankData()[0];
1385: for (int y = 0; y < wr.getHeight(); y++) {
1386: int sp = base + y * scanStride;
1387: final int end = sp + width;
1388: while (sp < end) {
1389: pixel = pixels[sp];
1390: a = pixel >>> 24;
1391: if (a <= 0) {
1392: pixels[sp] = 0x00FFFFFF;
1393: } else if (a < 255) {
1394: aFP = (0x00FF0000 / a);
1395: pixels[sp] = ((a << 24)
1396: | (((((pixel & 0xFF0000) >> 16) * aFP) & 0xFF0000))
1397: | (((((pixel & 0x00FF00) >> 8) * aFP) & 0xFF0000) >> 8) | (((((pixel & 0x0000FF)) * aFP) & 0xFF0000) >> 16));
1398: }
1399: sp++;
1400: }
1401: }
1402: }
1403:
1404: protected static void mult_INT_PACK_Data(WritableRaster wr) {
1405: // System.out.println("Multiply Int: " + wr);
1406:
1407: SinglePixelPackedSampleModel sppsm;
1408: sppsm = (SinglePixelPackedSampleModel) wr.getSampleModel();
1409:
1410: final int width = wr.getWidth();
1411:
1412: final int scanStride = sppsm.getScanlineStride();
1413: DataBufferInt db = (DataBufferInt) wr.getDataBuffer();
1414: final int base = (db.getOffset() + sppsm.getOffset(wr.getMinX()
1415: - wr.getSampleModelTranslateX(), wr.getMinY()
1416: - wr.getSampleModelTranslateY()));
1417: // Access the pixel data array
1418: final int pixels[] = db.getBankData()[0];
1419: for (int y = 0; y < wr.getHeight(); y++) {
1420: int sp = base + y * scanStride;
1421: final int end = sp + width;
1422: while (sp < end) {
1423: int pixel = pixels[sp];
1424: int a = pixel >>> 24;
1425: if ((a >= 0) && (a < 255)) {
1426: pixels[sp] = ((a << 24)
1427: | ((((pixel & 0xFF0000) * a) >> 8) & 0xFF0000)
1428: | ((((pixel & 0x00FF00) * a) >> 8) & 0x00FF00) | ((((pixel & 0x0000FF) * a) >> 8) & 0x0000FF));
1429: }
1430: sp++;
1431: }
1432: }
1433: }
1434:
1435: protected static void divide_BYTE_COMP_Data(WritableRaster wr) {
1436: // System.out.println("Multiply Int: " + wr);
1437:
1438: ComponentSampleModel csm;
1439: csm = (ComponentSampleModel) wr.getSampleModel();
1440:
1441: final int width = wr.getWidth();
1442:
1443: final int scanStride = csm.getScanlineStride();
1444: final int pixStride = csm.getPixelStride();
1445: final int[] bandOff = csm.getBandOffsets();
1446:
1447: DataBufferByte db = (DataBufferByte) wr.getDataBuffer();
1448: final int base = (db.getOffset() + csm.getOffset(wr.getMinX()
1449: - wr.getSampleModelTranslateX(), wr.getMinY()
1450: - wr.getSampleModelTranslateY()));
1451:
1452: int a = 0;
1453: int aOff = bandOff[bandOff.length - 1];
1454: int bands = bandOff.length - 1;
1455: int b, i;
1456: // Access the pixel data array
1457: final byte pixels[] = db.getBankData()[0];
1458: for (int y = 0; y < wr.getHeight(); y++) {
1459: int sp = base + y * scanStride;
1460: final int end = sp + width * pixStride;
1461: while (sp < end) {
1462: a = pixels[sp + aOff] & 0xFF;
1463: if (a == 0) {
1464: for (b = 0; b < bands; b++)
1465: pixels[sp + bandOff[b]] = (byte) 0xFF;
1466: } else if (a < 255) {
1467: int aFP = (0x00FF0000 / a);
1468: for (b = 0; b < bands; b++) {
1469: i = sp + bandOff[b];
1470: pixels[i] = (byte) (((pixels[i] & 0xFF) * aFP) >>> 16);
1471: }
1472: }
1473: sp += pixStride;
1474: }
1475: }
1476: }
1477:
1478: protected static void mult_BYTE_COMP_Data(WritableRaster wr) {
1479: // System.out.println("Multiply Int: " + wr);
1480:
1481: ComponentSampleModel csm;
1482: csm = (ComponentSampleModel) wr.getSampleModel();
1483:
1484: final int width = wr.getWidth();
1485:
1486: final int scanStride = csm.getScanlineStride();
1487: final int pixStride = csm.getPixelStride();
1488: final int[] bandOff = csm.getBandOffsets();
1489:
1490: DataBufferByte db = (DataBufferByte) wr.getDataBuffer();
1491: final int base = (db.getOffset() + csm.getOffset(wr.getMinX()
1492: - wr.getSampleModelTranslateX(), wr.getMinY()
1493: - wr.getSampleModelTranslateY()));
1494:
1495: int a = 0;
1496: int aOff = bandOff[bandOff.length - 1];
1497: int bands = bandOff.length - 1;
1498: int b, i;
1499:
1500: // Access the pixel data array
1501: final byte pixels[] = db.getBankData()[0];
1502: for (int y = 0; y < wr.getHeight(); y++) {
1503: int sp = base + y * scanStride;
1504: final int end = sp + width * pixStride;
1505: while (sp < end) {
1506: a = pixels[sp + aOff] & 0xFF;
1507: if (a != 0xFF)
1508: for (b = 0; b < bands; b++) {
1509: i = sp + bandOff[b];
1510: pixels[i] = (byte) (((pixels[i] & 0xFF) * a) >> 8);
1511: }
1512: sp += pixStride;
1513: }
1514: }
1515: }
1516:
1517: ///*
1518: // This is skanky debugging code that might be useful in the future:
1519: //
1520: // if (count == 33) {
1521: // String label = "sub [" + x + ", " + y + "]: ";
1522: // org.ImageDisplay.showImage
1523: // (label, subBI);
1524: // org.ImageDisplay.printImage
1525: // (label, subBI,
1526: // new Rectangle(75-iR.x, 90-iR.y, 32, 32));
1527: //
1528: // }
1529: //
1530: //
1531: // // if ((count++ % 50) == 10)
1532: // // org.ImageDisplay.showImage("foo: ", subBI);
1533: //
1534: //
1535: // Graphics2D realG2D = g2d;
1536: // while (realG2D instanceof sun.java2d.ProxyGraphics2D) {
1537: // realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate();
1538: // }
1539: // if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) {
1540: // count++;
1541: // if (count == 34) {
1542: // RenderedImage ri;
1543: // ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg;
1544: // // g2d.setComposite(SVGComposite.OVER);
1545: // // org.ImageDisplay.showImage("Bar: " + count, cr);
1546: // org.ImageDisplay.printImage("Bar: " + count, cr,
1547: // new Rectangle(75, 90, 32, 32));
1548: //
1549: // org.ImageDisplay.showImage ("Foo: " + count, ri);
1550: // org.ImageDisplay.printImage("Foo: " + count, ri,
1551: // new Rectangle(75, 90, 32, 32));
1552: //
1553: // System.out.println("BI: " + ri);
1554: // System.out.println("BISM: " + ri.getSampleModel());
1555: // System.out.println("BICM: " + ri.getColorModel());
1556: // System.out.println("BICM class: " + ri.getColorModel().getClass());
1557: // System.out.println("BICS: " + ri.getColorModel().getColorSpace());
1558: // System.out.println
1559: // ("sRGB CS: " +
1560: // ColorSpace.getInstance(ColorSpace.CS_sRGB));
1561: // System.out.println("G2D info");
1562: // System.out.println("\tComposite: " + g2d.getComposite());
1563: // System.out.println("\tTransform" + g2d.getTransform());
1564: // java.awt.RenderingHints rh = g2d.getRenderingHints();
1565: // java.util.Set keys = rh.keySet();
1566: // java.util.Iterator iter = keys.iterator();
1567: // while (iter.hasNext()) {
1568: // Object o = iter.next();
1569: //
1570: // System.out.println("\t" + o.toString() + " -> " +
1571: // rh.get(o).toString());
1572: // }
1573: //
1574: // ri = cr;
1575: // System.out.println("RI: " + ri);
1576: // System.out.println("RISM: " + ri.getSampleModel());
1577: // System.out.println("RICM: " + ri.getColorModel());
1578: // System.out.println("RICM class: " + ri.getColorModel().getClass());
1579: // System.out.println("RICS: " + ri.getColorModel().getColorSpace());
1580: // }
1581: // }
1582: //*/
1583: //
1584: }
|