Java/2D Graphics GUI/Paint

Материал из Java эксперт
Версия от 06:54, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Anti Alias

   
/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.ru/javaexamples2.
 */
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** A demonstration of anti-aliasing */
public class AntiAlias extends JPanel{
  static final int WIDTH = 650, HEIGHT = 350; // Size of our example
  public String getName() {
    return "AntiAliasing";
  }
  public int getWidth() {
    return WIDTH;
  }
  public int getHeight() {
    return HEIGHT;
  }
  /** Draw the example */
  public void paint(Graphics g1) {
    Graphics2D g = (Graphics2D) g1;
    BufferedImage image = // Create an off-screen image
    new BufferedImage(65, 35, BufferedImage.TYPE_INT_RGB);
    Graphics2D ig = image.createGraphics(); // Get its Graphics for drawing
    // Set the background to a gradient fill. The varying color of
    // the background helps to demonstrate the anti-aliasing effect
    ig.setPaint(new GradientPaint(0, 0, Color.black, 65, 35, Color.white));
    ig.fillRect(0, 0, 65, 35);
    // Set drawing attributes for the foreground.
    // Most importantly, turn on anti-aliasing.
    ig.setStroke(new BasicStroke(2.0f)); // 2-pixel lines
    ig.setFont(new Font("Serif", Font.BOLD, 18)); // 18-point font
    ig.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // Anti-alias!
        RenderingHints.VALUE_ANTIALIAS_ON);
    // Now draw pure blue text and a pure red oval
    ig.setColor(Color.blue);
    ig.drawString("Java", 9, 22);
    ig.setColor(Color.red);
    ig.drawOval(1, 1, 62, 32);
    // Finally, scale the image by a factor of 10 and display it
    // in the window. This will allow us to see the anti-aliased pixels
    g.drawImage(image, AffineTransform.getScaleInstance(10, 10), this);
    // Draw the image one more time at its original size, for comparison
    g.drawImage(image, 0, 0, this);
  }
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    f.setContentPane(new AntiAlias());
    f.setSize(400,400);
    f.setVisible(true);
  }
}



A panel that displays a paint sample.

  
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * ----------------
 * PaintSample.java
 * ----------------
 * (C) Copyright 2000-2004, by Object Refinery Limited.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: PaintSample.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 *
 */

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
/**
 * A panel that displays a paint sample.
 *
 * @author David Gilbert
 */
public class PaintSample extends JComponent {
    /** The paint. */
    private Paint paint;
    /** The preferred size of the component. */
    private Dimension preferredSize;
    /**
     * Standard constructor - builds a paint sample.
     *
     * @param paint   the paint to display.
     */
    public PaintSample(final Paint paint) {
        this.paint = paint;
        this.preferredSize = new Dimension(80, 12);
    }
    /**
     * Returns the current Paint object being displayed in the panel.
     *
     * @return the paint.
     */
    public Paint getPaint() {
        return this.paint;
    }
    /**
     * Sets the Paint object being displayed in the panel.
     *
     * @param paint  the paint.
     */
    public void setPaint(final Paint paint) {
        this.paint = paint;
        repaint();
    }
    /**
     * Returns the preferred size of the component.
     *
     * @return the preferred size.
     */
    public Dimension getPreferredSize() {
        return this.preferredSize;
    }
    /**
     * Fills the component with the current Paint.
     *
     * @param g  the graphics device.
     */
    public void paintComponent(final Graphics g) {
        final Graphics2D g2 = (Graphics2D) g;
        final Dimension size = getSize();
        final Insets insets = getInsets();
        final double xx = insets.left;
        final double yy = insets.top;
        final double ww = size.getWidth() - insets.left - insets.right - 1;
        final double hh = size.getHeight() - insets.top - insets.bottom - 1;
        final Rectangle2D area = new Rectangle2D.Double(xx, yy, ww, hh);
        g2.setPaint(this.paint);
        g2.fill(area);
        g2.setPaint(Color.black);
        g2.draw(area);
    }
}



Bad vs. Good Primitive Rendering

   
 
 
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
 * OptimalPrimitives.java
 *
 * Created on May 2, 2007, 11:06 AM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Chet
 */
public class OptimalPrimitives extends JComponent {
    
    private static final int LINE_X = 100;
    private static final int RECT_X = 200;
    private static final int TEXT_X = 250;
    private static final int BAD_Y = 60;
    private static final int GOOD_Y = 160;
    private static final int ITERATIONS = 1000;
    
    /** Creates a new instance of OptimalPrimitives */
    public OptimalPrimitives() {
    }
    
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        long startTime, endTime, totalTime;
        
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.BLACK);
        
        g.drawString("Bad vs. Good Primitive Rendering", 50, 20);
        g.drawString("(" + ITERATIONS + " iterations)", 100, 35);
        g.drawString("Bad: ", 10, BAD_Y + 30);
        g.drawString("Good: ", 10, GOOD_Y + 30);
        
        // Bad line
        Shape line = new Line2D.Double(LINE_X, BAD_Y, LINE_X + 50, 
                BAD_Y + 50);
        startTime = System.nanoTime();
        for (int i = 0; i < ITERATIONS; ++i) {
            g2d.draw(line);
        }
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        System.out.println("bad line = " + totalTime);
        g.drawString(totalTime + " ms", LINE_X, BAD_Y + 70);
        
        // Good line
        startTime = System.nanoTime();
        for (int i = 0; i < ITERATIONS; ++i) {
            g.drawLine(LINE_X, GOOD_Y, LINE_X + 50, GOOD_Y + 50);
        }
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        System.out.println("good line = " + totalTime);
        g.drawString(totalTime + " ms", LINE_X, GOOD_Y + 70);
        
        
        // Bad rect
        Shape rect = new Rectangle(RECT_X, BAD_Y, 50, 50);
        startTime = System.nanoTime();
        for (int i = 0; i < ITERATIONS; ++i) {
            g2d.fill(rect);
        }
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        System.out.println("bad rect = " + totalTime);
        g.drawString(totalTime + " ms", RECT_X, BAD_Y + 70);
        
        // Good rect
        startTime = System.nanoTime();
        for (int i = 0; i < ITERATIONS; ++i) {
            g.fillRect(RECT_X, GOOD_Y, 50, 50);
        }
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        System.out.println("good rect = " + totalTime);
        g.drawString(totalTime + " ms", RECT_X, GOOD_Y + 70);
    }
    
    private static void createAndShowGUI() {    
        JFrame f = new JFrame("OptimalPrimitives");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(320, 300);
        f.add(new OptimalPrimitives());
        f.setVisible(true);
    }
    
    public static void main(String args[]) {
        Runnable doCreateAndShowGUI = new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        };
        SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
}



Draw canvas with color and text

   
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class MyCanvas extends JComponent {
  private static Color m_tRed = new Color(255, 0, 0, 150);
  private static Color m_tGreen = new Color(0, 255, 0, 150);
  private static Color m_tBlue = new Color(0, 0, 255, 150);
  private static Font monoFont = new Font("Monospaced", Font.BOLD
      | Font.ITALIC, 36);
  private static Font sanSerifFont = new Font("SanSerif", Font.PLAIN, 12);
  private static Font serifFont = new Font("Serif", Font.BOLD, 24);
  private static ImageIcon jexpLogo = new ImageIcon("jexp.gif");
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    // draw entire component white
    g.setColor(Color.white);
    g.fillRect(0, 0, getWidth(), getHeight());
    // yellow circle
    g.setColor(Color.yellow);
    g.fillOval(0, 0, 240, 240);
    // magenta circle
    g.setColor(Color.magenta);
    g.fillOval(160, 160, 240, 240);
    // paint the icon below blue sqaure
    int w = jexpLogo.getIconWidth();
    int h = jexpLogo.getIconHeight();
    jexpLogo.paintIcon(this, g, 280 - (w / 2), 120 - (h / 2));
    // paint the icon below red sqaure
    jexpLogo.paintIcon(this, g, 120 - (w / 2), 280 - (h / 2));
    // transparent red square
    g.setColor(m_tRed);
    g.fillRect(60, 220, 120, 120);
    // transparent green circle
    g.setColor(m_tGreen);
    g.fillOval(140, 140, 120, 120);
    // transparent blue square
    g.setColor(m_tBlue);
    g.fillRect(220, 60, 120, 120);
    g.setColor(Color.black);
    g.setFont(monoFont);
    FontMetrics fm = g.getFontMetrics();
    w = fm.stringWidth("Java Source");
    h = fm.getAscent();
    g.drawString("Java Source", 120 - (w / 2), 120 + (h / 4));
    g.setFont(sanSerifFont);
    fm = g.getFontMetrics();
    w = fm.stringWidth("and");
    h = fm.getAscent();
    g.drawString("and", 200 - (w / 2), 200 + (h / 4));
    g.setFont(serifFont);
    fm = g.getFontMetrics();
    w = fm.stringWidth("Support.");
    h = fm.getAscent();
    g.drawString("Support.", 280 - (w / 2), 280 + (h / 4));
  }
  public Dimension getPreferredSize() {
    return new Dimension(400, 400);
  }
  public Dimension getMinimumSize() {
    return getPreferredSize();
  }
  public static void main(String args[]) {
    JFrame mainFrame = new JFrame("Graphics demo");
    mainFrame.getContentPane().add(new MyCanvas());
    mainFrame.pack();
    mainFrame.setVisible(true);
  }
}



Draw string

   
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class NotHelloWorldPanel extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawString("Java Source and Support", 75, 100);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("NotHelloWorld");
    frame.setSize(300, 200);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new NotHelloWorldPanel());
    frame.show();
  }
}



Graphics Util: draw shapes and text

     
/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.ru/logisim/. */
 
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class GraphicsUtil {
    public static final int H_LEFT = -1;
    public static final int H_CENTER = 0;
    public static final int H_RIGHT = 1;
    public static final int V_TOP = -1;
    public static final int V_CENTER = 0;
    public static final int V_BASELINE = 1;
    public static final int V_BOTTOM = 2;
    static public void switchToWidth(Graphics g, int width) {
        if(g instanceof Graphics2D) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setStroke(new BasicStroke((float) width));
        }
    }
    static public void drawCenteredArc(Graphics g, int x, int y,
            int r, int start, int dist) {
        g.drawArc(x - r, y - r, 2 * r, 2 * r, start, dist);
    }
    static public Rectangle getTextBounds(Graphics g, Font font,
            String text, int x, int y, int halign, int valign) {
        if(g == null) return new Rectangle(x, y, 0, 0);
        Font oldfont = g.getFont();
        if(font != null) g.setFont(font);
        Rectangle ret = getTextBounds(g, text, x, y, halign, valign);
        if(font != null) g.setFont(oldfont);
        return ret;
    }
    static public Rectangle getTextBounds(Graphics g, String text,
            int x, int y, int halign, int valign) {
        if(g == null) return new Rectangle(x, y, 0, 0);
        FontMetrics mets = g.getFontMetrics();
        int width = mets.stringWidth(text);
        int ascent = mets.getAscent();
        int height = ascent + mets.getDescent();
        Rectangle ret = new Rectangle(x, y, width, height);
        
        switch(halign) {
            case H_CENTER: ret.translate(-(width / 2), 0); break;
            case H_RIGHT:  ret.translate(-width, 0); break;
            default: ;
        }
        switch(valign) {
            case V_TOP:      break;
            case V_CENTER:   ret.translate(0, -(ascent / 2)); break;
            case V_BASELINE: ret.translate(0, -ascent); break;
            case V_BOTTOM:   ret.translate(0, -height); break;
            default: ;
        }
        return ret;
    }
    static public void drawText(Graphics g, Font font,
            String text, int x, int y, int halign, int valign) {
        Font oldfont = g.getFont();
        if(font != null) g.setFont(font);
        drawText(g, text, x, y, halign, valign);
        if(font != null) g.setFont(oldfont);
    }
    static public void drawText(Graphics g, String text,
            int x, int y, int halign, int valign) {
        if(text.length() == 0) return;
        Rectangle bd = getTextBounds(g, text, x, y, halign, valign);
        g.drawString(text, bd.x, bd.y + g.getFontMetrics().getAscent());
    }
    static public void drawCenteredText(Graphics g, String text,
            int x, int y) {
        drawText(g, text, x, y, H_CENTER, V_CENTER);
    }
    static public void drawArrow(Graphics g, int x0, int y0, int x1, int y1,
            int headLength, int headAngle) {
        double offs = headAngle * Math.PI / 180.0;
        double angle = Math.atan2(y0 - y1, x0 - x1);
        int[] xs = { x1 + (int) (headLength * Math.cos(angle + offs)), x1,
            x1 + (int) (headLength * Math.cos(angle - offs)) };
        int[] ys = { y1 + (int) (headLength * Math.sin(angle + offs)), y1,
            y1 + (int) (headLength * Math.sin(angle - offs)) };
        g.drawLine(x0, y0, x1, y1);
        g.drawPolyline(xs, ys, 3);
    }
}



Paints

   
/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.ru/javaexamples2.
 */
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.TexturePaint;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** A demonstration of Java2D transformations */
public class Paints extends JPanel {
  static final int WIDTH = 800, HEIGHT = 375; // Size of our example
  public String getName() {
    return "Paints";
  }
  public int getWidth() {
    return WIDTH;
  }
  public int getHeight() {
    return HEIGHT;
  }
  /** Draw the example */
  public void paint(Graphics g1) {
    Graphics2D g = (Graphics2D) g1;
    // Paint the entire background using a GradientPaint.
    // The background color varies diagonally from deep red to pale blue
    g.setPaint(new GradientPaint(0, 0, new Color(150, 0, 0), WIDTH, HEIGHT,
        new Color(200, 200, 255)));
    g.fillRect(0, 0, WIDTH, HEIGHT); // fill the background
    // Use a different GradientPaint to draw a box.
    // This one alternates between deep opaque green and transparent green.
    // Note: the 4th arg to Color() constructor specifies color opacity
    g.setPaint(new GradientPaint(0, 0, new Color(0, 150, 0), 20, 20,
        new Color(0, 150, 0, 0), true));
    g.setStroke(new BasicStroke(15)); // use wide lines
    g.drawRect(25, 25, WIDTH - 50, HEIGHT - 50); // draw the box
    // The glyphs of fonts can be used as Shape objects, which enables
    // us to use Java2D techniques with letters Just as we would with
    // any other shape. Here we get some letter shapes to draw.
    Font font = new Font("Serif", Font.BOLD, 10); // a basic font
    Font bigfont = // a scaled up version
    font.deriveFont(AffineTransform.getScaleInstance(30.0, 30.0));
    GlyphVector gv = bigfont.createGlyphVector(g.getFontRenderContext(),
        "JAV");
    Shape jshape = gv.getGlyphOutline(0); // Shape of letter J
    Shape ashape = gv.getGlyphOutline(1); // Shape of letter A
    Shape vshape = gv.getGlyphOutline(2); // Shape of letter V
    // We"re going to outline the letters with a 5-pixel wide line
    g.setStroke(new BasicStroke(5.0f));
    // We"re going to fake shadows for the letters using the
    // following Paint and AffineTransform objects
    Paint shadowPaint = new Color(0, 0, 0, 100); // Translucent black
    AffineTransform shadowTransform = AffineTransform.getShearInstance(
        -1.0, 0.0); // Shear to the right
    shadowTransform.scale(1.0, 0.5); // Scale height by 1/2
    // Move to the baseline of our first letter
    g.translate(65, 270);
    // Draw the shadow of the J shape
    g.setPaint(shadowPaint);
    g.translate(15, 20); // Compensate for the descender of the J
    // transform the J into the shape of its shadow, and fill it
    g.fill(shadowTransform.createTransformedShape(jshape));
    g.translate(-15, -20); // Undo the translation above
    // Now fill the J shape with a solid (and opaque) color
    g.setPaint(Color.blue); // Fill with solid, opaque blue
    g.fill(jshape); // Fill the shape
    g.setPaint(Color.black); // Switch to solid black
    g.draw(jshape); // And draw the outline of the J
    // Now draw the A shadow
    g.translate(75, 0); // Move to the right
    g.setPaint(shadowPaint); // Set shadow color
    g.fill(shadowTransform.createTransformedShape(ashape)); // draw shadow
    // Draw the A shape using a solid transparent color
    g.setPaint(new Color(0, 255, 0, 125)); // Transparent green as paint
    g.fill(ashape); // Fill the shape
    g.setPaint(Color.black); // Switch to solid back
    g.draw(ashape); // Draw the outline
    // Move to the right and draw the shadow of the letter V
    g.translate(175, 0);
    g.setPaint(shadowPaint);
    g.fill(shadowTransform.createTransformedShape(vshape));
    // We"re going to fill the next letter using a TexturePaint, which
    // repeatedly tiles an image. The first step is to obtain the image.
    // We could load it from an image file, but here we create it
    // ourselves by drawing a into an off-screen image. Note that we use
    // a GradientPaint to fill the off-screen image, so the fill pattern
    // combines features of both Paint classes.
    BufferedImage tile = // Create an image
    new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
    Graphics2D tg = tile.createGraphics(); // Get its Graphics for drawing
    tg.setColor(Color.pink);
    tg.fillRect(0, 0, 50, 50); // Fill tile background with pink
    tg.setPaint(new GradientPaint(40, 0, Color.green, // diagonal gradient
        0, 40, Color.gray)); // green to gray
    tg.fillOval(5, 5, 40, 40); // Draw a circle with this gradient
    // Use this new tile to create a TexturePaint and fill the letter V
    g.setPaint(new TexturePaint(tile, new Rectangle(0, 0, 50, 50)));
    g.fill(vshape); // Fill letter shape
    g.setPaint(Color.black); // Switch to solid black
    g.draw(vshape); // Draw outline of letter
    // Move to the right and draw the shadow of the final A
    g.translate(160, 0);
    g.setPaint(shadowPaint);
    g.fill(shadowTransform.createTransformedShape(ashape));

    g.fill(ashape); // Fill letter A
    g.setPaint(Color.black); // Revert to solid black
    g.draw(ashape); // Draw the outline of the A
  }
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    f.setContentPane(new Paints());
    f.setSize(800,375);
    f.setVisible(true);
  }
}



Picture Scaler

   
 
 
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
 * PictureScaler.java
 *
 * Created on May 1, 2007, 5:03 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Chet
 */
public class PictureScaler extends JComponent {
    private static BufferedImage picture = null;
    private static final int PADDING = 10;
    private static final double SCALE_FACTOR = .05;
    private int scaleW, scaleH;
    
    /** Creates a new instance of PictureScaler */
    public PictureScaler() {
        try {
            URL url = getClass().getResource("BB.jpg");
            picture = ImageIO.read(url);
            scaleW = (int)(SCALE_FACTOR * picture.getWidth());
            scaleH = (int)(SCALE_FACTOR * picture.getHeight());
            System.out.println("w, h = " + picture.getWidth() + ", " + picture.getHeight());
            setPreferredSize(new Dimension(PADDING + (5 * (scaleW + PADDING)), 
                    scaleH + (4 * PADDING)));
        } catch (Exception e) {
            System.out.println("Problem reading image file: " + e);
            System.exit(0);
        }
    }
    /**
     * Convenience method that returns a scaled instance of the
     * provided BufferedImage.
     * 
     * 
     * @param img the original image to be scaled
     * @param targetWidth the desired width of the scaled instance,
     *    in pixels
     * @param targetHeight the desired height of the scaled instance,
     *    in pixels
     * @param hint one of the rendering hints that corresponds to
     *    RenderingHints.KEY_INTERPOLATION (e.g.
     *    RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
     *    RenderingHints.VALUE_INTERPOLATION_BILINEAR,
     *    RenderingHints.VALUE_INTERPOLATION_BICUBIC)
     * @param progressiveBilinear if true, this method will use a multi-step
     *    scaling technique that provides higher quality than the usual
     *    one-step technique (only useful in down-scaling cases, where
     *    targetWidth or targetHeight is
     *    smaller than the original dimensions)
     * @return a scaled version of the original BufferedImage
     */
    public BufferedImage getFasterScaledInstance(BufferedImage img,
            int targetWidth, int targetHeight, Object hint,
            boolean progressiveBilinear)
    {
        int type = (img.getTransparency() == Transparency.OPAQUE) ?
            BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = img;
        BufferedImage scratchImage = null;
        Graphics2D g2 = null;
        int w, h;
        int prevW = ret.getWidth();
        int prevH = ret.getHeight();
        boolean isTranslucent = img.getTransparency() !=  Transparency.OPAQUE; 
        if (progressiveBilinear) {
            // Use multi-step technique: start with original size, then
            // scale down in multiple passes with drawImage()
            // until the target size is reached
            w = img.getWidth();
            h = img.getHeight();
        } else {
            // Use one-step technique: scale directly from original
            // size to target size with a single drawImage() call
            w = targetWidth;
            h = targetHeight;
        }
        
        do {
            if (progressiveBilinear && w > targetWidth) {
                w /= 2;
                if (w < targetWidth) {
                    w = targetWidth;
                }
            }
            if (progressiveBilinear && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }
            if (scratchImage == null || isTranslucent) {
                // Use a single scratch buffer for all iterations
                // and then copy to the final, correctly-sized image
                // before returning
                scratchImage = new BufferedImage(w, h, type);
                g2 = scratchImage.createGraphics();
            }
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, 0, 0, prevW, prevH, null);
            prevW = w;
            prevH = h;
            ret = scratchImage;
        } while (w != targetWidth || h != targetHeight);
        
        if (g2 != null) {
            g2.dispose();
        }
        // If we used a scratch buffer that is larger than our target size,
        // create an image of the right size and copy the results into it
        if (targetWidth != ret.getWidth() || targetHeight != ret.getHeight()) {
            scratchImage = new BufferedImage(targetWidth, targetHeight, type);
            g2 = scratchImage.createGraphics();
            g2.drawImage(ret, 0, 0, null);
            g2.dispose();
            ret = scratchImage;
        }
        
        return ret;
    }
    
    /**
     * Render all scaled versions 10 times, timing each version and 
     * reporting the results below the appropriate scaled image.
     */
    protected void paintComponent(Graphics g) {
        // Scale with NEAREST_NEIGHBOR
        int xLoc = PADDING, yLoc = PADDING;
        long startTime, endTime;
        float totalTime;
        int iterations = 10;
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        startTime = System.nanoTime();
        for (int i = 0; i < iterations; ++i) {
            g.drawImage(picture, xLoc, yLoc, scaleW, scaleH, null);
        }
        endTime = System.nanoTime();
        totalTime = (float)((endTime - startTime) / 1000000) / iterations;
        g.drawString("NEAREST ", xLoc, yLoc + scaleH + PADDING);
        g.drawString(Float.toString(totalTime) + " ms", 
                xLoc, yLoc + scaleH + PADDING + 10);
        System.out.println("NEAREST: " + ((endTime - startTime) / 1000000));
        
        // Scale with BILINEAR
        xLoc += scaleW + PADDING;
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        startTime = System.nanoTime();
        for (int i = 0; i < iterations; ++i) {
            g.drawImage(picture, xLoc, yLoc, scaleW, scaleH, null);
        }
        endTime = System.nanoTime();
        totalTime = (float)((endTime - startTime) / 1000000) / iterations;
        g.drawString("BILINEAR", xLoc, yLoc + scaleH + PADDING);
        g.drawString(Float.toString(totalTime) + " ms", 
                xLoc, yLoc + scaleH + PADDING + 10);
        System.out.println("BILINEAR: " + ((endTime - startTime) / 1000000));
        // Scale with BICUBIC
        xLoc += scaleW + PADDING;
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        startTime = System.nanoTime();
        for (int i = 0; i < iterations; ++i) {
            g.drawImage(picture, xLoc, yLoc, scaleW, scaleH, null);
        }
        endTime = System.nanoTime();
        totalTime = (float)((endTime - startTime) / 1000000) / iterations;
        g.drawString("BICUBIC", xLoc, yLoc + scaleH + PADDING);
        g.drawString(Float.toString(totalTime) + " ms", 
                xLoc, yLoc + scaleH + PADDING + 10);
        System.out.println("BICUBIC: " + ((endTime - startTime) / 1000000));
        // Scale with getScaledInstance
        xLoc += scaleW + PADDING;
        startTime = System.nanoTime();
        for (int i = 0; i < iterations; ++i) {
            Image scaledPicture = picture.getScaledInstance(scaleW, scaleH, 
                    Image.SCALE_AREA_AVERAGING);
            g.drawImage(scaledPicture, xLoc, yLoc, null);
        }
        endTime = System.nanoTime();
        totalTime = (float)((endTime - startTime) / 1000000) / iterations;
        g.drawString("getScaled", xLoc, yLoc + scaleH + PADDING);
        g.drawString(Float.toString(totalTime) + " ms", 
                xLoc, yLoc + scaleH + PADDING + 10);
        System.out.println("getScaled: " + ((endTime - startTime) / 1000000));
        
        // Scale with Progressive Bilinear
        xLoc += scaleW + PADDING;
        startTime = System.nanoTime();
        for (int i = 0; i < iterations; ++i) {
            Image scaledPicture = getFasterScaledInstance(picture, scaleW, scaleH, 
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
            g.drawImage(scaledPicture, xLoc, yLoc, null);
        }
        endTime = System.nanoTime();
        totalTime = (float)((endTime - startTime) / 1000000) / iterations;
        g.drawString("Progressive", xLoc, yLoc + scaleH + PADDING);
        g.drawString(Float.toString(totalTime) + " ms", 
                xLoc, yLoc + scaleH + PADDING + 10);
        System.out.println("Progressive: " + ((endTime - startTime) / 1000000));
    }
    
    private static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setLayout(new BorderLayout());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        PictureScaler test = new PictureScaler();
        //f.setSize(scaleW + (4 * PADDING), scaleH + (4 * PADDING));
        f.add(test);        
        f.validate();
        f.pack();
        f.setVisible(true);
    }
    
    public static void main(String args[]) {
        Runnable doCreateAndShowGUI = new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        };
        SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
}



Plot

   
/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */
import javax.rum.*;
import java.util.*;
import java.io.*;
import java.lang.*;
import java.awt.*;
import java.awt.event.*;

/** Main program, driver for Plotter class.
 * This is to simulate a larger graphics application such as GnuPlot.
 */
public class PlotDriver {
  /** Construct a Plotter driver, and try it out. */
  public static void main(String[] argv)
  {
    Plotter r ;
//    if (argv.length != 1) {
  //    System.err.println("Usage: PlotDriver driverclass");
    //  return;
//    }
    try {
      Class c = Class.forName("PlotterAWT");
      Object o = c.newInstance();
      if (!(o instanceof Plotter))
        throw new ClassNotFoundException("Not instanceof Plotter");
      r = (Plotter)o;
    } catch (ClassNotFoundException e) {
      System.err.println("Sorry, "+argv[0]+" not a plotter class");
      return;
    } catch (Exception e) {
      e.printStackTrace();
      return;
    }
    r.penDown();
    r.penColor(1);
    r.moveTo(200, 200);
    r.penColor(2);
    r.drawBox(123, 200);
    r.rmoveTo(10, 20);
    r.penColor(3);
    r.drawBox(123, 200);
    r.penUp();
    r.moveTo(300, 100);
    r.penDown();
    r.setFont("Helvetica", 14);
    r.drawString("Hello World");
    r.penColor(4);
    r.drawBox(10, 10);
  }
}
/**
 * Plotter abstract class. Must be subclassed 
 * for X, DOS, Penman, HP plotter, etc.
 *
 * Coordinate space: X = 0 at left, increases to right.
 *    Y = 0 at top, increases downward (same as AWT).
 *
 * @author  Ian F. Darwin
 */
abstract class Plotter {
  public final int MAXX = 800;
  public final int MAXY = 600;
  /** Current X co-ordinate (same reference frame as AWT!) */
  protected int curx;
  /** Current Y co-ordinate (same reference frame as AWT!) */
  protected int cury;
  /** The current state: up or down */
  protected boolean penIsUp;
  /** The current color */
  protected int penColor;
  Plotter() {
    penIsUp = true;
    curx = 0; cury = 0;
  }
  abstract void rmoveTo(int incrx, int incry);
  abstract void moveTo(int absx, int absy);
  abstract void penUp();
  abstract void penDown();
  abstract void penColor(int c);
  abstract void setFont(String fName, int fSize);
  abstract void drawString(String s);
  /* Concrete methods */
  /** Draw a box of width w and height h */
  public void drawBox(int w, int h) {
    penDown();
    rmoveTo(w, 0);
    rmoveTo(0, h);
    rmoveTo(-w, 0);
    rmoveTo(0, -h);
    penUp();
  }
  /** Draw a box given an AWT Dimension for its size */
  public void drawBox(java.awt.Dimension d) {
    drawBox(d.width, d.height);
  }
  /** Draw a box given an AWT Rectangle for its location and size */
  public void drawBox(java.awt.Rectangle r) {
    moveTo(r.x, r.y);
    drawBox(r.width, r.height);
  }
}
/**
 * A Plotter subclass for drawing into an AWT Window. Reflecting back
 * to AWT gives us a "known working" plotter to test on.
 * You can also steal this as a basis for your own plotter driver.
 * @author  Ian Darwin
 */
class PlotterAWT extends Plotter {
  Frame f;
  PCanvas p;
  Graphics g;
  Font font;
  FontMetrics fontMetrics;
  PlotterAWT() {
    super();
    f = new Frame("Plotter");
    p = new PCanvas(MAXX, MAXY);
    f.add(p);
    f.pack();
    f.setVisible(true);
    g = p.getOsGraphics();
  }
  public void drawBox(int w, int h) {
    g.drawRect(curx, cury, w, h);
    p.repaint();
  }
  public void rmoveTo(int incrx, int incry){
    moveTo(curx += incrx, cury += incry);
  }
  public void moveTo(int absx, int absy){
    if (!penIsUp)
      g.drawLine(curx, cury, absx, absy);
    curx = absx;
    cury = absy;
  }
  public void setdir(float deg){}
  void penUp(){ penIsUp = true; }
  void penDown(){ penIsUp = false; }
  void penColor(int c){
    switch(c) {
    case 0: g.setColor(Color.white); break;
    case 1: g.setColor(Color.black); break;
    case 2: g.setColor(Color.red); break;
    case 3: g.setColor(Color.green); break;
    case 4: g.setColor(Color.blue); break;
    default: g.setColor(new Color(c)); break;
    }
  }
  void setFont(String fName, int fSize) {
    font = new Font(fName, Font.BOLD, fSize);
    fontMetrics = p.getFontMetrics(font);
  }
  void drawString(String s) {
    g.drawString(s, curx, cury);
    curx += fontMetrics.stringWidth(s);
  }
  /** A Member Class that contains an off-screen Image that is
   * drawn into; this component"s paint() copies from there to
   * the screen. This avoids having to keep a list of all the
   * things that have been drawn.
   */
  class PCanvas extends Canvas {
    Image offScreenImage;
    int width;
    int height;
    Graphics pg;
    PCanvas(int w, int h) {
      width = w;
      height = h;
      setBackground(Color.white);
      setForeground(Color.red);
    }
    public Graphics getOsGraphics() {
      return pg;
    }
    /** This is called by AWT after the native window peer is created,
     * and before paint() is called for the first time, so
     * is a good time to create images and the like.
     */
    public void addNotify() {
      super.addNotify();
      offScreenImage = createImage(width, height);
      // assert (offScreenImage != null);
      pg = offScreenImage.getGraphics();
    }
    public void paint(Graphics pg) {
      pg.drawImage(offScreenImage, 0, 0, null);
    }
    public Dimension getPreferredSize() {
      return new Dimension(width, height);
    }
  }
}
/** Plotter class for testing higher-level software. */
class PlotterDummy extends Plotter {
  /** Constructor: nothing to do */
  PlotterDummy() {
    super();
  }
  /** move to absolute location */
  void moveTo(int absx, int absy) {
    curx = absx;
    cury = absy;
    System.out.println("moveTo ["+curx+","+cury+"]");
  }
  /** move to relative location */
  void rmoveTo(int incrx, int incry) {
    curx += incrx;
    cury += incry;
    System.out.println("rmoveTo ["+curx+","+cury+"]");
  }
  public void setFont(java.lang.String fName, int fSize) {
    System.out.println("set Font to " + fName);
  }
  public void drawString(java.lang.String s) {
    System.out.println("Draw the string \"" + s + "\"");
  }
  void setPenState(boolean up) {
    penIsUp = up;
    System.out.println("Pen Up is ["+penIsUp+"]");
  }
  void penUp() {
    setPenState(true);
  }
  void penDown() {
    setPenState(false);
  }
  void penColor(int c) {
    penColor = c;
    System.out.println("PenColor is ["+penColor+"]");
  }
}
/**
 * A Plotter subclass for drawing on a Penman plotter.
 * These were made in the UK and sold into North American markets.
 * It is a little "turtle" style robot plotter that communicates
 * over a serial port. For this, we use the "Java Communicatons" API.
 * Java Communications is a "standard extention" and must be downloaded
 * and installed separately from the JDK before you can even compile this 
 * program.
 *
 * @author  Ian Darwin, http://www.darwinsys.ru/
 */
class Penman extends Plotter {
  private final String OK_PROMPT = "\r\n!";
  private final int MAX_REPLY_BYTES = 50;  // paranoid upper bound
  private SerialPort tty;
  private DataInputStream is;
  private DataOutputStream os;
  /** Construct a Penman plotter object */
  public Penman() throws NoSuchPortException,PortInUseException,
      IOException,UnsupportedCommOperationException {
    super();
    init_comm("COM2");    // setup serial commx
    init_plotter();    // set plotter to good state
  }
  private void init_plotter() {
    send("I"); expect("!");  // eat VERSION etc., up to !
    send("I"); expect("!");  // wait for it!
    send("H");    // find home position
    expect("!");  // wait for it!
    send("A");    // Set to use absolute coordinates
    expect("!");
    curx = cury = 0;
    penUp();
  }
  //
  // PUBLIC DRAWING ROUTINES
  //
  public void setFont(String fName, int fSize) {
    // Font name is ignored for now...
    // Penman"s size is in mm, fsize in points (inch/72).
    int size = (int)(fSize*25.4f/72);
    send("S"+size + ","); expect(OK_PROMPT);
    System.err.println("Font set request: " + fName + "/" + fSize);
  }
  public void drawString(String mesg) {
    send("L" + mesg + "\r"); expect(OK_PROMPT);
  }
  /** Move to a relative location */
  public void rmoveTo(int incrx, int incry){
    moveTo(curx + incrx, cury + incry);
  }
  /** move to absolute location */
  public void moveTo(int absx, int absy) {
    System.err.println("moveTo ["+absx+","+absy+"]");
    curx = absx;
    cury = absy;
    send("M" + curx + "," + cury + ","); expect(OK_PROMPT);
  }
  private void setPenState(boolean up) {
    penIsUp = up;
    System.err.println("Pen Up is ["+penIsUp+"]");
  }
  public void penUp() {
    setPenState(true);
    send("U"); expect(OK_PROMPT);
  }
  public void penDown() {
    setPenState(false);
    send("D"); expect(OK_PROMPT);
  }
  public void penColor(int c) {
    penColor = (c%3)+1;    // only has 3 pens, 4->1
    System.err.println("PenColor is ["+penColor+"]");
    send("P" + c + ","); expect(OK_PROMPT);
  }
  //
  // PRIVATE COMMUNICATION ROUTINES
  //
  /** Set up communication. 
   * <br/>
   * XXX: Should probably re-use CommPortOpen instead.
   */
  private void init_comm(String portName) throws NoSuchPortException,PortInUseException,
      IOException,UnsupportedCommOperationException {
    // get list of ports available on this particular computer.
    // Enumeration pList = CommPortIdentifier.getPortIdentifiers();
    // Print the list. A GUI program would put these in a chooser!
    // while (pList.hasMoreElements()) {
      // CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement();
      // System.err.println("Port " + cpi.getName());
    // }
    
    // Open a port. 
    CommPortIdentifier port =
      CommPortIdentifier.getPortIdentifier(portName);
    // This form of open takes an Application Name and a timeout.
    tty = (SerialPort) port.open("Penman Driver", 1000);
    // set up the serial port
    tty.setSerialPortParams(9600, SerialPort.DATABITS_8,
      SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
    tty.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_OUT|
      SerialPort.FLOWCONTROL_RTSCTS_OUT);
    // Get the input and output streams
    is = new DataInputStream(tty.getInputStream());
    os = new DataOutputStream(tty.getOutputStream());
  }
  /** Send a command to the plotter. Although the argument is a String,
   * we send each char as a *byte*, so avoid 16-bit characters!
   * Not that it matters: the Penman only knows about 8-bit chars.
   */
  private  void send(String s) {
    System.err.println("sending " + s + "...");
    try {
      for (int i=0; i<s.length(); i++)
        os.writeByte(s.charAt(i));
    } catch(IOException e) {
      e.printStackTrace();
    }
  }
  /** Expect a given CHAR for a result */
  private  void expect(char s) {
    byte b;
    try {
      for (int i=0; i<MAX_REPLY_BYTES; i++){
        if ((b = is.readByte()) == s) {
            return;
        }
        System.err.print((char)b);
      }
    } catch (IOException e) {
      System.err.println("Penman:expect(char "+s+"): Read failed");
      System.exit(1);
    }
    System.err.println("ARGHH!");
  }
  /** Expect a given String for a result */
  private  void expect(String s) {
    byte ans[] = new byte[s.length()];
    System.err.println("expect " + s + " ...");
    try {
      is.read(ans);
    } catch (IOException e) {
      System.err.println("Penman:expect(String "+s+"): Read failed");
      System.exit(1);
    };
    for (int i=0; i<s.length() && i<ans.length; i++)
      if (ans[i] != s.charAt(i)) {
        System.err.println("MISMATCH");
        break;
      }
    System.err.println("GOT: " + new String(ans));
  }
}



Program to draw grids

   
/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */
import java.awt.Canvas;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
 * Program to draw grids.
 * 
 * @author Ian Darwin, http://www.darwinsys.ru/
 */
class GridsCanvas extends Canvas {
  int width, height;
  int rows;
  int cols;
  GridsCanvas(int w, int h, int r, int c) {
    setSize(width = w, height = h);
    rows = r;
    cols = c;
  }
  public void paint(Graphics g) {
    int i;
    width = getSize().width;
    height = getSize().height;
    // draw the rows
    int rowHt = height / (rows);
    for (i = 0; i < rows; i++)
      g.drawLine(0, i * rowHt, width, i * rowHt);
    // draw the columns
    int rowWid = width / (cols);
    for (i = 0; i < cols; i++)
      g.drawLine(i * rowWid, 0, i * rowWid, height);
  }
}
/** This is the demo class. */
public class Grids extends Frame {
  /*
   * Construct a GfxDemo2 given its title, width and height. Uses a
   * GridBagLayout to make the Canvas resize properly.
   */
  Grids(String title, int w, int h, int rows, int cols) {
    setTitle(title);
    // Now create a Canvas and add it to the Frame.
    GridsCanvas xyz = new GridsCanvas(w, h, rows, cols);
    add(xyz);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    // Normal end ... pack it up!
    pack();
  }
  public static void main(String[] a) {
    new Grids("Test", 300, 300, 5, 10).setVisible(true);
  }
}



Radial Gradient

   
 
 
/*
 * Copyright (c) 2007, Romain Guy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.ruposite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
 *
 * @author Romain GUy
 */
public class RadialGradientApp extends JFrame {
    
    /** Creates a new instance of RadialGradientApp */
    public RadialGradientApp() {
        super("Radial Gradient");
        
        JPanel panel = new JPanel();
        panel.add(new SphereComponent());
        add(panel);
        
        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new RadialGradientApp().setVisible(true);
            }
        });
    }
}
/*
 * Copyright (c) 2007, Romain Guy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Romain Guy
 */
 class SphereComponent extends JComponent {
    
    /** Creates a new instance of SphereComponent */
    public SphereComponent() {
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(120, 120);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        setFont(getFont().deriveFont(70.f).deriveFont(Font.BOLD));
        
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        
        // Retains the previous state
        Paint oldPaint = g2.getPaint();
        // Fills the circle with solid blue color
        g2.setColor(new Color(0x0153CC));
        g2.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
        
        // Adds shadows at the top
        Paint p;
        p = new GradientPaint(0, 0, new Color(0.0f, 0.0f, 0.0f, 0.4f),
                0, getHeight(), new Color(0.0f, 0.0f, 0.0f, 0.0f));
        g2.setPaint(p);
        g2.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
        
        // Adds highlights at the bottom 
        p = new GradientPaint(0, 0, new Color(1.0f, 1.0f, 1.0f, 0.0f),
                0, getHeight(), new Color(1.0f, 1.0f, 1.0f, 0.4f));
        g2.setPaint(p);
        g2.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
        
        // Creates dark edges for 3D effect
        p = new RadialGradientPaint(new Point2D.Double(getWidth() / 2.0,
                getHeight() / 2.0), getWidth() / 2.0f,
                new float[] { 0.0f, 1.0f },
                new Color[] { new Color(6, 76, 160, 127),
                    new Color(0.0f, 0.0f, 0.0f, 0.8f) });
        g2.setPaint(p);
        g2.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
        
        // Adds oval inner highlight at the bottom
        p = new RadialGradientPaint(new Point2D.Double(getWidth() / 2.0,
                getHeight() * 1.5), getWidth() / 2.3f,
                new Point2D.Double(getWidth() / 2.0, getHeight() * 1.75 + 6),
                new float[] { 0.0f, 0.8f },
                new Color[] { new Color(64, 142, 203, 255),
                    new Color(64, 142, 203, 0) },
                RadialGradientPaint.CycleMethod.NO_CYCLE,
                RadialGradientPaint.ColorSpaceType.SRGB,
                AffineTransform.getScaleInstance(1.0, 0.5));
        g2.setPaint(p);
        g2.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
        
        // Adds oval specular highlight at the top left
        p = new RadialGradientPaint(new Point2D.Double(getWidth() / 2.0,
                getHeight() / 2.0), getWidth() / 1.4f,
                new Point2D.Double(45.0, 25.0),
                new float[] { 0.0f, 0.5f },
                new Color[] { new Color(1.0f, 1.0f, 1.0f, 0.4f),
                    new Color(1.0f, 1.0f, 1.0f, 0.0f) },
                RadialGradientPaint.CycleMethod.NO_CYCLE);
        g2.setPaint(p);
        g2.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
        
        // Restores the previous state
        g2.setPaint(oldPaint);
        
        // Draws the logo        
//        FontRenderContext context = g2.getFontRenderContext();
//        TextLayout layout = new TextLayout("R", getFont(), context);
//        Rectangle2D bounds = layout.getBounds();
//        
//        float x = (getWidth() - (float) bounds.getWidth()) / 2.0f;
//        float y = (getHeight() + (float) bounds.getHeight()) / 2.0f;
//        
//        g2.setColor(Color.WHITE);
//        layout.draw(g2, x, y);
//        
//        Area shadow = new Area(layout.getOutline(null));
//        shadow.subtract(new Area(layout.getOutline(AffineTransform.getTranslateInstance(1.0, 1.0))));
//        g2.setColor(Color.BLACK);
//        g2.translate(x, y);
//        g2.fill(shadow);
//        g2.translate(-x, -y);
    }
}



Reads a Paint object that has been serialised

  
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * ------------
 * IOUtils.java
 * ------------
 * (C)opyright 2002-2004, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: IOUtils.java,v 1.8 2009/01/22 08:34:58 taqua Exp $
 *
 * Changes
 * -------
 * 26-Jan-2003 : Initial version
 * 23-Feb-2003 : Documentation
 * 25-Feb-2003 : Fixed Checkstyle issues (DG);
 * 29-Apr-2003 : Moved to jcommon
 * 04-Jan-2004 : Fixed JDK 1.2.2 issues with createRelativeURL;
 *               added support for query strings within these urls (TM);
 */

public class Main {
  /**
   * Returns <code>true</code> if a class implements <code>Serializable</code>
   * and <code>false</code> otherwise.
   *
   * @param c  the class.
   *
   * @return A boolean.
   */
  public static boolean isSerializable(final Class c) {
      /**
      final Class[] interfaces = c.getInterfaces();
      for (int i = 0; i < interfaces.length; i++) {
          if (interfaces[i].equals(Serializable.class)) {
              return true;
          }
      }
      Class cc = c.getSuperclass();
      if (cc != null) {
          return isSerializable(cc);
      }
       */
      return (Serializable.class.isAssignableFrom(c));
  }
  /**
   * Reads a <code>Paint</code> object that has been serialised by the
   * {@link SerialUtilities#writePaint(Paint, ObjectOutputStream)} method.
   *
   * @param stream  the input stream (<code>null</code> not permitted).
   *
   * @return The paint object (possibly <code>null</code>).
   *
   * @throws IOException  if there is an I/O problem.
   * @throws ClassNotFoundException  if there is a problem loading a class.
   */
  public static Paint readPaint(final ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      Paint result = null;
      final boolean isNull = stream.readBoolean();
      if (!isNull) {
          final Class c = (Class) stream.readObject();
          if (isSerializable(c)) {
              result = (Paint) stream.readObject();
          }
          else if (c.equals(GradientPaint.class)) {
              final float x1 = stream.readFloat();
              final float y1 = stream.readFloat();
              final Color c1 = (Color) stream.readObject();
              final float x2 = stream.readFloat();
              final float y2 = stream.readFloat();
              final Color c2 = (Color) stream.readObject();
              final boolean isCyclic = stream.readBoolean();
              result = new GradientPaint(x1, y1, c1, x2, y2, c2, isCyclic);
          }
      }
      return result;
  }
  /**
   * Serialises a <code>Paint</code> object.
   *
   * @param paint  the paint object (<code>null</code> permitted).
   * @param stream  the output stream (<code>null</code> not permitted).
   *
   * @throws IOException if there is an I/O error.
   */
  public static void writePaint(final Paint paint,
                                final ObjectOutputStream stream)
      throws IOException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      if (paint != null) {
          stream.writeBoolean(false);
          stream.writeObject(paint.getClass());
          if (paint instanceof Serializable) {
              stream.writeObject(paint);
          }
          else if (paint instanceof GradientPaint) {
              final GradientPaint gp = (GradientPaint) paint;
              stream.writeFloat((float) gp.getPoint1().getX());
              stream.writeFloat((float) gp.getPoint1().getY());
              stream.writeObject(gp.getColor1());
              stream.writeFloat((float) gp.getPoint2().getX());
              stream.writeFloat((float) gp.getPoint2().getY());
              stream.writeObject(gp.getColor2());
              stream.writeBoolean(gp.isCyclic());
          }
      }
      else {
          stream.writeBoolean(true);
      }
  }
}



Rotation About Center

   
 
 
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
 * RotationAboutCenter.java
 *
 * Created on May 1, 2007, 4:14 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Chet
 */
public class RotationAboutCenter extends JComponent {
    
    /** Creates a new instance of RotationAboutCenter */
    public RotationAboutCenter() {
    }
    
    protected void paintComponent(Graphics g) {
        Graphics2D g2d;
        g2d = (Graphics2D)g.create();
        
        // Erase background to white
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, getWidth(), getHeight());
        
        // base rectangle
        g2d.setColor(Color.GRAY.brighter());
        g2d.fillRect(50, 50, 50, 50);
        
        // rotated 45 degrees around origin
        g2d.rotate(Math.toRadians(45));
        g2d.setColor(Color.GRAY.darker());
        g2d.fillRect(50, 50, 50, 50);
        
        // rotated 45 degrees about center of rect
        g2d = (Graphics2D)g.create();
        g2d.rotate(Math.toRadians(45), 75, 75);
        g2d.setColor(Color.BLACK);
        g2d.fillRect(50, 50, 50, 50);
        // done with g2d, dispose it
        g2d.dispose();
    }
    
    private static void createAndShowGUI() {    
        JFrame f = new JFrame("Rotation");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(200, 200);
        f.add(new RotationAboutCenter());
        f.setVisible(true);
    }
    
    public static void main(String args[]) {
        Runnable doCreateAndShowGUI = new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        };
        SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
}



Safe Repaint

   
 
 
 
/*
 * Copyright (c) 2007, Romain Guy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import java.awt.*;
import javax.swing.*;

/**
 * @author Romain Guy
 */
public class SafeRepaint extends JFrame {
    private SafeComponent safeComponent;
    public SafeRepaint() {
        super("Safe Repaint");
        safeComponent = new SafeComponent();
        add(safeComponent);
        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    safeComponent.repaint();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
            }
        }).start();
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                SafeRepaint repaint = new SafeRepaint();
                repaint.setVisible(true);
            }
        });
    }
}
/*
 * Copyright (c) 2007, Romain Guy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @author Romain Guy
 */
class SafeComponent extends JLabel {
    public SafeComponent() {
        super("Safe Repaint");
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println(SwingUtilities.isEventDispatchThread());
    }
}



Scale Test

   
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
 * ScaleTest_2008.java
 *
 * Created on May 1, 2007, 4:42 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Chet
 */
public class ScaleTest_2008 extends JComponent {
    
    private static final int FULL_SIZE = 190;
    private static final int PADDING = 5;
    private static final int QUAD_SIZE = FULL_SIZE / 2;
    private static final double SCALE_FACTOR = .17;
    private static BufferedImage originalImage = 
            new BufferedImage(FULL_SIZE, FULL_SIZE, BufferedImage.TYPE_INT_RGB);
    boolean originalImagePainted = false;
    
    /**
     * Paints the test image that will be downscaled and timed by the various
     * scaling methods. A different image is rendered into each of the four
     * quadrants of this image: RGB stripes, a picture, vector art, and 
     * a black and white grid.
     */
    private void paintOriginalImage() {
        Graphics g = originalImage.getGraphics();
        // Erase to black
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, FULL_SIZE, FULL_SIZE);
        
        // RGB quadrant
        for (int i = 0; i < QUAD_SIZE; i += 3) {
            int x = i;
            g.setColor(Color.RED);
            g.drawLine(x, 0, x, QUAD_SIZE);
            x++;
            g.setColor(Color.GREEN);
            g.drawLine(x, 0, x, QUAD_SIZE);
            x++;
            g.setColor(Color.BLUE);
            g.drawLine(x, 0, x, QUAD_SIZE);
        }
        
        // Picture quadrant
        try {
            URL url = getClass().getResource("BBGrayscale.png");
            BufferedImage picture = ImageIO.read(url);
            // Center picture in quadrant area
            int xDiff = QUAD_SIZE - picture.getWidth();
            int yDiff = QUAD_SIZE - picture.getHeight();
            g.drawImage(picture, QUAD_SIZE + xDiff/2, yDiff/2, null);
        } catch (Exception e) {
            System.out.println("Problem reading image file: " + e);
        }
        
        // Vector drawing quadrant
        g.setColor(Color.WHITE);
        g.fillRect(0, QUAD_SIZE, QUAD_SIZE, QUAD_SIZE);
        g.setColor(Color.BLACK);
        g.drawOval(2, QUAD_SIZE + 2, QUAD_SIZE-4, QUAD_SIZE-4);
        g.drawArc(20, QUAD_SIZE + 20, (QUAD_SIZE - 40), QUAD_SIZE - 40, 
                190, 160);
        int eyeSize = 7;
        int eyePos = 30 - (eyeSize / 2);
        g.fillOval(eyePos, QUAD_SIZE + eyePos, eyeSize, eyeSize);
        g.fillOval(QUAD_SIZE - eyePos - eyeSize, QUAD_SIZE + eyePos, 
                eyeSize, eyeSize);
        
        // B&W grid
        g.setColor(Color.WHITE);
        g.fillRect(QUAD_SIZE + 1, QUAD_SIZE + 1, QUAD_SIZE, QUAD_SIZE);
        g.setColor(Color.BLACK);
        for (int i = 0; i < QUAD_SIZE; i += 4) {
            int pos = QUAD_SIZE + i;
            g.drawLine(pos, QUAD_SIZE + 1, pos, FULL_SIZE);
            g.drawLine(QUAD_SIZE + 1, pos, FULL_SIZE, pos);
        }
        
        originalImagePainted = true;
    }
    
    /**
     * Progressive bilinear scaling: for any downscale size, scale
     * iteratively by halves using BILINEAR filtering until the proper 
     * size is reached.
     */
    private BufferedImage getOptimalScalingImage(BufferedImage inputImage,
            int startSize, int endSize) {
        int currentSize = startSize;
        BufferedImage currentImage = inputImage;
        int delta = currentSize - endSize;
        int nextPow2 = currentSize >> 1;
        while (currentSize > 1) {
            if (delta <= nextPow2) {
                if (currentSize != endSize) {
                    BufferedImage tmpImage = new BufferedImage(endSize,
                            endSize, BufferedImage.TYPE_INT_RGB);
                    Graphics g = tmpImage.getGraphics();
                    ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                    g.drawImage(currentImage, 0, 0, tmpImage.getWidth(), 
                            tmpImage.getHeight(), null);
                    currentImage = tmpImage;
                }
                return currentImage;
            } else {
                BufferedImage tmpImage = new BufferedImage(currentSize >> 1,
                        currentSize >> 1, BufferedImage.TYPE_INT_RGB);
                Graphics g = tmpImage.getGraphics();
                ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g.drawImage(currentImage, 0, 0, tmpImage.getWidth(), 
                        tmpImage.getHeight(), null);
                currentImage = tmpImage;
                currentSize = currentImage.getWidth();
                delta = currentSize - endSize;
                nextPow2 = currentSize >> 1;
            }
        }
        return currentImage;
    }
    
    /**
     * Progressive Bilinear approach: this method gets each scaled version from
     * the getOptimalScalingImage method and copies it into place.
     */
    private void drawBetterImage(Graphics g, int yLoc) {
        int xLoc = 100;
        int delta = (int)(SCALE_FACTOR * FULL_SIZE);
        for (int scaledSize = FULL_SIZE; scaledSize > 0; scaledSize -= delta) {
            Image scaledImage = getOptimalScalingImage(originalImage, FULL_SIZE, scaledSize);
            g.drawImage(scaledImage, xLoc, yLoc + (FULL_SIZE - scaledSize)/2, 
                    null);
            xLoc += scaledSize + 20;
        }
    }
    
    /**
     * This approach uses either the getScaledInstance() approach to get
     * each new size or it scales on the fly using drawImage().
     */
    private void drawImage(Graphics g, int yLoc, boolean getScaled) {
        int xLoc = 100;
        int delta = (int)(SCALE_FACTOR * FULL_SIZE);
        if (getScaled) {
            for (int scaledSize = FULL_SIZE; scaledSize > 0; scaledSize -= delta) {
                Image scaledImage = originalImage.getScaledInstance(scaledSize,
                        scaledSize, Image.SCALE_AREA_AVERAGING);
                g.drawImage(scaledImage, xLoc, yLoc + (FULL_SIZE - scaledSize)/2, 
                        null);
                xLoc += scaledSize + 20;
            }
        } else {
            for (int scaledSize = FULL_SIZE; scaledSize > 0; scaledSize -= delta) {
                g.drawImage(originalImage, xLoc, yLoc + (FULL_SIZE - scaledSize)/2, 
                        scaledSize, scaledSize, null);
                xLoc += scaledSize + 20;
            }
        }
    }
    
    /**
     * Scale the image to several smaller sizes using each of the approaches
     * and time each series of operations. The times are output into the
     * application window for each row that they represent.
     */
    protected void paintComponent(Graphics g) {
        if (!originalImagePainted) {
            paintOriginalImage();
        }
        long startTime, endTime, totalTime;
        int xLoc, yLoc;
        
        // Draw scaled versions with nearest neighbor
        xLoc = 5;
        yLoc = 20;
        startTime = System.nanoTime();
        drawImage(g, yLoc, false);
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        g.drawString("NEAREST ", xLoc, yLoc + (FULL_SIZE / 2));
        g.drawString(Long.toString(totalTime) + " ms", 
                xLoc, yLoc + (FULL_SIZE / 2) + 15);
        System.out.println("NEAREST: " + (endTime - startTime) / 1000000);
        // BILINEAR
        yLoc += FULL_SIZE + PADDING;
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        startTime = System.nanoTime();
        drawImage(g, yLoc, false);
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        g.drawString("BILINEAR ", xLoc, yLoc + (FULL_SIZE / 2));
        g.drawString(Long.toString(totalTime) + " ms", 
                xLoc, yLoc + (FULL_SIZE / 2) + 15);
        System.out.println("BILINEAR: " + (endTime - startTime) / 1000000);
        // BIDUBIC
        yLoc += FULL_SIZE + PADDING;
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        startTime = System.nanoTime();
        drawImage(g, yLoc, false);
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        g.drawString("BICUBIC ", xLoc, yLoc + (FULL_SIZE / 2));
        g.drawString(Long.toString(totalTime) + " ms", 
                xLoc, yLoc + (FULL_SIZE / 2) + 15);
        System.out.println("BICUBIC: " + (endTime - startTime) / 1000000);
        // getScaledInstance()
        yLoc += FULL_SIZE + PADDING;
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        startTime = System.nanoTime();
        drawImage(g, yLoc, true);
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        g.drawString("getScaled ", xLoc, yLoc + (FULL_SIZE / 2));
        g.drawString(Long.toString(totalTime) + " ms", 
                xLoc, yLoc + (FULL_SIZE / 2) + 15);
        System.out.println("getScaled: " + (endTime - startTime) / 1000000);
        // Progressive Bilinear
        yLoc += FULL_SIZE + PADDING;
        startTime = System.nanoTime();
        drawBetterImage(g, yLoc);
        endTime = System.nanoTime();
        totalTime = (endTime - startTime) / 1000000;
        g.drawString("Progressive ", xLoc, yLoc + (FULL_SIZE / 2));
        g.drawString(Long.toString(totalTime) + " ms", 
                xLoc, yLoc + (FULL_SIZE / 2) + 15);
        System.out.println("faster: " + (endTime - startTime) / 1000000);
        // Draw image sizes
        xLoc = 100;
        int delta = (int)(SCALE_FACTOR * FULL_SIZE);
        for (int scaledSize = FULL_SIZE; scaledSize > 0; scaledSize -= delta) {
            g.drawString(scaledSize + " x " + scaledSize, 
                    xLoc + Math.max(0, scaledSize/2 - 20), 15);
            xLoc += scaledSize + 20;
        }
    }
    private static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setLayout(new BorderLayout());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(900, 50 + (5 * FULL_SIZE) + (6 * PADDING));
        ScaleTest_2008 test = new ScaleTest_2008();
        f.add(test);        
        f.setVisible(true);
    }
    
    public static void main(String args[]) {
        Runnable doCreateAndShowGUI = new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        };
        SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
}



Scaling Methods

   
 
 
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
 * ScalingMethods.java
 *
 * Created on May 1, 2007, 4:36 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Chet
 */
public class ScalingMethods extends JComponent {
    private static BufferedImage picture = null;
    private static final int PADDING = 10;
    private static final double SCALE_FACTOR = .05;
    private int scaleW, scaleH;
    
    /** Creates a new instance of ScalingMethods */
    public ScalingMethods() {
        try {
            URL url = getClass().getResource("BB.jpg");
            picture = ImageIO.read(url);
            scaleW = (int)(SCALE_FACTOR * picture.getWidth());
            scaleH = (int)(SCALE_FACTOR * picture.getHeight());
            setPreferredSize(new Dimension(PADDING + (5 * (scaleW + PADDING)), 
                    scaleH + (2 * PADDING)));
        } catch (Exception e) {
            System.out.println("Problem reading image file: " + e);
            System.exit(0);
        }
    }
    
    /**
     * Draws the picture five times, using the five different scaling
     * approaches described in the book. All five look the same, since
     * all are using default (nearest neighbor) filtering during the
     * scale operation.
     */
    public void paintComponent(Graphics g) {
        int x = PADDING;
        int y = PADDING;
        
        // Simplest approach
        g.drawImage(picture, x, y, scaleW, scaleH, null);
        
        // Subregion approach
        x += scaleW + PADDING;
        g.drawImage(picture, x, y, x + scaleW, y + scaleH,
                0, 0, picture.getWidth(), picture.getHeight(), null);
        
        // Graphics2D.scale approach
        x += scaleW + PADDING;
        Graphics2D g2d = (Graphics2D)g.create();
        g2d.translate(x, y);
        g2d.scale(SCALE_FACTOR, SCALE_FACTOR);
        g2d.drawImage(picture, 0, 0, null);
        g2d.dispose();
        
        // AffineTransform.scale approach
        x += scaleW + PADDING;
        g2d = (Graphics2D)g.create();
        AffineTransform at = new AffineTransform();
        at.translate(x, y);
        at.scale(SCALE_FACTOR, SCALE_FACTOR);
        g2d.drawImage(picture, at, null);
        g2d.dispose();
        
        // getScaledInstance() approach
        x += scaleW + PADDING;
        Image scaledImg = picture.getScaledInstance(scaleW, scaleH, 
                Image.SCALE_DEFAULT);
        g.drawImage(scaledImg, x, y, null);
    }
    
    private static void createAndShowGUI() {
        JFrame f = new JFrame("ScalingMethods");
        f.setLayout(new BorderLayout());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ScalingMethods test = new ScalingMethods();
        f.add(test);        
        f.validate();
        f.pack();
        f.setVisible(true);
    }
    
    public static void main(String args[]) {
        Runnable doCreateAndShowGUI = new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        };
        SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
    
}



Set Text Anti Aliasing

     
//
//   GuiUtil
//
//   Copyright (C) by Andrea Carboni.
//   This file may be distributed under the terms of the LGPL license.

import java.awt.Color;
import java.awt.ruponent;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

public class GuiUtil
{
  private static Cursor defCursor  = Cursor.getDefaultCursor();
  private static Cursor waitCursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
  //---------------------------------------------------------------------------
  public static void setWaitCursor(Component c, boolean yesno)
  {
    c.setCursor(yesno ? waitCursor : defCursor);
    getFrame(c).setCursor(yesno ? waitCursor : defCursor);
  }
  //---------------------------------------------------------------------------
  public static void setWaitCursor(boolean yesno)
  {
    Frame.getFrames()[0].setCursor(yesno ? waitCursor : defCursor);
  }
  //---------------------------------------------------------------------------
  public static Frame getFrame(Component c)
  {
    Object obj = c;
    while (!(obj instanceof Frame))
      obj = ((Component)obj).getParent();
    return (Frame)obj;
  }
  //---------------------------------------------------------------------------
  public static Color cloneColor(Color c)
  {
    return new Color(c.getRed(), c.getGreen(), c.getBlue());
  }
  //---------------------------------------------------------------------------
  public static final void setTextAntiAliasing(Graphics g, boolean yesno)
  {
    Object obj = yesno ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON
                 : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
    ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, obj);
  }
  //---------------------------------------------------------------------------
  public static final void setAntiAliasing(Graphics g, boolean yesno)
  {
    Object obj = yesno ? RenderingHints.VALUE_ANTIALIAS_ON
                 : RenderingHints.VALUE_ANTIALIAS_OFF;
    ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, obj);
  }
}



Simple Attributes of painting

   
 
 

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
 * SimpleAttributes.java
 *
 * Created on May 1, 2007, 3:59 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 * @author Chet
 */
public class SimpleAttributes extends JComponent {
    
    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g.create();
        g2d.setBackground(Color.GRAY);
        g2d.clearRect(0, 0, getWidth(), getHeight());
        
        // String and line with default attributes
        g2d.drawString("Default Font", 10, 20);
        g2d.drawLine(10, 22, 80, 22);
        
        // Change the font, foreground color, and Stroke
        g2d.setFont(g.getFont().deriveFont(Font.BOLD | Font.ITALIC, 24f));
        g2d.setColor(Color.WHITE);
        g2d.setStroke(new BasicStroke(10f, 
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
        
        // String and line with new attributes
        g2d.drawString("New Font", 10, 50);
        g2d.drawLine(10, 57, 120, 57);
        g2d.dispose();
    }
    
    private static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(150, 100);
        JComponent test = new SimpleAttributes();
        f.add(test);
        f.setVisible(true);
    }
    
    public static void main(String args[]) {
        Runnable doCreateAndShowGUI = new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        };
        SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
}



Static methods for some common painting functions

     
/*
* @(#)PaintUtils.java  1.0  2008-03-01
*
* Copyright (c) 2008 Jeremy Wood
* E-mail: mickleness@gmail.ru
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* Jeremy Wood. For details see accompanying license terms.
*/

import java.awt.*;
import javax.swing.*;
/** Some static methods for some common painting functions.
 *
 * @version 1.0
 * @author Jeremy Wood
 **/
public class PaintUtils {
  /** Four shades of white, each with increasing opacity. */
  public final static Color[] whites = new Color[] {
      new Color(255,255,255,50),
      new Color(255,255,255,100),
      new Color(255,255,255,150)
  };
  
  /** Four shades of black, each with increasing opacity. */
  public final static Color[] blacks = new Color[] {
      new Color(0,0,0,50),
      new Color(0,0,0,100),
      new Color(0,0,0,150)
  };
  
  /** @return the color used to indicate when a component has
   * focus.  By default this uses the color (64,113,167), but you can
   * override this by calling:
   * <BR><code>UIManager.put("focusRing",customColor);</code>
   */
  public static Color getFocusRingColor() {
    Object obj = UIManager.getColor("focusRing");
    if(obj instanceof Color)
      return (Color)obj;
    return new Color(64,113,167);
  }
  
  /** Paints 3 different strokes around a shape to indicate focus.
   * The widest stroke is the most transparent, so this achieves a nice
   * "glow" effect.
   * <P>The catch is that you have to render this underneath the shape,
   * and the shape should be filled completely.
   * 
   * @param g the graphics to paint to
   * @param shape the shape to outline
   * @param biggestStroke the widest stroke to use.
   */
  public static void paintFocus(Graphics2D g,Shape shape,int biggestStroke) {
    Color focusColor = getFocusRingColor();
    Color[] focusArray = new Color[] {
      new Color(focusColor.getRed(), focusColor.getGreen(), focusColor.getBlue(),255),
      new Color(focusColor.getRed(), focusColor.getGreen(), focusColor.getBlue(),170),
      new Color(focusColor.getRed(), focusColor.getGreen(), focusColor.getBlue(),110) 
    };
    g.setStroke(new BasicStroke(biggestStroke));
    g.setColor(focusArray[2]);
    g.draw(shape);
    g.setStroke(new BasicStroke(biggestStroke-1));
    g.setColor(focusArray[1]);
    g.draw(shape);
    g.setStroke(new BasicStroke(biggestStroke-2));
    g.setColor(focusArray[0]);
    g.draw(shape);
    g.setStroke(new BasicStroke(1));
  }
  
  /** Uses translucent shades of white and black to draw highlights
   * and shadows around a rectangle, and then frames the rectangle
   * with a shade of gray (120).
   * <P>This should be called to add a finishing touch on top of
   * existing graphics.
   * @param g the graphics to paint to.
   * @param r the rectangle to paint.
   */
  public static void drawBevel(Graphics g,Rectangle r) {
    drawColors(blacks,g, r.x, r.y+r.height, r.x+r.width, r.y+r.height, SwingConstants.SOUTH);
    drawColors(blacks,g, r.x+r.width, r.y, r.x+r.width, r.y+r.height, SwingConstants.EAST);
    drawColors(whites,g, r.x, r.y, r.x+r.width, r.y, SwingConstants.NORTH);
    drawColors(whites,g, r.x, r.y, r.x, r.y+r.height, SwingConstants.WEST);
    
    g.setColor(new Color(120, 120, 120));
    g.drawRect(r.x, r.y, r.width, r.height);
  }
  
  private static void drawColors(Color[] colors,Graphics g,int x1,int y1,int x2,int y2,int direction) {
    for(int a = 0; a<colors.length; a++) {
      g.setColor(colors[colors.length-a-1]);
      if(direction==SwingConstants.SOUTH) {
        g.drawLine(x1, y1-a, x2, y2-a);
      } else if(direction==SwingConstants.NORTH) {
        g.drawLine(x1, y1+a, x2, y2+a);
      } else if(direction==SwingConstants.EAST) {
        g.drawLine(x1-a, y1, x2-a, y2);
      } else if(direction==SwingConstants.WEST) {
        g.drawLine(x1+a, y1, x2+a, y2);
      }
    }
  }
}



Two Stops Gradient

   
 
 
/*
 * Copyright (c) 2007, Romain Guy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import javax.swing.JButton;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
/**
 *
 * @author Romain Guy
 */
public class TwoStopsGradient extends JFrame {
    
    /** Creates a new instance of TwoStopsGradient */
    public TwoStopsGradient() {
        super("Two Stops Gradient");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel(new GridBagLayout());
        JButton button;
        panel.add(button = new DepthButton("New"),
                new GridBagConstraints(0, 0, 1, 1,
                    0.0, 0.0, GridBagConstraints.CENTER,
                    GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 0, 0));
        button.setFocusPainted(false);
        panel.add(button = new DepthButton("Open"),
                new GridBagConstraints(1, 0, 1, 1,
                    0.0, 0.0, GridBagConstraints.CENTER,
                    GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 0, 0));
        button.setFocusPainted(false);
        panel.add(button = new DepthButton("Save"),
                new GridBagConstraints(2, 0, 1, 1,
                    0.0, 0.0, GridBagConstraints.CENTER,
                    GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 0, 0));
        button.setFocusPainted(false);
        
        add(panel);
        setSize(320, 240);
    }
    
    public static void main(String... args) {
        try {
            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new TwoStopsGradient().setVisible(true);
            }
        });
    }
}
/*
 * Copyright (c) 2007, Romain Guy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 *
 * @author Romain Guy
 */
 class DepthButton extends JButton {
    
    /** Creates a new instance of DepthButton */
    public DepthButton(String text) {
        super(text);
        setContentAreaFilled(false);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        
        GradientPaint p;
        p = new GradientPaint(0, 0, new Color(0xFFFFFF),
                0, getHeight(), new Color(0xC8D2DE));
        
        Paint oldPaint = g2.getPaint();
        g2.setPaint(p);
        g2.fillRect(0, 0, getWidth(), getHeight());
        g2.setPaint(oldPaint);
        
        
        super.paintComponent(g);
    }
}



Utilties for painting visual effects

    
/*
 * $Id: PaintUtils.java,v 1.24 2009/05/25 16:37:52 kschaefe Exp $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
/**
 * A collection of utilties for painting visual effects.
 *
 * @author Mark Davidson
 */
public class PaintUtils {
    public static final GradientPaint BLUE_EXPERIENCE = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(168, 204, 241),
            new Point2D.Double(0, 1),
            new Color(44, 61, 146));
    public static final GradientPaint MAC_OSX_SELECTED = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(81, 141, 236),
            new Point2D.Double(0, 1),
            new Color(36, 96, 192));
    public static final GradientPaint MAC_OSX = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(167, 210, 250),
            new Point2D.Double(0, 1),
            new Color(99, 147, 206));
    public static final GradientPaint AERITH = new GradientPaint(
            new Point2D.Double(0, 0),
            Color.WHITE,
            new Point2D.Double(0, 1),
            new Color(64, 110, 161));
    public static final GradientPaint GRAY = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(226, 226, 226),
            new Point2D.Double(0, 1),
            new Color(250, 248, 248));
    public static final GradientPaint RED_XP = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(236, 81, 81),
            new Point2D.Double(0, 1),
            new Color(192, 36, 36));
    public static final GradientPaint NIGHT_GRAY = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(102, 111, 127),
            new Point2D.Double(0, 1),
            new Color(38, 45, 61));
    public static final GradientPaint NIGHT_GRAY_LIGHT = new GradientPaint(
            new Point2D.Double(0, 0),
            new Color(129, 138, 155),
            new Point2D.Double(0, 1),
            new Color(58, 66, 82));
    
    
    private PaintUtils() {
    }
    
    /**
     * Returns the bounds that the text of a label will be drawn into.
     * Takes into account the current font metrics.
     */
    public static Rectangle getTextBounds(Graphics g, JLabel label) {
        FontMetrics fm = g.getFontMetrics();
        Rectangle2D r2d = fm.getStringBounds(label.getText(), g);
        Rectangle rect = r2d.getBounds();
        int xOffset = 0;
        switch (label.getHorizontalAlignment()) {
            case SwingConstants.RIGHT:
            case SwingConstants.TRAILING:
                xOffset = label.getBounds().width - rect.width;
                break;
            case SwingConstants.CENTER:
                xOffset = (label.getBounds().width - rect.width) / 2;
                break;
            default:
            case SwingConstants.LEFT:
            case SwingConstants.LEADING:
                xOffset = 0;
                break;
        }
        int yOffset = 0;
        switch (label.getVerticalAlignment()) {
            case SwingConstants.TOP:
                yOffset = 0;
                break;
            case SwingConstants.CENTER:
                yOffset = (label.getBounds().height - rect.height) / 2;
                break;
            case SwingConstants.BOTTOM:
                yOffset = label.getBounds().height - rect.height;
                break;
        }
        return new Rectangle(xOffset, yOffset, rect.width, rect.height);
    }
    
    /**
     * Paints a top to bottom gradient fill over the component bounds
     * from color1 to color2.
     */
    public static void paintGradient(Graphics g, JComponent comp,
            Color color1, Color color2) {
        GradientPaint paint = new GradientPaint(0, 0, color1,
                0, comp.getHeight(), color2,
                true);
        Graphics2D g2 = (Graphics2D) g;
        Paint oldPaint = g2.getPaint();
        g2.setPaint(paint);
        g2.fillRect(0, 0, comp.getWidth(), comp.getHeight());
        g2.setPaint(oldPaint);
    }
    
    /** Resizes a gradient to fill the width and height available. If the
     * gradient is left to right it will be resized to fill the entire width.
     * If the gradient is top to bottom it will be resized to fill the entire
     * height. If the gradient is on an angle it will be resized to go from
     * one corner to the other of the rectangle formed by (0,0 -> width,height).
     *
     * This method can resize java.awt.GradientPaint, java.awt.LinearGradientPaint,
     * and the LinearGradientPaint implementation from Apache"s Batik project. Note,
     * this method does not require the MultipleGradientPaint.jar from Apache to
     * compile or to run. MultipleGradientPaint.jar *is* required if you want
     * to resize the LinearGradientPaint from that jar.
     *
     * Any paint passed into this method which is not a kind of gradient paint (like
     * a Color or TexturePaint) will be returned unmodified. It will not throw
     * an exception. If the gradient cannot be resized due to other errors the
     * original paint will be returned unmodified. It will not throw an
     * exception.
     *
     */
    public static Paint resizeGradient(Paint p, int width, int height) {
        if(p == null) return p;
        
        if(p instanceof GradientPaint) {
            GradientPaint gp = (GradientPaint)p;
            Point2D[] pts = new Point2D[2];
            pts[0] = gp.getPoint1();
            pts[1] = gp.getPoint2();
            pts = adjustPoints(pts, width, height);
            return new GradientPaint(pts[0], gp.getColor1(), pts[1], gp.getColor2(), gp.isCyclic());
        }
        
        if("java.awt.LinearGradientPaint".equals(p.getClass().getName()) ||
           "org.apache.batik.ext.awt.LinearGradientPaint".equals(p.getClass().getName())) {
            return resizeLinearGradient(p,width,height);
        }
        return p;
    }
    
    
    private static Paint resizeLinearGradient(Paint p, int width, int height) {
        try {
            Point2D[] pts = new Point2D[2];
            pts[0] = (Point2D) invokeMethod(p,"getStartPoint");
            pts[1] = (Point2D) invokeMethod(p,"getEndPoint");
            pts = adjustPoints(pts, width, height);
            float[] fractions = (float[]) invokeMethod(p,"getFractions");
            Color[] colors = (Color[]) invokeMethod(p,"getColors");
            
            Constructor<?> con = p.getClass().getDeclaredConstructor(
                    Point2D.class, Point2D.class,
                    new float[0].getClass(),
                    new Color[0].getClass());
            return (Paint) con.newInstance(pts[0],pts[1],fractions, colors);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return p;
    }
    
    private static Object invokeMethod(final Object p, final String methodName)
            throws NoSuchMethodException, InvocationTargetException, IllegalArgumentException, SecurityException, IllegalAccessException {
        Method meth = p.getClass().getMethod(methodName);
        return meth.invoke(p);
    }
    
    
    private static Point2D[] adjustPoints(Point2D[] pts, int width, int height) {
        Point2D start = pts[0];
        Point2D end = pts[1];
        
        double angle = calcAngle(start,end);
        double a2 = Math.toDegrees(angle);
        double e = 1;
        
        // if it is near 0 degrees
        if(Math.abs(angle) < Math.toRadians(e) ||
                Math.abs(angle) > Math.toRadians(360-e)) {
            start = new Point2D.Float(0,0);
            end = new Point2D.Float(width,0);
        }
        
        // near 45
        if(isNear(a2, 45, e)) {
            start = new Point2D.Float(0,0);
            end = new Point2D.Float(width,height);
        }
        
        // near 90
        if(isNear(a2,  90, e)) {
            start = new Point2D.Float(0,0);
            end = new Point2D.Float(0,height);
        }
        
        // near 135
        if(isNear(a2, 135, e)) {
            start = new Point2D.Float(width,0);
            end = new Point2D.Float(0,height);
        }
        
        // near 180
        if(isNear(a2, 180, e)) {
            start = new Point2D.Float(width,0);
            end = new Point2D.Float(0,0);
        }
        
        // near 225
        if(isNear(a2, 225, e)) {
            start = new Point2D.Float(width,height);
            end = new Point2D.Float(0,0);
        }
        
        // near 270
        if(isNear(a2, 270, e)) {
            start = new Point2D.Float(0,height);
            end = new Point2D.Float(0,0);
        }
        
        // near 315
        if(isNear(a2, 315, e)) {
            start = new Point2D.Float(0,height);
            end = new Point2D.Float(width,0);
        }
        
        return new Point2D[] { start, end };
    }
    
    private static boolean isNear(double angle, double target, double error) {
        return Math.abs(target - Math.abs(angle)) < error;
    }
    
    private static double calcAngle(Point2D p1, Point2D p2) {
        double x_off = p2.getX() - p1.getX();
        double y_off = p2.getY() - p1.getY();
        double angle = Math.atan(y_off / x_off);
        if (x_off < 0) {
            angle = angle + Math.PI;
        }
        
        if(angle < 0) { angle+= 2*Math.PI; }
        if(angle > 2*Math.PI) { angle -= 2*Math.PI; }
        return angle;
    }
/*    
    public static void main(String ... args) {
        LinearGradientPaint in = new LinearGradientPaint(
                new Point(0,0), new Point(10,0),
                new float[] {0f, 0.5f, 1f},
                new Color[] {Color.RED, Color.GREEN, Color.BLUE});
        log.fine("in  = " + toString(in));
        Paint out = resizeGradient(in,100,100);
        log.fine(("out = " + toString((MultipleGradientPaint) out));
    }*/
    /*
    private static String toString(MultipleGradientPaint paint) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(paint.getClass().getName());
        Color[] colors = paint.getColors();
        float[] values = paint.getFractions();
        buffer.append("[");
        for(int i=0; i<colors.length; i++) {
            buffer.append("#").append(Integer.toHexString(colors[i].getRGB()));
            buffer.append(":");
            buffer.append(values[i]);
            buffer.append(", ");
        }
        buffer.append("]");
        if(paint instanceof LinearGradientPaint) {
            LinearGradientPaint lgp = (LinearGradientPaint) paint;
            buffer.append(", ");
            buffer.append(""+lgp.getStartPoint().getX() + ", " + lgp.getStartPoint().getY());
            buffer.append("->");
            buffer.append(""+lgp.getEndPoint().getX() + ", " + lgp.getEndPoint().getY());
        }
        
        return buffer.toString();
    }*/
    
//    private static void p(String string) {
//        log.fine((string);
//    }
}



Your own Graphics2D

    
/*
 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.
 */
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.ruposite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * This concrete implementation of <tt>AbstractGraphics2D</tt> is a simple
 * help to programmers to get started with their own implementation of
 * <tt>Graphics2D</tt>. <tt>DefaultGraphics2D</tt> implements all the
 * abstract methods is <tt>AbstractGraphics2D</tt> and makes it easy to start
 * implementing a <tt>Graphic2D</tt> piece-meal.
 * 
 * @author 
 * @version $Id: TransformType.java 504084 2007-02-06 11:24:46Z dvholten $
 */
class TransformType {
  /*
   * Transform type constants
   */
  public static final int TRANSFORM_TRANSLATE = 0;
  public static final int TRANSFORM_ROTATE = 1;
  public static final int TRANSFORM_SCALE = 2;
  public static final int TRANSFORM_SHEAR = 3;
  public static final int TRANSFORM_GENERAL = 4;
  /**
   * Strings describing the elementary transforms
   */
  public static final String TRANSLATE_STRING = "translate";
  public static final String ROTATE_STRING = "rotate";
  public static final String SCALE_STRING = "scale";
  public static final String SHEAR_STRING = "shear";
  public static final String GENERAL_STRING = "general";
  /**
   * TransformType values
   */
  public static final TransformType TRANSLATE = new TransformType(TRANSFORM_TRANSLATE,
      TRANSLATE_STRING);
  public static final TransformType ROTATE = new TransformType(TRANSFORM_ROTATE, ROTATE_STRING);
  public static final TransformType SCALE = new TransformType(TRANSFORM_SCALE, SCALE_STRING);
  public static final TransformType SHEAR = new TransformType(TRANSFORM_SHEAR, SHEAR_STRING);
  public static final TransformType GENERAL = new TransformType(TRANSFORM_GENERAL, GENERAL_STRING);
  private String desc;
  private int val;
  /**
   * Constructor is private so that no instances other than the ones in the
   * enumeration can be created.
   * 
   * @see #readResolve
   */
  private TransformType(int val, String desc) {
    this.desc = desc;
    this.val = val;
  }
  /**
   * @return description
   */
  public String toString() {
    return desc;
  }
  /**
   * Convenience for enumeration switching. That is,
   * 
   * <pre>
   *    switch(transformType.toInt()){
   *        case TransformType.TRANSFORM_TRANSLATE:
   *         ....
   *        case TransformType.TRANSFORM_ROTATE:
   * </pre>
   */
  public int toInt() {
    return val;
  }
  /**
   * This is called by the serialization code before it returns an unserialized
   * object. To provide for unicity of instances, the instance that was read is
   * replaced by its static equivalent
   */
  public Object readResolve() {
    switch (val) {
    case TRANSFORM_TRANSLATE:
      return TransformType.TRANSLATE;
    case TRANSFORM_ROTATE:
      return TransformType.ROTATE;
    case TRANSFORM_SCALE:
      return TransformType.SCALE;
    case TRANSFORM_SHEAR:
      return TransformType.SHEAR;
    case TRANSFORM_GENERAL:
      return TransformType.GENERAL;
    default:
      throw new Error("Unknown TransformType value:" + val);
    }
  }
}