All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlgraphics.java2d.ps.PSGraphics2D Maven / Gradle / Ivy

Go to download

Apache XML Graphics Commons is a library that consists of several reusable components used by Apache Batik and Apache FOP. Many of these components can easily be used separately outside the domains of SVG and XSL-FO.

There is a newer version: 2.9
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: PSGraphics2D.java 1809627 2017-09-25 13:42:08Z ssteiner $ */

package org.apache.xmlgraphics.java2d.ps;

//Java
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.TexturePaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
import org.apache.xmlgraphics.java2d.GraphicContext;
import org.apache.xmlgraphics.java2d.GraphicsConfigurationWithoutTransparency;
import org.apache.xmlgraphics.java2d.StrokingTextHandler;
import org.apache.xmlgraphics.java2d.TextHandler;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSImageUtils;

/**
 * This is a concrete implementation of AbstractGraphics2D (and
 * therefore of Graphics2D) which is able to generate PostScript
 * code.
 *
 * @version $Id: PSGraphics2D.java 1809627 2017-09-25 13:42:08Z ssteiner $
 * @see org.apache.xmlgraphics.java2d.AbstractGraphics2D
 *
 * Originally authored by Keiron Liddle.
 */
public class PSGraphics2D extends AbstractGraphics2D {

    private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform();

    private static final boolean DEBUG = false;

    protected List pathHashCache = new ArrayList();
    protected boolean startCache;
    /**
     * The G2D instance that represents the root instance
     * (used in context with create()/dispose()). Null if this instance is the root instance.
     */
    protected PSGraphics2D rootG2D;

    /** the PostScript generator being created */
    protected PSGenerator gen;

    /** Disable or enable clipping */
    protected boolean clippingDisabled;

    /** Fallback text handler */

    protected TextHandler fallbackTextHandler = new StrokingTextHandler();

    /** Custom text handler */
    protected TextHandler customTextHandler;

    /**
     * the current colour for use in svg
     */
    protected Color currentColour = new Color(0, 0, 0);

    /**
     * Create a new Graphics2D that generates PostScript code.
     * @param textAsShapes True if text should be rendered as graphics
     * @see org.apache.xmlgraphics.java2d.AbstractGraphics2D#AbstractGraphics2D(boolean)
     */
    public PSGraphics2D(boolean textAsShapes) {
        super(textAsShapes);
    }

    /**
     * Create a new Graphics2D that generates PostScript code.
     * @param textAsShapes True if text should be rendered as graphics
     * @param gen PostScript generator to use for output
     * @see org.apache.xmlgraphics.java2d.AbstractGraphics2D#AbstractGraphics2D(boolean)
     */
    public PSGraphics2D(boolean textAsShapes, PSGenerator gen) {
        this(textAsShapes);
        setPSGenerator(gen);
    }

    /**
     * Constructor for creating copies
     * @param g parent PostScript Graphics2D
     */
    public PSGraphics2D(PSGraphics2D g) {
        super(g);

        this.rootG2D = (g.rootG2D != null ? g.rootG2D : g);
        setPSGenerator(g.gen);
        this.clippingDisabled = g.clippingDisabled;
        //this.fallbackTextHandler is not copied
        //TODO The customTextHandler should probably not be passed over just like that
        //fallbackTextHandler, for example, has to be recreated to point to the sub-Graphics2D
        //to get the text positioning right. This might require changes in the TextHandler interface
        this.customTextHandler = g.customTextHandler;
        this.currentColour    = g.currentColour;
    }

    /**
     * Sets the PostScript generator
     * @param gen the PostScript generator
     */
    public void setPSGenerator(PSGenerator gen) {
        this.gen = gen;
    }

    /** @return the PostScript generator used by this instance. */
    public PSGenerator getPSGenerator() {
        return this.gen;
    }

    /**
     * Sets the GraphicContext
     * @param c GraphicContext to use
     */
    public void setGraphicContext(GraphicContext c) {
        gc = c;
        //setPrivateHints();
    }

    /** @return the fallback TextHandler implementation */
    public TextHandler getFallbackTextHandler() {
        return this.fallbackTextHandler;
    }

    /** @return the custom TextHandler implementation */
    public TextHandler getCustomTextHandler() {
        return this.customTextHandler;
    }

    /**
     * Sets a custom TextHandler implementation that is responsible for painting text. The default
     * TextHandler paints all text as shapes. A custom implementation can implement text painting
     * using text painting operators.
     * @param handler the custom TextHandler implementation
     */
    public void setCustomTextHandler(TextHandler handler) {
        this.customTextHandler = handler;
    }

    /* TODO Add me back at the right place!!!
    private void setPrivateHints() {
        setRenderingHint(RenderingHintsKeyExt.KEY_AVOID_TILE_PAINTING,
                RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_ON);
    }*/

    /**
     * Disable clipping on each draw command.
     *
     * @param b set to true to disable all clipping.
     */
    public void disableClipping(boolean b) {
        this.clippingDisabled = b;
    }

    /**
     * Creates a new Graphics object that is
     * a copy of this Graphics object.
     * @return     a new graphics context that is a copy of
     * this graphics context.
     */
    public Graphics create() {
        preparePainting();
        return new PSGraphics2D(this);
    }

    /**
     * Central handler for IOExceptions for this class.
     * @param ioe IOException to handle
     */
    public void handleIOException(IOException ioe) {
        //TODO Surely, there's a better way to do this.
        ioe.printStackTrace();
    }

    /**
     * This method is used by AbstractPSDocumentGraphics2D to prepare a new page if
     * necessary.
     */
    public void preparePainting() {
        //nop, used by AbstractPSDocumentGraphics2D
        if (rootG2D != null) {
            rootG2D.preparePainting();
        }
    }

    /**
     * Draws as much of the specified image as is currently available.
     * The image is drawn with its top-left corner at
     * (xy) in this graphics context's coordinate
     * space. Transparent pixels in the image do not affect whatever
     * pixels are already there.
     * 

* This method returns immediately in all cases, even if the * complete image has not yet been loaded, and it has not been dithered * and converted for the current output device. *

* If the image has not yet been completely loaded, then * drawImage returns false. As more of * the image becomes available, the process that draws the image notifies * the specified image observer. * @param img the specified image to be drawn. * @param x the x coordinate. * @param y the y coordinate. * @param observer object to be notified as more of * the image is converted. * @return True if the image has been fully drawn/loaded * @see java.awt.Image * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ public boolean drawImage(Image img, int x, int y, ImageObserver observer) { return drawImage(img, x, y, observer, null); } public boolean drawImage(Image img, int x, int y, ImageObserver observer, Color mask) { preparePainting(); if (DEBUG) { System.out.println("drawImage: " + x + ", " + y + " " + img.getClass().getName()); } final int width = img.getWidth(observer); final int height = img.getHeight(observer); if (width == -1 || height == -1) { return false; } Dimension size = new Dimension(width, height); BufferedImage buf = buildBufferedImage(size); java.awt.Graphics2D g = buf.createGraphics(); g.setComposite(AlphaComposite.SrcOver); g.setBackground(new Color(1, 1, 1, 0)); g.fillRect(0, 0, width, height); g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight())); if (!g.drawImage(img, 0, 0, observer)) { return false; } g.dispose(); try { AffineTransform at = getTransform(); gen.saveGraphicsState(); gen.concatMatrix(at); Shape imclip = getClip(); writeClip(imclip); PSImageUtils.renderBitmapImage(buf, x, y, width, height, gen, mask); gen.restoreGraphicsState(); } catch (IOException ioe) { handleIOException(ioe); } return true; } /** * Creates a buffered image. * @param size dimensions of the image to be created * @return the buffered image */ public BufferedImage buildBufferedImage(Dimension size) { return new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); } /** * Draws as much of the specified image as has already been scaled * to fit inside the specified rectangle. *

* The image is drawn inside the specified rectangle of this * graphics context's coordinate space, and is scaled if * necessary. Transparent pixels do not affect whatever pixels * are already there. *

* This method returns immediately in all cases, even if the * entire image has not yet been scaled, dithered, and converted * for the current output device. * If the current output representation is not yet complete, then * drawImage returns false. As more of * the image becomes available, the process that draws the image notifies * the image observer by calling its imageUpdate method. *

* A scaled version of an image will not necessarily be * available immediately just because an unscaled version of the * image has been constructed for this output device. Each size of * the image may be cached separately and generated from the original * data in a separate image production sequence. * @param img the specified image to be drawn. * @param x the x coordinate. * @param y the y coordinate. * @param width the width of the rectangle. * @param height the height of the rectangle. * @param observer object to be notified as more of * the image is converted. * @return True if the image has been fully loaded/drawn * @see java.awt.Image * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { preparePainting(); System.err.println("NYI: drawImage"); return true; } /** * Disposes of this graphics context and releases * any system resources that it is using. * A Graphics object cannot be used after * disposehas been called. *

* When a Java program runs, a large number of Graphics * objects can be created within a short time frame. * Although the finalization process of the garbage collector * also disposes of the same system resources, it is preferable * to manually free the associated resources by calling this * method rather than to rely on a finalization process which * may not run to completion for a long period of time. *

* Graphics objects which are provided as arguments to the * paint and update methods * of components are automatically released by the system when * those methods return. For efficiency, programmers should * call dispose when finished using * a Graphics object only if it was created * directly from a component or another Graphics object. * @see java.awt.Graphics#finalize * @see java.awt.Component#paint * @see java.awt.Component#update * @see java.awt.Component#getGraphics * @see java.awt.Graphics#create */ public void dispose() { this.gen = null; this.fallbackTextHandler = null; this.customTextHandler = null; this.currentColour = null; } /** * Processes a Shape generating the necessary painting operations. * @param s Shape to process * @return the winding rule of the path defining the shape * @throws IOException In case of an I/O problem. */ public int processShape(Shape s, boolean cached) throws IOException { if (s instanceof Rectangle2D) { // Special optimization in case of Rectangle Shape Rectangle2D r = (Rectangle2D) s; gen.defineRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); return PathIterator.WIND_NON_ZERO; } else { PathIterator iter = s.getPathIterator(IDENTITY_TRANSFORM); if (cached) { processPathIteratorCached(s); } else { processPathIterator(iter); } return iter.getWindingRule(); } } protected String processPathIteratorToString(PathIterator iter) throws IOException { StringBuilder cmd = new StringBuilder(); double[] vals = new double[6]; while (!iter.isDone()) { int type = iter.currentSegment(vals); switch (type) { case PathIterator.SEG_CUBICTO: cmd.append(gen.formatDouble(vals[0])).append(" ").append(gen.formatDouble(vals[1])).append(" ") .append(gen.formatDouble(vals[2])).append(" ").append(gen.formatDouble(vals[3])).append(" ") .append(gen.formatDouble(vals[4])).append(" ").append(gen.formatDouble(vals[5])).append(" ") .append(gen.mapCommand("curveto")).append("\n"); break; case PathIterator.SEG_LINETO: cmd.append(gen.formatDouble(vals[0])).append(" ").append(gen.formatDouble(vals[1])).append(" ") .append(gen.mapCommand("lineto")).append("\n"); break; case PathIterator.SEG_MOVETO: cmd.append(gen.formatDouble(vals[0])).append(" ").append(gen.formatDouble(vals[1])).append(" ") .append(gen.mapCommand("moveto")).append("\n"); break; case PathIterator.SEG_QUADTO: cmd.append(gen.formatDouble(vals[0])).append(" ").append(gen.formatDouble(vals[1])).append(" ") .append(gen.formatDouble(vals[2])).append(" ").append(gen.formatDouble(vals[3])).append(" QT") .append("\n"); break; case PathIterator.SEG_CLOSE: cmd.append(gen.mapCommand("closepath")).append("\n"); break; default: break; } iter.next(); } return cmd.toString().trim(); } protected void processPathIteratorCached(Shape s) throws IOException { String cmd = processPathIteratorToString(s.getPathIterator(IDENTITY_TRANSFORM)); int hash = cmd.hashCode(); if (!startCache) { if (pathHashCache.contains(hash)) { startCache = true; pathHashCache.clear(); } else { gen.writeln(cmd); pathHashCache.add(hash); } } if (startCache) { if (!pathHashCache.contains(hash)) { gen.writeln("/f" + hash + "{" + cmd + "}def"); pathHashCache.add(hash); } gen.writeln("f" + hash); } } /** * Processes a path iterator generating the nexessary painting operations. * @param iter PathIterator to process * @throws IOException In case of an I/O problem. */ public void processPathIterator(PathIterator iter) throws IOException { gen.writeln(processPathIteratorToString(iter)); } /** * Strokes the outline of a Shape using the settings of the * current Graphics2D context. The rendering attributes * applied include the Clip, Transform, * Paint, Composite and * Stroke attributes. * @param s the Shape to be rendered * @see #setStroke * @see #setPaint * @see java.awt.Graphics#setColor * @see #transform * @see #setTransform * @see #clip * @see #setClip * @see #setComposite */ public void draw(Shape s) { preparePainting(); try { gen.saveGraphicsState(); AffineTransform trans = getTransform(); boolean newTransform = !trans.isIdentity(); if (newTransform) { gen.concatMatrix(trans); } Shape imclip = getClip(); if (shouldBeClipped(imclip, s)) { writeClip(imclip); } establishColor(getColor()); applyPaint(getPaint(), false); applyStroke(getStroke()); gen.writeln(gen.mapCommand("newpath")); processShape(s, false); doDrawing(false, true, false); gen.restoreGraphicsState(); } catch (IOException ioe) { handleIOException(ioe); } } /** * Determines if a shape interacts with a clipping region. * @param clip Shape defining the clipping region * @param s Shape to be drawn * @return true if code for a clipping region needs to be generated. */ public boolean shouldBeClipped(Shape clip, Shape s) { if (clip == null || s == null) { return false; } if (s instanceof Line2D) { //Line shapes don't work with intersections so always clip return true; } Area as = new Area(s); Area imclip = new Area(clip); imclip.intersect(as); return !imclip.equals(as); } /** * Establishes a clipping region * @param s Shape defining the clipping region */ public void writeClip(Shape s) { if (s == null) { return; } if (!this.clippingDisabled) { preparePainting(); try { gen.writeln(gen.mapCommand("newpath")); processShape(s, false); // clip area gen.writeln(gen.mapCommand("clip")); } catch (IOException ioe) { handleIOException(ioe); } } } /** * Applies a new Paint object. * @param paint Paint object to use * @param fill True if to be applied for filling */ protected void applyPaint(Paint paint, boolean fill) { preparePainting(); if (paint instanceof GradientPaint) { System.err.println("NYI: Gradient paint"); } else if (paint instanceof TexturePaint) { if (fill) { try { // create pattern with texture and use it for filling of a graphics object PSTilingPattern psTilingPattern = new PSTilingPattern("Pattern1", (TexturePaint)paint, 0, 0, 3, null); gen.write(psTilingPattern.toString(gen.isAcrobatDownsample())); gen.writeln("/Pattern " + gen.mapCommand("setcolorspace")); gen.writeln(psTilingPattern.getName() + " " + gen.mapCommand("setcolor")); } catch (IOException ioe) { handleIOException(ioe); } } } } /** * Applies a new Stroke object. * @param stroke Stroke object to use */ protected void applyStroke(Stroke stroke) { preparePainting(); try { applyStroke(stroke, gen); } catch (IOException ioe) { handleIOException(ioe); } } /** * Applies a new Stroke object. * @param stroke the Stroke instance * @param gen the PS generator * @throws IOException if an I/O error occurs */ public static void applyStroke(Stroke stroke, final PSGenerator gen) throws IOException { if (stroke instanceof BasicStroke) { BasicStroke basicStroke = (BasicStroke)stroke; float[] da = basicStroke.getDashArray(); if (da != null) { StringBuffer sb = new StringBuffer("["); for (int count = 0; count < da.length; count++) { sb.append(gen.formatDouble(da[count])); if (count < da.length - 1) { sb.append(" "); } } sb.append("] "); float offset = basicStroke.getDashPhase(); sb.append(gen.formatDouble(offset)); gen.useDash(sb.toString()); } else { gen.useDash(null); } int ec = basicStroke.getEndCap(); switch (ec) { case BasicStroke.CAP_BUTT: gen.useLineCap(0); break; case BasicStroke.CAP_ROUND: gen.useLineCap(1); break; case BasicStroke.CAP_SQUARE: gen.useLineCap(2); break; default: System.err.println("Unsupported line cap: " + ec); } int lj = basicStroke.getLineJoin(); switch (lj) { case BasicStroke.JOIN_MITER: gen.useLineJoin(0); float ml = basicStroke.getMiterLimit(); gen.useMiterLimit(ml >= -1 ? ml : 1); break; case BasicStroke.JOIN_ROUND: gen.useLineJoin(1); break; case BasicStroke.JOIN_BEVEL: gen.useLineJoin(2); break; default: System.err.println("Unsupported line join: " + lj); } float lw = basicStroke.getLineWidth(); gen.useLineWidth(lw); } else { System.err.println("Stroke not supported: " + stroke.toString()); } } /** * Renders a {@link RenderedImage}, * applying a transform from image * space into user space before drawing. * The transformation from user space into device space is done with * the current Transform in the Graphics2D. * The specified transformation is applied to the image before the * transform attribute in the Graphics2D context is applied. * The rendering attributes applied include the Clip, * Transform, and Composite attributes. Note * that no rendering is done if the specified transform is * noninvertible. * @param img the image to be rendered * @param xform the transformation from image space into user space * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { preparePainting(); try { AffineTransform at = getTransform(); gen.saveGraphicsState(); gen.concatMatrix(at); gen.concatMatrix(xform); Shape imclip = getClip(); writeClip(imclip); PSImageUtils.renderBitmapImage(img, 0, 0, img.getWidth(), img.getHeight(), gen, null); gen.restoreGraphicsState(); } catch (IOException ioe) { handleIOException(ioe); } } /** * Renders a * {@link RenderableImage}, * applying a transform from image space into user space before drawing. * The transformation from user space into device space is done with * the current Transform in the Graphics2D. * The specified transformation is applied to the image before the * transform attribute in the Graphics2D context is applied. * The rendering attributes applied include the Clip, * Transform, and Composite attributes. Note * that no rendering is done if the specified transform is * noninvertible. *

* Rendering hints set on the Graphics2D object might * be used in rendering the RenderableImage. * If explicit control is required over specific hints recognized by a * specific RenderableImage, or if knowledge of which hints * are used is required, then a RenderedImage should be * obtained directly from the RenderableImage * and rendered using * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}. * @param img the image to be rendered * @param xform the transformation from image space into user space * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip * @see #drawRenderedImage */ public void drawRenderableImage(RenderableImage img, AffineTransform xform) { preparePainting(); System.err.println("NYI: drawRenderableImage"); } /** * Establishes the given color in the PostScript interpreter. * @param c the color to set * @throws IOException In case of an I/O problem */ public void establishColor(Color c) throws IOException { gen.useColor(c); } /** * Renders the text specified by the specified String, * using the current Font and Paint attributes * in the Graphics2D context. * The baseline of the first character is at position * (xy) in the User Space. * The rendering attributes applied include the Clip, * Transform, Paint, Font and * Composite attributes. For characters in script systems * such as Hebrew and Arabic, the glyphs can be rendered from right to * left, in which case the coordinate supplied is the location of the * leftmost character on the baseline. * @param s the String to be rendered * @param x the x-coordinate where the String * should be rendered * @param y the y-coordinate where the String * should be rendered * @see #setPaint * @see java.awt.Graphics#setColor * @see java.awt.Graphics#setFont * @see #setTransform * @see #setComposite * @see #setClip */ public void drawString(String s, float x, float y) { try { if (customTextHandler != null && !textAsShapes) { customTextHandler.drawString(this, s, x, y); } else { fallbackTextHandler.drawString(this, s, x, y); } } catch (IOException ioe) { handleIOException(ioe); } } /** * Fills the interior of a Shape using the settings of the * Graphics2D context. The rendering attributes applied * include the Clip, Transform, * Paint, and Composite. * @param s the Shape to be filled * @see #setPaint * @see java.awt.Graphics#setColor * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip */ public void fill(Shape s) { preparePainting(); try { gen.saveGraphicsState(); AffineTransform trans = getTransform(); boolean newTransform = !trans.isIdentity(); if (newTransform) { gen.concatMatrix(trans); } Shape imclip = getClip(); if (shouldBeClipped(imclip, s)) { writeClip(imclip); } establishColor(getColor()); applyPaint(getPaint(), true); gen.writeln(gen.mapCommand("newpath")); int windingRule = processShape(s, true); doDrawing(true, false, windingRule == PathIterator.WIND_EVEN_ODD); gen.restoreGraphicsState(); } catch (IOException ioe) { handleIOException(ioe); } } /** * Commits a painting operation. * @param fill filling * @param stroke stroking * @param nonzero true if the non-zero winding rule should be used when filling * @exception IOException In case of an I/O problem */ protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) throws IOException { preparePainting(); if (fill) { if (stroke) { if (!nonzero) { gen.writeln(gen.mapCommand("gsave") + " " + gen.mapCommand("fill") + " " + gen.mapCommand("grestore") + " " + gen.mapCommand("stroke")); } else { gen.writeln(gen.mapCommand("gsave") + " " + gen.mapCommand("eofill") + " " + gen.mapCommand("grestore") + " " + gen.mapCommand("stroke")); } } else { if (!nonzero) { gen.writeln(gen.mapCommand("fill")); } else { gen.writeln(gen.mapCommand("eofill")); } } } else { // if(stroke) gen.writeln(gen.mapCommand("stroke")); } } /** * Returns the device configuration associated with this * Graphics2D. * @return the device configuration */ public GraphicsConfiguration getDeviceConfiguration() { return new GraphicsConfigurationWithoutTransparency(); } /** * Used to create proper font metrics */ private Graphics2D fmg; { BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); fmg = bi.createGraphics(); } /** * Gets the font metrics for the specified font. * @return the font metrics for the specified font. * @param f the specified font * @see java.awt.Graphics#getFont * @see java.awt.FontMetrics * @see java.awt.Graphics#getFontMetrics() */ public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { return fmg.getFontMetrics(f); } /** * Sets the paint mode of this graphics context to alternate between * this graphics context's current color and the new specified color. * This specifies that logical pixel operations are performed in the * XOR mode, which alternates pixels between the current color and * a specified XOR color. *

* When drawing operations are performed, pixels which are the * current color are changed to the specified color, and vice versa. *

* Pixels that are of colors other than those two colors are changed * in an unpredictable but reversible manner; if the same figure is * drawn twice, then all pixels are restored to their original values. * @param c1 the XOR alternation color */ public void setXORMode(Color c1) { System.err.println("NYI: setXORMode"); } /** * Copies an area of the component by a distance specified by * dx and dy. From the point specified * by x and y, this method * copies downwards and to the right. To copy an area of the * component to the left or upwards, specify a negative value for * dx or dy. * If a portion of the source rectangle lies outside the bounds * of the component, or is obscured by another window or component, * copyArea will be unable to copy the associated * pixels. The area that is omitted can be refreshed by calling * the component's paint method. * @param x the x coordinate of the source rectangle. * @param y the y coordinate of the source rectangle. * @param width the width of the source rectangle. * @param height the height of the source rectangle. * @param dx the horizontal distance to copy the pixels. * @param dy the vertical distance to copy the pixels. */ public void copyArea(int x, int y, int width, int height, int dx, int dy) { System.err.println("NYI: copyArea"); } /* --- for debugging public void transform(AffineTransform tx) { System.out.println("transform(" + toArray(tx) + ")"); super.transform(zx); } public void scale(double sx, double sy) { System.out.println("scale(" + sx + ", " + sy + ")"); super.scale(sx, sy); } public void translate(double tx, double ty) { System.out.println("translate(double " + tx + ", " + ty + ")"); super.translate(tx, ty); } public void translate(int tx, int ty) { System.out.println("translate(int " + tx + ", " + ty + ")"); super.translate(tx, ty); } */ }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy