/**
* EpsGraphics.java
*
* This file is part of the EPS Graphics Library
*
* The EPS Graphics Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The EPS Graphics 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the EPS Graphics Library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Copyright (c) 2001-2004, Paul Mutton
*
* Copyright (c) 2006-2009, Thomas Abeel
*
* Project: http://sourceforge.net/projects/epsgraphics/
*
* based on original code by Paul Mutton, http://www.jibble.org/
*/
package org.geogebra.desktop.export.epsgraphics;
import java.util.LinkedList;
import org.geogebra.common.awt.GAffineTransform;
import org.geogebra.common.awt.GBasicStroke;
import org.geogebra.common.awt.GBufferedImage;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.awt.GComposite;
import org.geogebra.common.awt.GFont;
import org.geogebra.common.awt.GFontRenderContext;
import org.geogebra.common.awt.GGraphics2D;
import org.geogebra.common.awt.GLine2D;
import org.geogebra.common.awt.GPaint;
import org.geogebra.common.awt.GPathIterator;
import org.geogebra.common.awt.GPoint2D;
import org.geogebra.common.awt.GQuadCurve2D;
import org.geogebra.common.awt.GShape;
import org.geogebra.common.awt.MyImage;
import org.geogebra.common.factories.AwtFactory;
import org.geogebra.common.util.debug.Log;
import org.geogebra.desktop.awt.GFontRenderContextD;
/**
* EpsGraphics is suitable for creating high quality EPS graphics for use in
* documents and papers, and can be used just like a standard Graphics2D object.
* <p>
* Many Java programs use Graphics2D to draw stuff on the screen, and while it
* is easy to save the output as a png or jpeg file, it is a little harder to
* export it as an EPS for including in a document or paper.
* <p>
* This class makes the whole process extremely easy, because you can use it as
* if it's a Graphics2D object. The only difference is that all of the
* implemented methods create EPS output, which means the diagrams you draw can
* be resized without leading to any of the jagged edges you may see when
* resizing pixel-based images, such as jpeg and png files.
* <p>
* Example usage:
* <p>
*
* <pre>
* Graphics2D g = new EpsGraphics2D();
* g.setColor(Color.black);
*
* // Line thickness 2.
* g.setStroke(new BasicStroke(2.0f));
*
* // Draw a line.
* g.drawLine(10, 10, 50, 10);
*
* // Fill a rectangle in blue
* g.setColor(Color.blue);
* g.fillRect(10, 0, 20, 20);
*
* // Get the EPS output.
* String output = g.toString();
* </pre>
*
* <p>
* You do not need to worry about the size of the canvas when drawing on a
* EpsGraphics object. The bounding box of the EPS document will automatically
* resize to accommodate new items that you draw.
* <p>
* Not all methods are implemented yet. Those that are not are clearly labelled.
*
*/
abstract public class EpsGraphics implements GGraphics2D {
public static final String VERSION = "1.0.0";
/**
* Constructs a new EPS document that is initially empty and can be drawn on
* like a Graphics2D object. The EPS document is written to the output
* stream as it goes, which reduces memory usage. The bounding box of the
* document is fixed and specified at construction time by
* minX,minY,maxX,maxY. The output stream is flushed and closed when the
* close() method is called.
*
* @param bgColor
*/
public EpsGraphics(String title, StringBuilder outputStream, int minX,
int minY, int maxX, int maxY, ColorMode colorMode, GColor bgColor) {
_document = new EpsDocument(title, outputStream, minX, minY, maxX,
maxY);
this.colorMode = colorMode;
_backgroundColor = bgColor == null ? GColor.WHITE : bgColor;
_clip = null;
_transform = AwtFactory.getPrototype().newAffineTransform();
_clipTransform = AwtFactory.getPrototype().newAffineTransform();
_accurateTextMode = true;
setColor(GColor.BLACK);
setPaint(GColor.BLACK);
// setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
// setFont(GFont.decode(null));
setStroke(AwtFactory.getPrototype().newBasicStroke(1));
}
/**
* Copy constructor. Creates a copy of this EPSGraphics object.
*/
public EpsGraphics(EpsGraphics g) {
// System.err.println("G: " + g._document);
EpsDocument doc = g._document;
this._document = doc;
this.colorMode = g.colorMode;
_backgroundColor = g._backgroundColor;
_clip = g.getClip();
_transform = g.getTransform();
_clipTransform = g._clipTransform;
_accurateTextMode = true;
setColor(g.getColor());
setPaint(g.getPaint());
// setComposite(g.getComposite());
setFont(g.getFont());
setStroke(g.getStroke());
}
// ///////////// Specialist methods ///////////////////////
/**
* Sets whether to use accurate text mode when rendering text in EPS. This
* is enabled (true) by default. When accurate text mode is used, all text
* will be rendered in EPS to appear exactly the same as it would do when
* drawn with a Graphics2D context. With accurate text mode enabled, it is
* not necessary for the EPS viewer to have the required font installed.
* <p>
* Turning off accurate text mode will require the EPS viewer to have the
* necessary fonts installed. If you are using a lot of text, you will find
* that this significantly reduces the file size of your EPS documents.
* AffineTransforms can only affect the starting point of text using this
* simpler text mode - all text will be horizontal.
*/
public void setAccurateTextMode(boolean b) {
_accurateTextMode = b;
if (!getAccurateTextMode()) {
setFont(getFont());
}
}
/**
* Returns whether accurate text mode is being used.
*/
public boolean getAccurateTextMode() {
return _accurateTextMode;
}
/**
* Appends a line to the EpsDocument.
*/
protected void append(String line) {
_document.append(this, line);
}
/**
* Returns the point after it has been transformed by the transformation.
*/
protected GPoint2D transform(double x, double y) {
GPoint2D result = AwtFactory.getPrototype().newPoint2D(x, y);
result = _transform.transform(result, result);
result.setLocation(result.getX(), -result.getY());
return result;
}
/**
* Appends the commands required to draw a shape on the EPS document.
*/
protected void draw(GShape s0, String action, boolean subPath) {
if (s0 != null) {
GShape s = s0;
// 20120115 bugfix: stroke needs to be appended each time
if (!subPath) {
appendStroke();
}
if (!_transform.isIdentity()) {
s = _transform.createTransformedShape(s);
}
if (!subPath) {
append("newpath");
}
int type = 0;
double[] coords = new double[6];
GPathIterator it = s.getPathIterator(null);
double x0 = 0;
double y0 = 0;
while (!it.isDone()) {
type = it.currentSegment(coords);
double x1 = coords[0];
double y1 = -coords[1];
double x2 = coords[2];
double y2 = -coords[3];
double x3 = coords[4];
double y3 = -coords[5];
if (type == GPathIterator.SEG_CLOSE) {
append("closepath");
} else if (type == GPathIterator.SEG_CUBICTO) {
append(x1 + " " + y1 + " " + x2 + " " + y2 + " " + x3 + " "
+ y3 + " curveto");
x0 = x3;
y0 = y3;
} else if (type == GPathIterator.SEG_LINETO) {
append(x1 + " " + y1 + " lineto");
x0 = x1;
y0 = y1;
} else if (type == GPathIterator.SEG_MOVETO) {
append(x1 + " " + y1 + " moveto");
x0 = x1;
y0 = y1;
} else if (type == GPathIterator.SEG_QUADTO) {
// Convert the quad curve into a cubic.
double _x1 = x0 + 2 / 3f * (x1 - x0);
double _y1 = y0 + 2 / 3f * (y1 - y0);
double _x2 = x1 + 1 / 3f * (x2 - x1);
double _y2 = y1 + 1 / 3f * (y2 - y1);
double _x3 = x2;
double _y3 = y2;
append(_x1 + " " + _y1 + " " + _x2 + " " + _y2 + " " + _x3
+ " " + _y3 + " curveto");
x0 = _x3;
y0 = _y3;
} else {
Log.warn("unknown type " + type);
}
it.next();
}
if (!subPath) {
append(action);
append("newpath");
}
}
}
/**
* Returns a hex string that always contains two characters.
*/
protected static String toHexString(int n) {
String result = Integer.toString(n, 16);
while (result.length() < 2) {
result = "0" + result;
}
return result;
}
// ///////////// Graphics2D methods ///////////////////////
/**
* Draws a 3D rectangle outline. If it is raised, light appears to come from
* the top left.
*/
// @Override
// public void draw3DRect(int x, int y, int width, int height, boolean
// raised) {
// Color originalColor = getColor();
// Stroke originalStroke = getStroke();
// setStroke(new BasicStroke(1.0f));
// if (raised) {
// setColor(originalColor.brighter());
// } else {
// setColor(originalColor.darker());
// }
// drawLine(x, y, x + width, y);
// drawLine(x, y, x, y + height);
// if (raised) {
// setColor(originalColor.darker());
// } else {
// setColor(originalColor.brighter());
// }
// drawLine(x + width, y + height, x, y + height);
// drawLine(x + width, y + height, x + width, y);
// setColor(originalColor);
// setStroke(originalStroke);
// }
/**
* Fills a 3D rectangle. If raised, it has bright fill and light appears to
* come from the top left.
*/
// @Override
// public void fill3DRect(int x, int y, int width, int height, boolean
// raised) {
// Color originalColor = getColor();
// if (raised) {
// setColor(originalColor.brighter());
// } else {
// setColor(originalColor.darker());
// }
// draw(new Rectangle(x, y, width, height), "fill");
// setColor(originalColor);
// draw3DRect(x, y, width, height, raised);
// }
/**
* Draws a Shape on the EPS document.
*/
@Override
public void draw(GShape s) {
draw(s, "stroke", false);
}
/**
* Draws an Image on the EPS document.
*/
public void drawImage(GBufferedImage img, GAffineTransform xform) {
GAffineTransform at = getTransform();
transform(xform);
drawImage(img, 0, 0, img.getWidth(), img.getHeight());
setTransform(at);
}
/**
* Draws a BufferedImage on the EPS document.
*/
@Override
public void drawImage(GBufferedImage img, int x, int y) {
GAffineTransform transform = AwtFactory.getPrototype()
.newAffineTransform();
transform.setTransform(1f, 0f, 0f, 1f, x, y);
// drawImage(op.filter(img, null), transform, null);
drawImage(img, transform);
}
/**
* Draws a RenderedImage on the EPS document.
*/
// @Override
// public void drawRenderedImage(GRenderedImage img, GAffineTransform xform)
// {
// Hashtable<String, Object> properties = new Hashtable<String, Object>();
// String[] names = img.getPropertyNames();
// for (int i = 0; i < names.length; i++) {
// properties.put(names[i], img.getProperty(names[i]));
// }
// GColorModel cm = img.getColorModel();
// GWritableRaster wr = img.copyData(null);
// GBufferedImage img1 = new BufferedImage(cm, wr,
// cm.isAlphaPremultiplied(), properties);
// GAffineTransform at = GAffineTransform.getTranslateInstance(
// img.getMinX(), img.getMinY());
// at.preConcatenate(xform);
// drawImage(img1, at, null);
// }
/**
* Draws a RenderableImage by invoking its createDefaultRendering method.
*/
// @Override
// public void drawRenderableImage(GRenderableImage img, GAffineTransform
// xform) {
// drawRenderedImage(img.createDefaultRendering(), xform);
// }
/**
* Draws a string at (x,y)
*/
@Override
public void drawString(String str, int x, int y) {
drawString(str, (float) x, (float) y);
}
/**
* Draws a string at (x,y)
*/
@Override
public void drawString(String s, double x, double y) {
if (s != null && s.length() > 0) {
// AttributedString as = new AttributedString(s);
// as.addAttribute(TextAttribute.FONT, getFont());
// drawString(as.getIterator(), x, y);
drawString(s, x, y, getFont());
}
}
/**
* Draws the characters of an AttributedCharacterIterator, starting from
* (x,y).
*/
public abstract void drawString(String s, double x, double y, GFont font);
/**
* Draws a GlyphVector at (x,y)
*/
// @Override
// public void drawGlyphVector(GGlyphVector g, float x, float y) {
// GShape shape = g.getOutline(x, y);
// draw(shape, "fill");
// }
/**
* Fills a Shape on the EPS document.
*/
@Override
public void fill(GShape s) {
draw(s, "fill", false);
}
/**
* Checks whether or not the specified Shape intersects the specified
* Rectangle, which is in device space.
*/
// @Override
// public boolean hit(GRectangle rect, GShape s, boolean onStroke) {
// return s.intersects(rect);
// }
/**
* Returns the device configuration associated with this EpsGraphics2D
* object.
*/
// @Override
// public GraphicsConfiguration getDeviceConfiguration() {
// GraphicsConfiguration gc = null;
// GraphicsEnvironment ge = GraphicsEnvironment
// .getLocalGraphicsEnvironment();
// GraphicsDevice[] gds = ge.getScreenDevices();
// for (int i = 0; i < gds.length; i++) {
// GraphicsDevice gd = gds[i];
// GraphicsConfiguration[] gcs = gd.getConfigurations();
// if (gcs.length > 0) {
// return gcs[0];
// }
// }
// return gc;
// }
/**
* Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does
* not make use of these.
*/
@Override
public void setComposite(GComposite comp) {
_composite = comp;
}
/**
* Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
* of type Color are respected by EpsGraphics2D.
*/
@Override
public void setPaint(GPaint paint) {
_paint = paint;
if (paint instanceof GColor) {
setColor((GColor) paint);
}
}
/*
* 20120115 bugfix: stroke needs to be appended each time (non-Javadoc)
*
* @see java.awt.Graphics2D#setStroke(java.awt.Stroke)
*/
@Override
public void setStroke(final GBasicStroke currentStroke) {
this.currentStroke = currentStroke;
}
GBasicStroke currentStroke = null;
/**
* Sets the stroke. Only accepts BasicStroke objects (or subclasses of
* BasicStroke).
*/
public void appendStroke() {
if (currentStroke != null) {
_stroke = currentStroke;
append(_stroke.getLineWidth() + " setlinewidth");
double miterLimit = _stroke.getMiterLimit();
if (miterLimit < 1.0f) {
miterLimit = 1;
}
append(miterLimit + " setmiterlimit");
append(_stroke.getLineJoin() + " setlinejoin");
append(_stroke.getEndCap() + " setlinecap");
StringBuffer dashes = new StringBuffer();
dashes.append("[ ");
double[] dashArray = _stroke.getDashArray();
if (dashArray != null) {
for (int i = 0; i < dashArray.length; i++) {
dashes.append((dashArray[i]) + " ");
}
}
dashes.append("]");
append(dashes.toString() + " 0 setdash");
}
}
/**
* Translates the origin of the EpsGraphics2D context to the point (x,y) in
* the current coordinate system.
*/
// @Override
// public void translate(int x, int y) {
// translate((double) x, (double) y);
// }
/**
* Concatenates the current EpsGraphics2D Transformation with a translation
* transform.
*/
@Override
public void translate(double tx, double ty) {
transform(AwtFactory.getTranslateInstance(tx, ty));
}
/**
* Concatenates the current EpsGraphics2D Transform with a rotation
* transform.
*
* @param theta
* anglein radians
*/
// @Override
public void rotate(double theta) {
rotate(theta, 0, 0);
}
/**
* Concatenates the current EpsGraphics2D Transform with a translated
* rotation transform.
*/
// @Override
public void rotate(double theta, double x, double y) {
transform(AwtFactory.getRotateInstance(theta, x, y));
}
/**
* Concatenates the current EpsGraphics2D Transform with a scaling
* transformation.
*/
@Override
public void scale(double sx, double sy) {
transform(AwtFactory.getScaleInstance(sx, sy));
}
/**
* Concatenates the current EpsGraphics2D Transform with a shearing
* transform.
*/
// @Override
// public void shear(double shx, double shy) {
// transform(AffineTransform.getShearInstance(shx, shy));
// }
/**
* Composes an AffineTransform object with the Transform in this
* EpsGraphics2D according to the rule last-specified-first-applied.
*/
@Override
public void transform(GAffineTransform Tx) {
_transform.concatenate(Tx);
setTransform(getTransform());
}
/**
* Sets the AffineTransform to be used by this EpsGraphics2D.
*/
public void setTransform(GAffineTransform Tx) {
if (Tx == null) {
_transform = AwtFactory.getPrototype().newAffineTransform();
} else {
_transform = AwtFactory.getPrototype().newAffineTransform();
_transform.setTransform(Tx);
}
// Need to update the stroke and font so they know the scale changed
setStroke(getStroke());
setFont(getFont());
}
/**
* Gets the AffineTransform used by this EpsGraphics2D.
*/
public GAffineTransform getTransform() {
GAffineTransform ret = AwtFactory.getPrototype().newAffineTransform();
ret.setTransform(_transform);
return ret;
}
/**
* Returns the current Paint of the EpsGraphics2D object.
*/
public GPaint getPaint() {
if (_paint == null) {
return GColor.BLACK;
}
return _paint;
}
/**
* returns the current Composite of the EpsGraphics2D object.
*/
@Override
public GComposite getComposite() {
return _composite;
}
/**
* Sets the background color to be used by the clearRect method.
*
* @param color
* background
*/
public void setBackground(GColor color) {
if (color == null) {
_backgroundColor = GColor.BLACK;
} else {
_backgroundColor = color;
}
}
/**
* Gets the background color that is used by the clearRect method.
*/
@Override
public GColor getBackground() {
return _backgroundColor;
}
/**
* Returns the Stroke currently used. Guaranteed to be an instance of
* BasicStroke.
*/
@Override
public GBasicStroke getStroke() {
return _stroke;
}
/**
* Returns the FontRenderContext.
*/
@Override
public GFontRenderContext getFontRenderContext() {
if (_fontRenderContext == null) {
_fontRenderContext = getNewFontRenderContext();
}
return _fontRenderContext;
}
// ///////////// Graphics methods ///////////////////////
/**
* Returns an EpsGraphics2D object based on this Graphics object, but with a
* new translation and clip area.
*/
// @Override
// public Graphics create(int x, int y, int width, int height) {
// Graphics g = create();
// g.translate(x, y);
// g.clipRect(0, 0, width, height);
// return g;
// }
/**
* Returns the current Color. This will be a default value (black) until it
* is changed using the setColor method.
*/
@Override
public GColor getColor() {
if (color == null) {
return GColor.BLACK;
}
return color;
}
/**
* Sets the Color to be used when drawing all future shapes, text, etc.
*/
@Override
public void setColor(GColor color) {
GColor color1 = color;
if (color1 == null) {
color1 = GColor.BLACK;
}
float red = color1.getRed() / 255f;
float green = color1.getGreen() / 255f;
float blue = color1.getBlue() / 255f;
float alpha = color1.getAlpha() / 255f;
if (alpha != 1) {
float bgRed = _backgroundColor.getRed() / 255f;
float bgGreen = _backgroundColor.getGreen() / 255f;
float bgBlue = _backgroundColor.getBlue() / 255f;
// GGB-1146
// fake transparency, work out correct color assuming shape
// is being drawn on the background and not over something else
// https://en.wikipedia.org/wiki/Alpha_compositing
red = bgRed * (1 - alpha) + red * alpha;
green = bgGreen * (1 - alpha) + green * alpha;
blue = bgBlue * (1 - alpha) + blue * alpha;
}
this.color = color1;
switch (colorMode) {
case BLACK_AND_WHITE:
double value = 0;
if (red + green + blue > 0.5) {
value = 1;
}
append(value + " setgray");
break;
case GRAYSCALE:
double grayvalue = (red + green + blue) / 3;
append(grayvalue + " setgray");
break;
case COLOR_RGB:
append(red + " " + green + " " + blue + " setrgbcolor");
break;
case COLOR_CMYK:
if (color1.equals(GColor.BLACK)) {
append("0.0 0.0 0.0 1.0 setcmykcolor");
} else {
double c = 1 - red;
double m = 1 - green;
double y = 1 - blue;
double k = Math.min(Math.min(c, y), m);
append((c - k) / (1 - k) + " " + (m - k) / (1 - k) + " "
+ (y - k) / (1 - k) + " " + k + " setcmykcolor");
}
break;
}
}
/**
* Sets the paint mode of this EpsGraphics2D object to overwrite the
* destination EpsDocument with the current color.
*/
// @Override
// public void setPaintMode() {
// // Do nothing - paint mode is the only method supported anyway.
// }
/**
* <b><i><font color="red">Not implemented</font></i></b> - performs no
* action.
*/
// @Override
// public void setXORMode(GColor c1) {
// methodNotSupported();
// }
/**
* Returns the Font currently being used.
*/
@Override
public GFont getFont() {
return _font;
}
/**
* Sets the Font to be used in future text.
*/
@Override
public void setFont(GFont font) {
// if (font == null) {
// font = GFont.decode(null);
// }
_font = font;
// if (!getAccurateTextMode()) {
// append("/" + _font.getPSName() + " findfont " + _font.getSize()
// + " scalefont setfont");
// }
}
/**
* Gets the font metrics of the current font.
*/
// @Override
// public FontMetrics getFontMetrics() {
// return getFontMetrics(getFont());
// }
/**
* Gets the font metrics for the specified font.
*/
// @Override
// public FontMetrics getFontMetrics(GFont f) {
// BufferedImage image = new BufferedImage(1, 1,
// BufferedImage.TYPE_INT_RGB);
// Graphics g = image.getGraphics();
// return g.getFontMetrics(f);
// }
/**
* Returns the bounding rectangle of the current clipping area.
*/
// @Override
// public GRectangle getClipBounds() {
// if (_clip == null) {
// return null;
// }
// Rectangle rect = getClip().getBounds();
// return rect;
// }
/**
* Intersects the current clip with the specified rectangle.
*/
// @Override
// public void clipRect(int x, int y, int width, int height) {
// clip(AwtFactory.getPrototype().newRectangle(x, y, width, height));
// }
/**
* Sets the current clip to the rectangle specified by the given
* coordinates.
*/
@Override
public void setClip(int x, int y, int width, int height) {
setClip(AwtFactory.getPrototype().newRectangle(x, y, width, height));
}
/**
* Gets the current clipping area.
*/
protected GShape getClip() {
if (_clip == null) {
return null;
}
try {
GAffineTransform t = _transform.createInverse();
t.concatenate(_clipTransform);
return t.createTransformedShape(_clip);
} catch (Exception e) {
throw new RuntimeException(
"Unable to get inverse of matrix: " + _transform);
}
}
/**
* Sets the current clipping area to an arbitrary clip shape.
*/
@Override
public void setClip(GShape clip) {
if (clip != null) {
if (_document.isClipSet()) {
append("grestore");
append("gsave");
} else {
_document.setClipSet(true);
append("gsave");
}
draw(clip, "clip", false);
_clip = clip;
// _clipTransform = (GAffineTransform) _transform.clone();
_clipTransform = AwtFactory.getPrototype().newAffineTransform();
_clipTransform.setTransform(_transform);
} else {
if (_document.isClipSet()) {
append("grestore");
_document.setClipSet(false);
}
_clip = null;
}
}
/**
* <b><i><font color="red">Not implemented</font></i></b> - performs no
* action.
*/
// @Override
// public void copyArea(int x, int y, int width, int height, int dx, int dy)
// {
// methodNotSupported();
// }
/**
* Draws a straight line from (x1,y1) to (x2,y2).
*/
@Override
public void drawLine(int x1, int y1, int x2, int y2) {
GLine2D line1 = AwtFactory.getPrototype().newLine2D();
line1.setLine(x1, y1, x2, y2);
draw(line1);
}
/**
* Fills a rectangle with top-left corner placed at (x,y).
*/
@Override
public void fillRect(int x, int y, int width, int height) {
GShape shape = AwtFactory.getPrototype().newRectangle(x, y, width,
height);
draw(shape, "fill", false);
}
/**
* Draws a rectangle with top-left corner placed at (x,y).
*/
@Override
public void drawRect(int x, int y, int width, int height) {
GShape shape = AwtFactory.getPrototype().newRectangle(x, y, width,
height);
draw(shape);
}
/**
* Clears a rectangle with top-left corner placed at (x,y) using the current
* background color.
*/
@Override
public void clearRect(int x, int y, int width, int height) {
GColor originalColor = getColor();
setColor(getBackground());
GShape shape = AwtFactory.getPrototype().newRectangle(x, y, width,
height);
draw(shape, "fill", false);
setColor(originalColor);
}
/**
* Draws a rounded rectangle.
*
* adapted from GGraphics2DW.drawRoundRectangle()
*/
@Override
public void drawRoundRect(int x, int y, int width, int height, int radius,
int arcHeight) {
drawLine(x + radius, y, x + width - radius, y);
GQuadCurve2D arc = AwtFactory.getPrototype().newQuadCurve2D();
arc.setCurve(x + width - radius, y, x + width, y, x + width,
y + radius);
draw(arc);
drawLine(x + width, y + radius, x + width, y + height - radius);
arc.setCurve(x + width, y + height - radius, x + width, y + height,
x + width - radius, y + height);
draw(arc);
drawLine(x + width - radius, y + height, x + radius, y + height);
arc.setCurve(x + radius, y + height, x, y + height, x,
y + height - radius);
draw(arc);
drawLine(x, y + height - radius, x, y + radius);
arc.setCurve(x, y + radius, x, y, x + radius, y);
draw(arc);
}
/**
* Fills a rounded rectangle.
*/
@Override
public void fillRoundRect(int x, int y, int width, int height, int radius,
int arcHeight) {
appendStroke();
append("newpath");
GLine2D line1 = AwtFactory.getPrototype().newLine2D();
line1.setLine(x + radius, y, x + width - radius, y);
draw(line1, null, true);
GQuadCurve2D arc = AwtFactory.getPrototype().newQuadCurve2D();
arc.setCurve(x + width - radius, y, x + width, y, x + width,
y + radius);
draw(arc, null, true);
line1.setLine(x + width, y + radius, x + width, y + height - radius);
draw(line1, null, true);
arc.setCurve(x + width, y + height - radius, x + width, y + height,
x + width - radius, y + height);
draw(arc, null, true);
line1.setLine(x + width - radius, y + height, x + radius, y + height);
draw(line1, null, true);
arc.setCurve(x + radius, y + height, x, y + height, x,
y + height - radius);
draw(arc, null, true);
line1.setLine(x, y + height - radius, x, y + radius);
draw(line1, null, true);
arc.setCurve(x, y + radius, x, y, x + radius, y);
draw(arc, null, true);
append("fill");
append("newpath");
}
/**
* Draws an oval.
*/
// @Override
// public void drawOval(int x, int y, int width, int height) {
// Shape shape = new Ellipse2D.Double(x, y, width, height);
// draw(shape);
// }
/**
* Fills an oval.
*/
// @Override
// public void fillOval(int x, int y, int width, int height) {
// Shape shape = new Ellipse2D.Double(x, y, width, height);
// draw(shape, "fill");
// }
/**
* Draws an arc.
*/
// @Override
// public void drawArc(int x, int y, int width, int height, int startAngle,
// int arcAngle) {
// Shape shape = new Arc2D.Double(x, y, width, height, startAngle,
// arcAngle, Arc2D.OPEN);
// draw(shape);
// }
/**
* Fills an arc.
*/
// @Override
// public void fillArc(int x, int y, int width, int height, int startAngle,
// int arcAngle) {
// Shape shape = new Arc2D.Double(x, y, width, height, startAngle,
// arcAngle, Arc2D.PIE);
// draw(shape, "fill");
// }
/**
* Draws a polyline.
*/
// @Override
// public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
// if (nPoints > 0) {
// GeneralPath path = new GeneralPath();
// path.moveTo(xPoints[0], yPoints[0]);
// for (int i = 1; i < nPoints; i++) {
// path.lineTo(xPoints[i], yPoints[i]);
// }
// draw(path);
// }
// }
/**
* Draws a polygon made with the specified points.
*/
// @Override
// public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
// Shape shape = new Polygon(xPoints, yPoints, nPoints);
// draw(shape);
// }
/**
* Draws a polygon.
*/
// public void drawPolygon(GPolygon p) {
// draw(p);
// }
/**
* Fills a polygon made with the specified points.
*/
// @Override
// public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
// Shape shape = new Polygon(xPoints, yPoints, nPoints);
// draw(shape, "fill");
// }
/**
* Fills a polygon.
*/
// public void fillPolygon(GPolygon p) {
// draw(p, "fill", false);
// }
/**
* Draws the specified characters, starting from (x,y)
*/
// @Override
// public void drawChars(char[] data, int offset, int length, int x, int y)
// {
// String string = new String(data, offset, length);
// drawString(string, x, y);
// }
/**
* Draws the specified bytes, starting from (x,y)
*/
// @Override
// public void drawBytes(byte[] data, int offset, int length, int x, int y)
// {
// String string = new String(data, offset, length);
// drawString(string, x, y);
// }
/**
* Draws an image.
*/
public void drawImage(GBufferedImage img, int x, int y, int width,
int height) {
drawImage(img, x, y, width, height, GColor.WHITE);
}
/**
* Draws an image.
*/
public void drawImage(GBufferedImage img, int x, int y, GColor bgcolor) {
int width = img.getWidth();
int height = img.getHeight();
drawImage(img, x, y, width, height, bgcolor);
}
/**
* Draws an image.
*/
public void drawImage(GBufferedImage img, int x, int y, int width,
int height, GColor bgcolor) {
drawImage(img, x, y, x + width, y + height, 0, 0, width, height,
bgcolor);
}
/**
* Draws an image.
*/
public void drawImage(GBufferedImage img, int dx1, int dy1, int dx2,
int dy2, int sx1, int sy1, int sx2, int sy2) {
drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, GColor.WHITE);
}
/**
* Draws an image.
*/
abstract public void drawImage(GBufferedImage img, int dx1, int dy1,
int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
GColor bgcolor);
/**
* Returns the entire contents of the EPS document, complete with headers
* and bounding box. The returned String is suitable for being written
* directly to disk as an EPS file.
*/
@Override
public String toString() {
if (_document == null) {
return "";
}
return _document.getStream().toString();
}
/**
* Returns true if the specified rectangular area might intersect the
* current clipping area.
*/
// @Override
// public boolean hitClip(int x, int y, int width, int height) {
// if (_clip == null) {
// return true;
// }
// Rectangle rect = new Rectangle(x, y, width, height);
// return hit(rect, _clip, true);
// }
/**
* Returns the bounding rectangle of the current clipping area.
*/
// @Override
// public GRectangle getClipBounds(GRectangle r) {
// if (_clip == null) {
// return r;
// }
// GRectangle rect = getClipBounds();
// r.setLocation((int) rect.getX(), (int) rect.getY());
// r.setSize((int) rect.getWidth(), (int) rect.getHeight());
// return r;
// }
private GColor color;
private GAffineTransform _clipTransform;
private GColor _backgroundColor;
private GPaint _paint;
private GComposite _composite;
private GBasicStroke _stroke;
private GFont _font;
private GShape _clip;
protected GAffineTransform _transform = AwtFactory.getPrototype()
.newAffineTransform();
private boolean _accurateTextMode;
private EpsDocument _document;
private GFontRenderContext _fontRenderContext;
protected ColorMode colorMode = ColorMode.COLOR_RGB;
abstract public GGraphics2D create();
@Override
abstract public void drawImage(MyImage img, int x, int y);
@Override
public void setAntialiasing() {
// TODO Auto-generated method stub
}
@Override
public void setTransparent() {
// TODO Auto-generated method stub
}
@Override
public Object setInterpolationHint(
boolean needsInterpolationRenderingHint) {
return null;
}
@Override
public void resetInterpolationHint(Object oldInterpolationHint) {
//
}
@Override
public void updateCanvasColor() {
// TODO Auto-generated method stub
}
private GLine2D line = AwtFactory.getPrototype().newLine2D();
@Override
public void drawStraightLine(double x1, double y1, double x2, double y2) {
line.setLine(x1, y1, x2, y2);
this.draw(line);
}
private LinkedList<GAffineTransform> transformationStack = new LinkedList<GAffineTransform>();
@Override
public void saveTransform() {
transformationStack.add(getTransform());
}
@Override
public void restoreTransform() {
_transform = transformationStack.removeLast();
}
public void drawChars(char[] data, int offset, int length, int x, int y) {
drawString(new String(data).substring(offset, offset + length), x, y);
}
protected abstract GFontRenderContextD getNewFontRenderContext();
}