0001: /*
0002: * $RCSfile: RenderableGraphics.java,v $
0003: *
0004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Use is subject to license terms.
0007: *
0008: * $Revision: 1.1 $
0009: * $Date: 2005/02/11 04:57:20 $
0010: * $State: Exp $
0011: */
0012: package javax.media.jai;
0013:
0014: import java.awt.Color;
0015: import java.awt.Composite;
0016: import java.awt.Font;
0017: import java.awt.FontMetrics;
0018: import java.awt.Graphics;
0019: import java.awt.Graphics2D;
0020: import java.awt.GraphicsConfiguration;
0021: import java.awt.Image;
0022: import java.awt.Paint;
0023: import java.awt.PaintContext;
0024: import java.awt.Point;
0025: import java.awt.Rectangle;
0026: import java.awt.RenderingHints;
0027: import java.awt.RenderingHints.Key;
0028: import java.awt.Shape;
0029: import java.awt.Stroke;
0030: import java.awt.Toolkit;
0031: import java.awt.color.ColorSpace;
0032: import java.awt.font.FontRenderContext;
0033: import java.awt.font.GlyphVector;
0034: import java.awt.font.TextLayout;
0035: import java.awt.geom.AffineTransform;
0036: import java.awt.geom.Area;
0037: import java.awt.geom.Rectangle2D;
0038: import java.awt.image.BufferedImage;
0039: import java.awt.image.BufferedImageOp;
0040: import java.awt.image.ColorModel;
0041: import java.awt.image.ComponentColorModel;
0042: import java.awt.image.DataBuffer;
0043: import java.awt.image.ImageConsumer;
0044: import java.awt.image.ImageObserver;
0045: import java.awt.image.Raster;
0046: import java.awt.image.RenderedImage;
0047: import java.awt.image.SampleModel;
0048: import java.awt.image.WritableRaster;
0049: import java.awt.image.WritableRenderedImage;
0050: import java.awt.image.renderable.RenderableImage;
0051: import java.awt.image.renderable.RenderContext;
0052: import java.lang.reflect.Method;
0053: import java.text.AttributedCharacterIterator;
0054: import java.util.LinkedList;
0055: import java.util.ListIterator;
0056: import java.util.Map;
0057: import java.util.Vector;
0058: import javax.media.jai.util.ImagingException;
0059: import javax.media.jai.util.ImagingListener;
0060: import com.sun.media.jai.util.JDKWorkarounds;
0061:
0062: /**
0063: * An implementation of <code>Graphics2D</code> with
0064: * <code>RenderableImage</code> semantics. In other words, content may be
0065: * drawn into the image using the <code>Graphics2D</code> interface and later
0066: * be turned into <code>RenderedImage</code>s with different resolutions and
0067: * characteristics.
0068: *
0069: * <p> A <code>RenderableGraphics</code> occupies a region of the plane
0070: * specified at the time of construction.
0071: *
0072: * <p> The contents of <code>RenderableImage</code>s that are drawn onto a
0073: * <code>RenderableGraphics</code> are accessed only at the time of rendering,
0074: * not the time of drawing.
0075: *
0076: * <p> Since the methods of this class all derive from <code>Graphics2D</code>
0077: * and <code>RenderableImage</code>, they are not all commented individually.
0078: *
0079: * @see java.awt.Graphics2D
0080: * @see java.awt.image.renderable.RenderableImage
0081: */
0082: public class RenderableGraphics extends Graphics2D implements
0083: RenderableImage {
0084:
0085: // Constants
0086: private static final Class GRAPHICS2D_CLASS = Graphics2D.class;
0087:
0088: // Bounding rectangle
0089: private Rectangle2D dimensions;
0090:
0091: // Linked list of (Method, Object[]) pairs.
0092: private LinkedList opArgList;
0093:
0094: // Graphics state information
0095: private Point origin;
0096: private Shape clip;
0097: private Color color;
0098: private Font font;
0099:
0100: // Graphics2D state information
0101: private Color background;
0102: private Composite composite;
0103: private Paint paint;
0104: private Stroke stroke;
0105: private RenderingHints renderingHints = new RenderingHints(null);
0106: private AffineTransform transform;
0107:
0108: /**
0109: * Constructs a <code>RenderableGraphics</code> given a bounding
0110: * <code>Rectangle2D</code>.
0111: *
0112: * @param dimensions The bounding <code>Rectangle2D</code>.
0113: */
0114: public RenderableGraphics(Rectangle2D dimensions) {
0115: this (dimensions, new LinkedList(), new Point(0, 0), null);
0116: }
0117:
0118: /**
0119: * Constructs a <code>RenderableGraphics</code> given a bounding
0120: * <code>Rectangle2D</code>, an origin, and a <code>Graphics2D</code>
0121: * object from which to initialize the <code>RenderableGraphics</code>
0122: * state. The <code>Graphics2D</code> may be null.
0123: *
0124: * @param dimensions The bounding <code>Rectangle2D</code>.
0125: * @param opArgList The list of operations and arguments.
0126: * @param dimensions The origin.
0127: * @param dimensions The <code>Graphics2D</code> state source; may be null.
0128: */
0129: private RenderableGraphics(Rectangle2D dimensions,
0130: LinkedList opArgList, Point origin, Graphics2D g) {
0131: if (dimensions.isEmpty()) {
0132: throw new RuntimeException(JaiI18N
0133: .getString("RenderableGraphics0"));
0134: }
0135:
0136: // -- RenderableGraphics state --
0137: this .dimensions = dimensions;
0138: this .opArgList = opArgList;
0139:
0140: // Use the Graphics2D passed in or create one.
0141: Graphics2D g2d = g;
0142: if (g2d == null) {
0143: g2d = getBogusGraphics2D();
0144: }
0145:
0146: // -- java.awt.Graphics state --
0147: this .origin = (Point) origin.clone();
0148: setClip(g2d.getClip());
0149: setColor(g2d.getColor());
0150: setFont(g2d.getFont());
0151:
0152: // -- java.awt.Graphics2D state --
0153: setBackground(g2d.getBackground());
0154: setComposite(g2d.getComposite());
0155: setRenderingHints(g2d.getRenderingHints());
0156: setStroke(g2d.getStroke());
0157: setTransform(g2d.getTransform());
0158:
0159: // Dispose of the Graphics2D if it was created within this method.
0160: if (g == null)
0161: g2d.dispose();
0162: }
0163:
0164: /**
0165: * Creates a bogus <code>Graphics2D</code> object to be used to retrieve
0166: * information dependent on system aspects which are image-independent.
0167: *
0168: * <p>The <code>dispose()</code> method of the <code>Graphics2D</code>
0169: * object returned should be called to free the associated resources as\
0170: * soon as possible.
0171: *
0172: * @return A <code>Graphics2D</code> object.
0173: */
0174: private Graphics2D getBogusGraphics2D() {
0175: TiledImage ti = createTiledImage(renderingHints, dimensions
0176: .getBounds());
0177:
0178: return ti.createGraphics();
0179: }
0180:
0181: /**
0182: * Create a TiledImage to be used as the canvas.
0183: *
0184: * @param hints RenderingHints from which to derive an ImageLayout.
0185: * @param bounds The bounding box of the TiledImage.
0186: *
0187: * @return A TiledImage.
0188: */
0189: private TiledImage createTiledImage(RenderingHints hints,
0190: Rectangle bounds) {
0191: // Set the default tile size.
0192: int tileWidth = bounds.width;
0193: int tileHeight = bounds.height;
0194:
0195: // Retrieve layout information from the hints. The tile size hints
0196: // are ignored if a SampleModel hint is supplied. Set the hints
0197: // observed if any hints are used.
0198: SampleModel sm = null;
0199: ColorModel cm = null;
0200: RenderingHints hintsObserved = null;
0201: if (hints != null) {
0202: // Get the ImageLayout.
0203: ImageLayout layout = (ImageLayout) hints
0204: .get(JAI.KEY_IMAGE_LAYOUT);
0205:
0206: if (layout != null) {
0207: // Initialize the observed hint variables.
0208: hintsObserved = new RenderingHints(null);
0209: ImageLayout layoutObserved = new ImageLayout();
0210:
0211: // Get the SampleModel.
0212: if (layout.isValid(ImageLayout.SAMPLE_MODEL_MASK)) {
0213: sm = layout.getSampleModel(null);
0214: if (sm.getWidth() != tileWidth
0215: || sm.getHeight() != tileHeight) {
0216: sm = sm.createCompatibleSampleModel(tileWidth,
0217: tileHeight);
0218: }
0219: if (layoutObserved != null) {
0220: layoutObserved.setSampleModel(sm);
0221: }
0222: }
0223:
0224: // Get the ColorModel.
0225: if (layout.isValid(ImageLayout.COLOR_MODEL_MASK)) {
0226: cm = layout.getColorModel(null);
0227: if (layoutObserved != null) {
0228: layoutObserved.setColorModel(cm);
0229: }
0230: }
0231:
0232: // Get the tile dimensions.
0233: if (layout.isValid(ImageLayout.TILE_WIDTH_MASK)) {
0234: tileWidth = layout.getTileWidth(null);
0235: if (layoutObserved != null) {
0236: layoutObserved.setTileWidth(tileWidth);
0237: }
0238: } else if (sm != null) {
0239: tileWidth = sm.getWidth();
0240: }
0241: if (layout.isValid(ImageLayout.TILE_HEIGHT_MASK)) {
0242: tileHeight = layout.getTileHeight(null);
0243: if (layoutObserved != null) {
0244: layoutObserved.setTileHeight(tileHeight);
0245: }
0246: } else if (sm != null) {
0247: tileHeight = sm.getHeight();
0248: }
0249:
0250: // Set the observed hints layout.
0251: hintsObserved.put(JAI.KEY_IMAGE_LAYOUT, layoutObserved);
0252: } // layout != null
0253: } // hints != null
0254:
0255: // Ensure that the SampleModel is compatible with the tile size.
0256: if (sm != null
0257: && (sm.getWidth() != tileWidth || sm.getHeight() != tileHeight)) {
0258: sm = sm.createCompatibleSampleModel(tileWidth, tileHeight);
0259: }
0260:
0261: // Attempt to derive compatible SampleModel/ColorModel combination.
0262: if (cm != null
0263: && (sm == null || !JDKWorkarounds
0264: .areCompatibleDataModels(sm, cm))) {
0265: // If the ColorModel is non-null and the SampleModel is null
0266: // or incompatible then create a new SampleModel.
0267: sm = cm.createCompatibleSampleModel(tileWidth, tileHeight);
0268: } else if (cm == null && sm != null) {
0269: // If the ColorModel is null but the SampleModel is not,
0270: // try to guess a reasonable ColorModel.
0271: cm = PlanarImage.createColorModel(sm);
0272:
0273: // If the ColorModel is still null, set it to the RGB default
0274: // ColorModel if the latter is compatible with the SampleModel.
0275: ColorModel cmRGB = ColorModel.getRGBdefault();
0276: if (cm == null
0277: && JDKWorkarounds
0278: .areCompatibleDataModels(sm, cmRGB)) {
0279: cm = cmRGB;
0280: }
0281: }
0282:
0283: // Create the TiledImage.
0284: TiledImage ti = null;
0285: if (sm != null) {
0286: // Use the (derived) SampleModel and ColorModel.
0287: ti = new TiledImage(bounds.x, bounds.y, bounds.width,
0288: bounds.height, bounds.x, bounds.y, sm, cm);
0289: } else {
0290: // Default to a PixelInterleaved TiledImage.
0291: ti = TiledImage.createInterleaved(bounds.x, bounds.y,
0292: bounds.width, bounds.height, 3,
0293: DataBuffer.TYPE_BYTE, tileWidth, tileHeight,
0294: new int[] { 0, 1, 2 });
0295: }
0296:
0297: // Set the HINTS_OBSERVED property of the TiledImage.
0298: if (hintsObserved != null) {
0299: ti.setProperty("HINTS_OBSERVED", hintsObserved);
0300: }
0301:
0302: return ti;
0303: }
0304:
0305: /**
0306: * Queue a <code>Graphics2D</code> operation and its argument list in the
0307: * linked list of operations and arguments. The name of the operation and
0308: * the array of class types of its arguments are used to determine the
0309: * associated <code>Method</code> object. The <code>Method</code> object
0310: * and array of <code>Object</code> arguments are appended to the list as
0311: * an ordered pair of the form (<code>Method</code>,<code>Object</code>[]).
0312: *
0313: * @param name The name of the <code>Graphics2D</code> operation.
0314: * @param argTypes An array of the <code>Classes</code> of the arguments
0315: * of the specified operation.
0316: * @param args The arguments of the operation as an array of
0317: * <code>Object</code>s.
0318: */
0319: private void queueOpArg(String name, Class[] argTypes, Object[] args) {
0320: // Determine the Method object associated with the Graphics2D method
0321: // having the indicated name. The search begins with the Graphics2D
0322: // class and continues to its superclasses until the Method is found.
0323: Method method = null;
0324: try {
0325: method = GRAPHICS2D_CLASS.getMethod(name, argTypes);
0326: } catch (Exception e) {
0327: String message = JaiI18N
0328: .getString("TiledGraphicsGraphics2")
0329: + name;
0330: sendExceptionToListener(message, new ImagingException(e));
0331: // throw new RuntimeException(e.getMessage());
0332: }
0333:
0334: // Queue the Method object and the Object[] argument array as an
0335: // ordered pair (Method, Object[]).
0336: opArgList.addLast(method);
0337: opArgList.addLast(args);
0338: }
0339:
0340: /**
0341: * Evaulate the queue of <code>Graphics2D</code> operations on the
0342: * specified <code>Graphics2D</code> object.
0343: *
0344: * @param g2d The <code>Graphics2D</code> on which to evaluate the
0345: * operation queue.
0346: */
0347: private void evaluateOpList(Graphics2D g2d) {
0348: if (opArgList == null) {
0349: return;
0350: }
0351:
0352: ListIterator li = opArgList.listIterator(0);
0353:
0354: while (li.hasNext()) {
0355: Method method = (Method) li.next();
0356: Object[] args = (Object[]) li.next();
0357:
0358: try {
0359: method.invoke(g2d, args);
0360: } catch (Exception e) {
0361: String message = JaiI18N
0362: .getString("TiledGraphicsGraphics4")
0363: + method;
0364: sendExceptionToListener(message,
0365: new ImagingException(e));
0366: // e.printStackTrace();
0367: // throw new RuntimeException(e.getMessage());
0368: }
0369: }
0370: }
0371:
0372: // ---------- Methods from java.awt.Graphics ----------
0373:
0374: public Graphics create() {
0375: return new RenderableGraphics(dimensions, opArgList, origin,
0376: this );
0377: }
0378:
0379: // public Graphics create(int x, int y, int width, int height)
0380: // -- implemented in Graphics superclass.
0381:
0382: public Color getColor() {
0383: return color;
0384: }
0385:
0386: public void setColor(Color c) {
0387: color = c;
0388:
0389: queueOpArg("setColor", new Class[] { java.awt.Color.class },
0390: new Object[] { c });
0391: }
0392:
0393: public void setPaintMode() {
0394: queueOpArg("setPaintMode", null, null);
0395: }
0396:
0397: public void setXORMode(Color c1) {
0398: queueOpArg("setXORMode", new Class[] { java.awt.Color.class },
0399: new Object[] { c1 });
0400: }
0401:
0402: public Font getFont() {
0403: return font;
0404: }
0405:
0406: public void setFont(Font font) {
0407: this .font = font;
0408:
0409: queueOpArg("setFont", new Class[] { java.awt.Font.class },
0410: new Object[] { font });
0411: }
0412:
0413: public FontMetrics getFontMetrics(Font f) {
0414: Graphics2D g2d = getBogusGraphics2D();
0415:
0416: FontMetrics fontMetrics = g2d.getFontMetrics(f);
0417:
0418: g2d.dispose();
0419:
0420: return fontMetrics;
0421: }
0422:
0423: public Rectangle getClipBounds() {
0424: return clip.getBounds();
0425: }
0426:
0427: public void clipRect(int x, int y, int width, int height) {
0428: clip(new Rectangle(x, y, width, height));
0429: }
0430:
0431: public void setClip(int x, int y, int width, int height) {
0432: clip = new Rectangle(x, y, width, height);
0433:
0434: queueOpArg("setClip", new Class[] { int.class, int.class,
0435: int.class, int.class },
0436: new Object[] { new Integer(x), new Integer(y),
0437: new Integer(width), new Integer(height) });
0438: }
0439:
0440: public Shape getClip() {
0441: return clip;
0442: }
0443:
0444: public void setClip(Shape clip) {
0445: this .clip = clip;
0446:
0447: queueOpArg("setClip", new Class[] { java.awt.Shape.class },
0448: new Object[] { clip });
0449: }
0450:
0451: public void copyArea(int x, int y, int width, int height, int dx,
0452: int dy) {
0453: queueOpArg("copyArea", new Class[] { int.class, int.class,
0454: int.class, int.class, int.class, int.class },
0455: new Object[] { new Integer(x), new Integer(y),
0456: new Integer(width), new Integer(height),
0457: new Integer(dx), new Integer(dy) });
0458: }
0459:
0460: public void drawLine(int x1, int y1, int x2, int y2) {
0461: queueOpArg("drawLine", new Class[] { int.class, int.class,
0462: int.class, int.class }, new Object[] { new Integer(x1),
0463: new Integer(y1), new Integer(x2), new Integer(y2) });
0464: }
0465:
0466: public void fillRect(int x, int y, int width, int height) {
0467: queueOpArg("fillRect", new Class[] { int.class, int.class,
0468: int.class, int.class },
0469: new Object[] { new Integer(x), new Integer(y),
0470: new Integer(width), new Integer(height) });
0471: }
0472:
0473: // public void drawRect(int x, int y, int width, int height)
0474: // -- implemented in Graphics superclass
0475:
0476: public void clearRect(int x, int y, int width, int height) {
0477: queueOpArg("clearRect", new Class[] { int.class, int.class,
0478: int.class, int.class },
0479: new Object[] { new Integer(x), new Integer(y),
0480: new Integer(width), new Integer(height) });
0481: }
0482:
0483: public void drawRoundRect(int x, int y, int width, int height,
0484: int arcWidth, int arcHeight) {
0485: queueOpArg("drawRoundRect", new Class[] { int.class, int.class,
0486: int.class, int.class, int.class, int.class },
0487: new Object[] { new Integer(x), new Integer(y),
0488: new Integer(width), new Integer(height),
0489: new Integer(arcWidth), new Integer(arcHeight) });
0490: }
0491:
0492: public void fillRoundRect(int x, int y, int width, int height,
0493: int arcWidth, int arcHeight) {
0494: queueOpArg("fillRoundRect", new Class[] { int.class, int.class,
0495: int.class, int.class, int.class, int.class },
0496: new Object[] { new Integer(x), new Integer(y),
0497: new Integer(width), new Integer(height),
0498: new Integer(arcWidth), new Integer(arcHeight) });
0499: }
0500:
0501: // draw3DRect() is implemented in the Graphics superclass but is
0502: // overridden in Graphics2D and so must be implemented here.
0503: public void draw3DRect(int x, int y, int width, int height,
0504: boolean raised) {
0505: queueOpArg("draw3DRect", new Class[] { int.class, int.class,
0506: int.class, int.class, boolean.class }, new Object[] {
0507: new Integer(x), new Integer(y), new Integer(width),
0508: new Integer(height), new Boolean(raised) });
0509: }
0510:
0511: // fill3DRect() is implemented in the Graphics superclass but is
0512: // overridden in Graphics2D and so must be implemented here.
0513: public void fill3DRect(int x, int y, int width, int height,
0514: boolean raised) {
0515: queueOpArg("fill3DRect", new Class[] { int.class, int.class,
0516: int.class, int.class, boolean.class }, new Object[] {
0517: new Integer(x), new Integer(y), new Integer(width),
0518: new Integer(height), new Boolean(raised) });
0519: }
0520:
0521: public void drawOval(int x, int y, int width, int height) {
0522: queueOpArg("drawOval", new Class[] { int.class, int.class,
0523: int.class, int.class },
0524: new Object[] { new Integer(x), new Integer(y),
0525: new Integer(width), new Integer(height) });
0526: }
0527:
0528: public void fillOval(int x, int y, int width, int height) {
0529: queueOpArg("fillOval", new Class[] { int.class, int.class,
0530: int.class, int.class },
0531: new Object[] { new Integer(x), new Integer(y),
0532: new Integer(width), new Integer(height) });
0533: }
0534:
0535: public void drawArc(int x, int y, int width, int height,
0536: int startAngle, int arcAngle) {
0537: queueOpArg(
0538: "drawArc",
0539: new Class[] { int.class, int.class, int.class,
0540: int.class, int.class, int.class },
0541: new Object[] { new Integer(x), new Integer(y),
0542: new Integer(width), new Integer(height),
0543: new Integer(startAngle), new Integer(arcAngle) });
0544: }
0545:
0546: public void fillArc(int x, int y, int width, int height,
0547: int startAngle, int arcAngle) {
0548: queueOpArg(
0549: "fillArc",
0550: new Class[] { int.class, int.class, int.class,
0551: int.class, int.class, int.class },
0552: new Object[] { new Integer(x), new Integer(y),
0553: new Integer(width), new Integer(height),
0554: new Integer(startAngle), new Integer(arcAngle) });
0555: }
0556:
0557: public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
0558: Class intArrayClass = xPoints.getClass();
0559: queueOpArg("drawPolyline", new Class[] { intArrayClass,
0560: intArrayClass, int.class }, new Object[] { xPoints,
0561: yPoints, new Integer(nPoints) });
0562: }
0563:
0564: public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
0565: Class intArrayClass = xPoints.getClass();
0566: queueOpArg("drawPolygon", new Class[] { intArrayClass,
0567: intArrayClass, int.class }, new Object[] { xPoints,
0568: yPoints, new Integer(nPoints) });
0569: }
0570:
0571: // public void drawPolygon -- implemented in Graphics superclass
0572:
0573: public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
0574: Class intArrayClass = xPoints.getClass();
0575: queueOpArg("fillPolygon", new Class[] { intArrayClass,
0576: intArrayClass, int.class }, new Object[] { xPoints,
0577: yPoints, new Integer(nPoints) });
0578: }
0579:
0580: // public void fillPolygon -- implemented in Graphics superclass
0581:
0582: public void drawString(String str, int x, int y) {
0583: queueOpArg("drawString", new Class[] { java.lang.String.class,
0584: int.class, int.class }, new Object[] { str,
0585: new Integer(x), new Integer(y) });
0586: }
0587:
0588: // public void drawChars -- implemented in Graphics superclass
0589: // public void drawBytes -- implemented in Graphics superclass
0590:
0591: public boolean drawImage(Image img, int x, int y,
0592: ImageObserver observer) {
0593: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0594: int.class, int.class,
0595: java.awt.image.ImageObserver.class }, new Object[] {
0596: img, new Integer(x), new Integer(y), observer });
0597: return true;
0598: }
0599:
0600: public boolean drawImage(Image img, int x, int y, int width,
0601: int height, ImageObserver observer) {
0602: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0603: int.class, int.class, int.class, int.class,
0604: java.awt.image.ImageObserver.class }, new Object[] {
0605: img, new Integer(x), new Integer(y),
0606: new Integer(width), new Integer(height), observer });
0607: return true;
0608: }
0609:
0610: public boolean drawImage(Image img, int x, int y, Color bgcolor,
0611: ImageObserver observer) {
0612: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0613: int.class, int.class, java.awt.Color.class,
0614: java.awt.image.ImageObserver.class },
0615: new Object[] { img, new Integer(x), new Integer(y),
0616: bgcolor, observer });
0617: return true;
0618: }
0619:
0620: public boolean drawImage(Image img, int x, int y, int width,
0621: int height, Color bgcolor, ImageObserver observer) {
0622: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0623: int.class, int.class, int.class, int.class,
0624: java.awt.Color.class,
0625: java.awt.image.ImageObserver.class }, new Object[] {
0626: img, new Integer(x), new Integer(y),
0627: new Integer(width), new Integer(height), bgcolor,
0628: observer });
0629: return true;
0630: }
0631:
0632: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
0633: int dy2, int sx1, int sy1, int sx2, int sy2,
0634: ImageObserver observer) {
0635: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0636: int.class, int.class, int.class, int.class, int.class,
0637: int.class, int.class, int.class,
0638: java.awt.image.ImageObserver.class }, new Object[] {
0639: img, new Integer(dx1), new Integer(dy1),
0640: new Integer(dx2), new Integer(dy2), new Integer(sx1),
0641: new Integer(sy1), new Integer(sx2), new Integer(sy2),
0642: observer });
0643: return true;
0644: }
0645:
0646: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
0647: int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor,
0648: ImageObserver observer) {
0649: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0650: int.class, int.class, int.class, int.class, int.class,
0651: int.class, int.class, int.class, java.awt.Color.class,
0652: java.awt.image.ImageObserver.class }, new Object[] {
0653: img, new Integer(dx1), new Integer(dy1),
0654: new Integer(dx2), new Integer(dy2), new Integer(sx1),
0655: new Integer(sy1), new Integer(sx2), new Integer(sy2),
0656: bgcolor, observer });
0657: return true;
0658: }
0659:
0660: public void dispose() {
0661: queueOpArg("dispose", null, null);
0662: }
0663:
0664: // public void finalize -- implemented in Graphics superclass
0665: // public String toString -- implemented in Graphics superclass
0666:
0667: // ---------- Methods from java.awt.Graphics2D ----------
0668:
0669: public void addRenderingHints(Map hints) {
0670: renderingHints.putAll(hints);
0671:
0672: queueOpArg("addRenderingHints",
0673: new Class[] { java.util.Map.class },
0674: new Object[] { hints });
0675: }
0676:
0677: public void draw(Shape s) {
0678: queueOpArg("draw", new Class[] { java.awt.Shape.class },
0679: new Object[] { s });
0680: }
0681:
0682: public boolean drawImage(Image img, AffineTransform xform,
0683: ImageObserver obs) {
0684: queueOpArg("drawImage", new Class[] { java.awt.Image.class,
0685: java.awt.geom.AffineTransform.class,
0686: java.awt.image.ImageObserver.class }, new Object[] {
0687: img, xform, obs });
0688: return true;
0689: }
0690:
0691: public void drawRenderedImage(RenderedImage img,
0692: AffineTransform xform) {
0693:
0694: queueOpArg("drawRenderedImage", new Class[] {
0695: java.awt.image.RenderedImage.class,
0696: java.awt.geom.AffineTransform.class }, new Object[] {
0697: img, xform });
0698: }
0699:
0700: public void drawRenderableImage(RenderableImage img,
0701: AffineTransform xform) {
0702: queueOpArg("drawRenderableImage", new Class[] {
0703: java.awt.image.renderable.RenderableImage.class,
0704: java.awt.geom.AffineTransform.class }, new Object[] {
0705: img, xform });
0706: }
0707:
0708: public void drawImage(BufferedImage img, BufferedImageOp op, int x,
0709: int y) {
0710: queueOpArg("drawImage", new Class[] {
0711: java.awt.image.BufferedImage.class,
0712: java.awt.image.BufferedImageOp.class, int.class,
0713: int.class }, new Object[] { img, op, new Integer(x),
0714: new Integer(y) });
0715: }
0716:
0717: public void drawString(String s, float x, float y) {
0718: queueOpArg("drawString", new Class[] { java.lang.String.class,
0719: float.class, float.class }, new Object[] { s,
0720: new Float(x), new Float(y) });
0721: }
0722:
0723: public void drawString(AttributedCharacterIterator iterator, int x,
0724: int y) {
0725: queueOpArg("drawString", new Class[] {
0726: java.text.AttributedCharacterIterator.class, int.class,
0727: int.class }, new Object[] { iterator, new Integer(x),
0728: new Integer(y) });
0729: }
0730:
0731: public void drawString(AttributedCharacterIterator iterator,
0732: float x, float y) {
0733: queueOpArg("drawString", new Class[] {
0734: java.text.AttributedCharacterIterator.class,
0735: float.class, float.class }, new Object[] { iterator,
0736: new Float(x), new Float(y) });
0737: }
0738:
0739: public void drawGlyphVector(GlyphVector v, float x, float y) {
0740: queueOpArg("drawGlyphVector", new Class[] {
0741: java.awt.font.GlyphVector.class, float.class,
0742: float.class }, new Object[] { v, new Float(x),
0743: new Float(y) });
0744:
0745: }
0746:
0747: public void fill(Shape s) {
0748: queueOpArg("fill", new Class[] { java.awt.Shape.class },
0749: new Object[] { s });
0750: }
0751:
0752: public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
0753: Graphics2D g2d = getBogusGraphics2D();
0754:
0755: boolean hitTarget = g2d.hit(rect, s, onStroke);
0756:
0757: g2d.dispose();
0758:
0759: return hitTarget;
0760: }
0761:
0762: public GraphicsConfiguration getDeviceConfiguration() {
0763: Graphics2D g2d = getBogusGraphics2D();
0764:
0765: GraphicsConfiguration gConf = g2d.getDeviceConfiguration();
0766:
0767: g2d.dispose();
0768:
0769: return gConf;
0770: }
0771:
0772: public FontRenderContext getFontRenderContext() {
0773: Graphics2D g2d = getBogusGraphics2D();
0774:
0775: FontRenderContext fontRenderContext = g2d
0776: .getFontRenderContext();
0777:
0778: g2d.dispose();
0779:
0780: return fontRenderContext;
0781: }
0782:
0783: public void setComposite(Composite comp) {
0784: composite = comp;
0785: queueOpArg("setComposite",
0786: new Class[] { java.awt.Composite.class },
0787: new Object[] { comp });
0788: }
0789:
0790: public void setPaint(Paint paint) {
0791: this .paint = paint;
0792: queueOpArg("setPaint", new Class[] { java.awt.Paint.class },
0793: new Object[] { paint });
0794: }
0795:
0796: public void setStroke(Stroke s) {
0797: stroke = s;
0798: queueOpArg("setStroke", new Class[] { java.awt.Stroke.class },
0799: new Object[] { s });
0800: }
0801:
0802: public void setRenderingHint(RenderingHints.Key hintKey,
0803: Object hintValue) {
0804: renderingHints.put(hintKey, hintValue);
0805:
0806: queueOpArg("setRenderingHint", new Class[] {
0807: java.awt.RenderingHints.Key.class,
0808: java.lang.Object.class }, new Object[] { hintKey,
0809: hintValue });
0810: }
0811:
0812: public Object getRenderingHint(RenderingHints.Key hintKey) {
0813: return renderingHints.get(hintKey);
0814: }
0815:
0816: public void setRenderingHints(Map hints) {
0817: renderingHints.putAll(hints);
0818:
0819: queueOpArg("setRenderingHints",
0820: new Class[] { java.util.Map.class },
0821: new Object[] { hints });
0822: }
0823:
0824: public RenderingHints getRenderingHints() {
0825: return renderingHints;
0826: }
0827:
0828: public void translate(int x, int y) {
0829: origin = new Point(x, y);
0830: transform.translate((double) x, (double) y);
0831:
0832: queueOpArg("translate", new Class[] { int.class, int.class },
0833: new Object[] { new Integer(x), new Integer(y) });
0834: }
0835:
0836: public void translate(double x, double y) {
0837: transform.translate(x, y);
0838:
0839: queueOpArg("translate", new Class[] { double.class,
0840: double.class }, new Object[] { new Double(x),
0841: new Double(y) });
0842: }
0843:
0844: public void rotate(double theta) {
0845: transform.rotate(theta);
0846:
0847: queueOpArg("rotate", new Class[] { double.class },
0848: new Object[] { new Double(theta) });
0849: }
0850:
0851: public void rotate(double theta, double x, double y) {
0852: transform.rotate(theta, x, y);
0853:
0854: queueOpArg("rotate", new Class[] { double.class, double.class,
0855: double.class }, new Object[] { new Double(theta),
0856: new Double(x), new Double(y) });
0857: }
0858:
0859: public void scale(double sx, double sy) {
0860: transform.scale(sx, sy);
0861:
0862: queueOpArg("scale", new Class[] { double.class, double.class },
0863: new Object[] { new Double(sx), new Double(sy) });
0864: }
0865:
0866: public void shear(double shx, double shy) {
0867: transform.shear(shx, shy);
0868:
0869: queueOpArg("shear", new Class[] { double.class, double.class },
0870: new Object[] { new Double(shx), new Double(shy) });
0871: }
0872:
0873: public void transform(AffineTransform Tx) {
0874: transform.concatenate(Tx);
0875:
0876: queueOpArg("transform",
0877: new Class[] { java.awt.geom.AffineTransform.class },
0878: new Object[] { Tx });
0879: }
0880:
0881: public void setTransform(AffineTransform Tx) {
0882: transform = Tx;
0883:
0884: queueOpArg("setTransform",
0885: new Class[] { java.awt.geom.AffineTransform.class },
0886: new Object[] { Tx });
0887: }
0888:
0889: public AffineTransform getTransform() {
0890: return transform;
0891: }
0892:
0893: public Paint getPaint() {
0894: return paint;
0895: }
0896:
0897: public Composite getComposite() {
0898: return composite;
0899: }
0900:
0901: public void setBackground(Color color) {
0902: background = color;
0903:
0904: queueOpArg("setBackground",
0905: new Class[] { java.awt.Color.class },
0906: new Object[] { color });
0907: }
0908:
0909: public Color getBackground() {
0910: return background;
0911: }
0912:
0913: public Stroke getStroke() {
0914: return stroke;
0915: }
0916:
0917: public void clip(Shape s) {
0918: if (clip == null) {
0919: clip = s;
0920: } else {
0921: Area clipArea = (clip instanceof Area ? (Area) clip
0922: : new Area(clip));
0923: clipArea.intersect(s instanceof Area ? (Area) s : new Area(
0924: s));
0925: clip = clipArea;
0926: }
0927:
0928: queueOpArg("clip", new Class[] { java.awt.Shape.class },
0929: new Object[] { s });
0930: }
0931:
0932: // ---------- Methods from RenderableImage ----------
0933:
0934: public Vector getSources() {
0935: return null;
0936: }
0937:
0938: public Object getProperty(String name) {
0939: return Image.UndefinedProperty;
0940: }
0941:
0942: public String[] getPropertyNames() {
0943: return null;
0944: }
0945:
0946: public boolean isDynamic() {
0947: return false;
0948: }
0949:
0950: public float getWidth() {
0951: return (float) dimensions.getWidth();
0952: }
0953:
0954: public float getHeight() {
0955: return (float) dimensions.getHeight();
0956: }
0957:
0958: public float getMinX() {
0959: return (float) dimensions.getMinX();
0960: }
0961:
0962: public float getMinY() {
0963: return (float) dimensions.getMinY();
0964: }
0965:
0966: public RenderedImage createScaledRendering(int w, int h,
0967: RenderingHints hints) {
0968: if (w <= 0 && h <= 0) {
0969: throw new IllegalArgumentException(JaiI18N
0970: .getString("RenderableGraphics1"));
0971: } else if (w <= 0) {
0972: w = (int) Math.round(h * dimensions.getWidth()
0973: / dimensions.getHeight());
0974: } else if (h <= 0) {
0975: h = (int) Math.round(w * dimensions.getHeight()
0976: / dimensions.getWidth());
0977: }
0978:
0979: double sx = (double) w / dimensions.getWidth();
0980: double sy = (double) h / dimensions.getHeight();
0981: AffineTransform usr2dev = new AffineTransform();
0982: usr2dev.setToScale(sx, sy);
0983:
0984: return createRendering(new RenderContext(usr2dev, hints));
0985: }
0986:
0987: public RenderedImage createDefaultRendering() {
0988: return createRendering(new RenderContext(new AffineTransform()));
0989: }
0990:
0991: /**
0992: * Creates a RenderedImage that represents a rendering of this image
0993: * using a given RenderContext. This is the most general way to obtain a
0994: * rendering of a RenderableImage.
0995: *
0996: * <p> The created RenderedImage may have a property identified
0997: * by the String HINTS_OBSERVED to indicate which RenderingHints
0998: * (from the RenderContext) were used to create the image. In addition
0999: * any RenderedImages that are obtained via the getSources() method on
1000: * the created RenderedImage may have such a property.
1001: *
1002: * <p> The bounds of the <code>RenderedImage</code> are determined from
1003: * the dimensions parameter passed to the <code>RenderableGraphics</code>
1004: * constructor. These bounds will be transformed by any
1005: * <code>AffineTransform</code> from the <code>RenderContext</code>.
1006: * The <code>RenderingHints</code> from the <code>RenderContext</code> may
1007: * be used to specify the tile width and height, <code>SampleModel</code>,
1008: * and <code>ColorModel</code> by supplying an <code>ImageLayout</code>
1009: * hint. The precedence for determining tile width and height is to use
1010: * firstly values provided explicitly via the <code>ImageLayout</code>,
1011: * secondly the width and height of the <code>SampleModel</code> in the
1012: * hint, and thirdly the bounds of the <code>RenderableGraphics</code>
1013: * object after transformation.
1014: *
1015: * <p> If either the <code>SampleModel</code> or <code>ColorModel</code>
1016: * is null, an attempt will be made to derive a compatible value for the
1017: * null object from the non-null object. If they are both null, a 3-band
1018: * byte <code>TiledImage</code> with a null <code>ColorModel</code> and a
1019: * <code>PixelInterleavedSampleModel</code> will be created.
1020: *
1021: * @param renderContext the RenderContext to use to produce the rendering.
1022: * @return a RenderedImage containing the rendered data.
1023: */
1024: public RenderedImage createRendering(RenderContext renderContext) {
1025: // Unpack the RenderContext and set local variables based thereon
1026: AffineTransform usr2dev = renderContext.getTransform();
1027: if (usr2dev == null) {
1028: usr2dev = new AffineTransform();
1029: }
1030: RenderingHints hints = renderContext.getRenderingHints();
1031: Shape aoi = renderContext.getAreaOfInterest();
1032: if (aoi == null) {
1033: aoi = dimensions.getBounds();
1034: }
1035:
1036: // Transform the area of interest.
1037: Shape transformedAOI = usr2dev.createTransformedShape(aoi);
1038:
1039: // Create a TiledImage to be used as the canvas.
1040: TiledImage ti = createTiledImage(hints, transformedAOI
1041: .getBounds());
1042:
1043: // Create the associated Graphics2D object and translate it to
1044: // account for the initial origin specified in the RenderableGraphics
1045: // constructor.
1046: Graphics2D g2d = ti.createGraphics();
1047:
1048: // NOTE: There is no need to copy the state to the TiledImageGraphics
1049: // object here as all modifications are contained in the opArgList.
1050:
1051: // Set Graphics2D state variables according to the RenderContext
1052: if (!usr2dev.isIdentity()) {
1053: AffineTransform tf = getTransform();
1054: tf.concatenate(usr2dev);
1055: g2d.setTransform(tf);
1056: }
1057: if (hints != null) {
1058: g2d.addRenderingHints(hints);
1059: }
1060: g2d.setClip(aoi);
1061:
1062: // Evaluate the operation queue
1063: evaluateOpList(g2d);
1064:
1065: // Free Graphics2D resources
1066: g2d.dispose();
1067:
1068: return ti;
1069: }
1070:
1071: void sendExceptionToListener(String message, Exception e) {
1072: ImagingListener listener = null;
1073: if (renderingHints != null)
1074: listener = (ImagingListener) renderingHints
1075: .get(JAI.KEY_IMAGING_LISTENER);
1076:
1077: if (listener == null)
1078: listener = JAI.getDefaultInstance().getImagingListener();
1079: listener.errorOccurred(message, e, this , false);
1080: }
1081: }
|