import java.awt.geom.*;
import java.io.*;
import java.awt.font.*;
import java.awt.*;
import java.util.*;
import java.awt.image.*;
import java.awt.image.renderable.*;
import java.text.*;
import javax.swing.*;
public class GraphicsV extends Graphics2D {
File out;
Graphics2D superior;
JComponent comp;
int format;
String contents; //file contents
//for WMF files
ByteArrayOutputStream storCont, storHeader;
int nObj, maxSize, brushNum;
public static final int SVG = 1;
public static final int WMF = 2;
Color c;
Font f;
//WMF Definitions
public static final int MAPMODE = 0x0103;
public static final int WINORG = 0x020B;
public static final int WINEXT = 0x020C;
public static final int BKGMODE = 0x0102;
public static final int BKGCOLOR = 0x0201;
public static final int EOF = 0x0000;
public static final int SELECT = 0x012D;
public static final int BRUSH = 0x02FC;
public static final int PEN = 0x02FA;
public static final int MOVETO = 0x0214;
public static final int LINETO = 0x0213;
public static final int ELLIPSE = 0x0418;
public static final int RECTANGLE = 0x041B;
public static final int POLYLINE = 0x0325;
public static final int POLYGON = 0x0324;
public static final int PIE = 0x081A;
public static final int FONT = 0x02FB;
public static final int TXTCOL = 0x0209;
public static final int TXTALI = 0x012E;
public static final int TEXT = 0x0A32;
public GraphicsV(File out, JComponent comp, int format) {
this.out = out;
this.superior = (Graphics2D)comp.getGraphics();
this.comp = comp;
this.format = format;
c = Color.black;
f = new Font("Dialog",Font.PLAIN,12);
contents = "";
storCont = new ByteArrayOutputStream();
storHeader = new ByteArrayOutputStream();
nObj = 0;
maxSize = 0;
brushNum = -1;
//header
if(format == SVG) {
contents += "\n";
contents += "\n";
contents += "\n";
} else {
try {
int[] zero = new int[0];
writeRecord(EOF, zero, true, null);
//do header here
//placeable metafile header
writeInt(storHeader, 0x9AC6CDD7); //key
writeShort(storHeader, 0); //reserved
writeShort(storHeader, 0); //x0
writeShort(storHeader, 0); //y0
writeShort(storHeader, comp.getWidth());
writeShort(storHeader, comp.getHeight());
writeShort(storHeader, 96); //resolution in twips/in //1440
writeInt(storHeader, 0); //reserved
writeShort(storHeader, checkSum(storHeader.toByteArray()));
//(storHeader, 0x9AC6 ^ 0xCDD7 ^ 0 ^ 0 ^ 0 ^ comp.getWidth() ^ comp.getHeight() ^ 1440 ^ 0 ^ 0); //checksum
//standard metafile header
writeShort(storHeader, 1); //disk
writeShort(storHeader, 9); //header size
writeShort(storHeader, 0x0300); //MS-WIN version
writeInt(storHeader, storCont.size()/2+9+11); //size of file in words
if(brushNum < 0)
brushNum = 0;
writeShort(storHeader, brushNum); //num objects
writeInt(storHeader, maxSize); //max record size
writeShort(storHeader, 0); //reserved
} catch(IOException ioe) {
//meaningless
}
}
//write to file
out.delete();
try {
RandomAccessFile raf = new RandomAccessFile(out, "rw");
if(format == SVG) {
raf.writeBytes(contents);
} else {
raf.write(storHeader.toByteArray());
raf.write(storCont.toByteArray());
}
raf.close();
} catch(IOException ioe) {
System.out.println(ioe.toString());
}
contents = null;
storCont = null;
storHeader = null;
}
public String getHTMLColor(Color c) {
//the idea is: #RRGGBB; added the first term to fill in zeros
double toConv = 1*Math.pow(16,6)+c.getRed()*Math.pow(16,4)+c.getGreen()*Math.pow(16,2)+c.getBlue()*Math.pow(16,0);
String hex = Integer.toHexString((int)toConv).toUpperCase();
return ("#"+hex.substring(1));
}
public byte[] getBinaryColor(Color c) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4);
DataOutputStream dos = new DataOutputStream(baos);
dos.writeByte(c.getRed());
dos.writeByte(c.getGreen());
dos.writeByte(c.getBlue());
dos.writeByte(0);
return baos.toByteArray();
} catch(IOException ioe) {
return null;
}
}
public byte[] getFontName(Font f) {
if(f.getFamily().equals("dialog")) {
byte[] name = { (byte)65, (byte)114, (byte)105, (byte)97, (byte)108, (byte)0, (byte)0, (byte)48 }; //(Arial)
return name;
} else if(f.getFamily().equals("serif")) {
byte[] name = { (byte)84, (byte)105, (byte)109, (byte)101, (byte)115, (byte)32, (byte)78, (byte)101, (byte)119, (byte)32, (byte)82, (byte)111, (byte)109, (byte)97, (byte)110, (byte)0, (byte)0, (byte)147 }; //(Times New Roman)
return name;
} else {
System.out.println("Error: Font Family Not Recognized: "+f.getFamily());
byte[] name = { (byte)65, (byte)114, (byte)105, (byte)97, (byte)108, (byte)0, (byte)0, (byte)48 }; //(Arial)
return name;
}
}
public int checkSum(byte[] b) {
short xor = 0;
ByteArrayInputStream bais = new ByteArrayInputStream(b);
DataInputStream dis = new DataInputStream(bais);
while(true) {
try {
xor ^= dis.readShort();
} catch (EOFException eof) {
break;
} catch (IOException ioe) {
return 0;
}
}
bais = null;
dis = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeShort(xor);
byte[] litEnd = baos.toByteArray();
byte[] bigEnd = { litEnd[1], litEnd[0] };
bais = new ByteArrayInputStream(bigEnd);
dis = new DataInputStream(bais);
int newxor = (int)dis.readShort();
bais = null;
dis = null;
return newxor;
} catch(IOException ioe) {
return 0;
}
}
public String getFontStyle(int fs) {
if(fs == Font.BOLD)
return "font-weight=\"bold\"";
else if(fs == Font.ITALIC)
return "font-style=\"italic\"";
else
return "";
}
public void writeRecord(int func, int[] params, boolean reverse, byte[] direct) { //version for integer array
try {
int recSize = 2+1+params.length;
if(direct != null)
recSize += direct.length/2 - 1; //(we assume direct byte writing is only occuring ONCE in a record)
if(recSize > maxSize)
maxSize = recSize;
writeInt(storCont, recSize);
writeShort(storCont, func);
if(reverse) {
for(int i = params.length-1; i >= 0; i--) { //store params in reverse
if(params[i] != -1)
writeShort(storCont, params[i]);
else
storCont.write(direct);
}
} else {
for(int i = 0; i < params.length; i++) { //store params in reverse
if(params[i] != -1)
writeShort(storCont, params[i]);
else
storCont.write(direct);
}
}
nObj++;
} catch(IOException ioe) {
System.out.println("Error in WMF generation!");
}
}
public void writeShort(ByteArrayOutputStream out, int i) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeShort(i);
byte[] bigEnd = baos.toByteArray();
if(bigEnd.length != 2) {
System.out.println("Weird behavior from ByteArrayOutputStream!");
return;
}
byte[] litEnd = { bigEnd[1], bigEnd[0] };
out.write(litEnd);
baos = null;
dos = null;
}
public void writeInt(ByteArrayOutputStream out, int i) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(i);
byte[] bigEnd = baos.toByteArray();
if(bigEnd.length != 4) {
System.out.println("Weird behavior from ByteArrayOutputStream!");
return;
}
byte[] litEnd = { bigEnd[3], bigEnd[2], bigEnd[1], bigEnd[0] };
out.write(litEnd);
baos = null;
dos = null;
}
public byte[] getBytes(String s) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeBytes(s);
if(dos.size() % 2 != 0)
dos.writeByte(0);
byte[] bytes = baos.toByteArray();
baos = null;
dos = null;
return bytes;
} catch(IOException ioe) {
return null;
}
}
public void writeBrushAndPen(boolean filled) {
//create "brush"
int[] brushtype = new int[3];
brushtype[0] = 0;
brushtype[1] = -1;
if(filled)
brushtype[2] = 0; //1=not filled, 0=filled
else
brushtype[2] = 1;
writeRecord(BRUSH, brushtype, true, getBinaryColor(c));
brushNum++;
int[] select = { brushNum };
writeRecord(SELECT, select, true, null);
//create "pen"
int[] pentype = new int[4];
pentype[0] = -1;
pentype[1] = 0;
pentype[2] = 0;
pentype[3] = 0;
writeRecord(PEN, pentype, true, getBinaryColor(c));
brushNum++;
int[] select2 = { brushNum };
writeRecord(SELECT, select2, true, null);
}
//////////////***********Begin Drawing Commands*****************\\\\\\\\\\\\\\\\\\\
public void draw(Shape s) {
if(s instanceof Line2D) {
Line2D line = (Line2D)s;
if(format == SVG) {
contents += "\n";
return;
} else {
writeBrushAndPen(false);
int[] point1 = { (int)line.getX1(), (int)line.getY1() };
writeRecord(MOVETO,point1, true, null);
int[] point2 = { (int)line.getX2(), (int)line.getY2() };
writeRecord(LINETO,point2, true, null);
return;
}
}
if(s instanceof Ellipse2D) {
Ellipse2D ellipse = (Ellipse2D)s;
if(format == SVG) {
double radx = ellipse.getMaxX()-ellipse.getCenterX();
double rady = ellipse.getMaxY()-ellipse.getCenterY();
contents += "\n";
return;
} else {
writeBrushAndPen(false);
int[] points = { (int)ellipse.getMinX(), (int)ellipse.getMinY(), (int)ellipse.getMaxX(), (int)ellipse.getMaxY() };
writeRecord(ELLIPSE,points, true, null);
return;
}
}
if(s instanceof Rectangle2D) {
Rectangle2D rect = (Rectangle2D)s;
if(format == SVG) {
contents += "\n";
return;
} else {
writeBrushAndPen(false);
int[] points = { (int)rect.getMinX(), (int)rect.getMinY(), (int)rect.getMaxX(), (int)rect.getMaxY() };
writeRecord(RECTANGLE,points, true, null);
return;
}
}
if(s instanceof GeneralPath) {
GeneralPath path = (GeneralPath)s;
PathIterator it = path.getPathIterator(superior.getTransform());
if(format == SVG) {
contents += "\n";
return;
} else {
Vector v = new Vector();
while(!it.isDone()) {
double[] points = new double[6];
int type = it.currentSegment(points);
if(type == PathIterator.SEG_LINETO || type == PathIterator.SEG_MOVETO) {
int[] point = { (int)points[0], (int)points[1] };
v.add(point);
} else if(type == PathIterator.SEG_CLOSE) {
} else {
System.out.println("Path Segment type not supported: "+type);
}
it.next();
}
int[] poly = new int[v.size()*2+1];
poly[0] = v.size();
int p = 1;
for(int i = 1; i < v.size(); i++) {
int[] point = (int[])v.elementAt(i);
poly[p] = point[0];
poly[p+1] = point[1];
p += 2;
}
writeBrushAndPen(false);
writeRecord(POLYLINE,poly,false, null);
return;
}
}
if(s instanceof Arc2D) {
Arc2D arc = (Arc2D)s;
if(format == SVG) {
//implement as a path
PathIterator it = arc.getPathIterator(superior.getTransform());
contents += "\n";
return;
} else {
writeBrushAndPen(false);
Rectangle2D bounds = arc.getBounds();
Point2D end = arc.getStartPoint();
Point2D start = arc.getEndPoint();
int[] points = { (int)bounds.getMinX(), (int)bounds.getMinY(), (int)bounds.getMaxX(), (int)bounds.getMaxY(), (int)start.getX(), (int)start.getY(), (int)end.getX(), (int)end.getY() };
writeRecord(PIE,points, true, null);
return;
}
}
System.out.println("Shape not supported: "+s.getClass());
}
public void fill(Shape s) {
if(s instanceof Ellipse2D) {
Ellipse2D ellipse = (Ellipse2D)s;
if(format == SVG) {
double radx = ellipse.getMaxX()-ellipse.getCenterX();
double rady = ellipse.getMaxY()-ellipse.getCenterY();
contents += "\n";
return;
} else {
writeBrushAndPen(true);
int[] points = { (int)ellipse.getMinX(), (int)ellipse.getMinY(), (int)ellipse.getMaxX(), (int)ellipse.getMaxY() };
writeRecord(ELLIPSE,points, true, null);
return;
}
}
if(s instanceof Rectangle2D) {
Rectangle2D rect = (Rectangle2D)s;
if(format == SVG) {
contents += "\n";
return;
} else {
writeBrushAndPen(true);
int[] points = { (int)rect.getMinX(), (int)rect.getMinY(), (int)rect.getMaxX(), (int)rect.getMaxY() };
writeRecord(RECTANGLE,points, true, null);
return;
}
}
if(s instanceof GeneralPath) {
GeneralPath path = (GeneralPath)s;
PathIterator it = path.getPathIterator(superior.getTransform());
if(format == SVG) {
contents += "\n";
return;
} else {
Vector v = new Vector();
while(!it.isDone()) {
double[] points = new double[6];
int type = it.currentSegment(points);
if(type == PathIterator.SEG_LINETO || type == PathIterator.SEG_MOVETO) {
int[] point = { (int)points[0], (int)points[1] };
v.addElement(point);
} else if(type == PathIterator.SEG_CLOSE) {
} else {
System.out.println("Path Segment type not supported: "+type);
}
it.next();
}
int[] poly = new int[v.size()*2+1];
poly[0] = v.size();
int p = 1;
for(int i = 0; i < v.size(); i++) {
int[] point = (int[])v.elementAt(i);
poly[p] = point[0];
poly[p+1] = point[1];
p += 2;
}
writeBrushAndPen(true);
writeRecord(POLYGON,poly,false, null);
return;
}
}
if(s instanceof Arc2D) {
Arc2D arc = (Arc2D)s;
if(format == SVG) {
//implement as a path
PathIterator it = arc.getPathIterator(superior.getTransform());
contents += "\n";
return;
} else {
writeBrushAndPen(true);
Rectangle2D bounds = arc.getBounds();
Point2D end = arc.getStartPoint();
Point2D start = arc.getEndPoint();
int[] points = { (int)bounds.getMinX(), (int)bounds.getMinY(), (int)bounds.getMaxX(), (int)bounds.getMaxY(), (int)start.getX(), (int)start.getY(), (int)end.getX(), (int)end.getY() };
writeRecord(PIE,points, true, null);
return;
}
}
System.out.println("Shape not supported: "+s.getClass());
}
public void drawString(String s, float x, float y) {
if(format == SVG) {
contents += "";
contents += s+"\n";
} else {
//set font
int weight;
if(f.getStyle() == Font.BOLD)
weight = 700;
else
weight = 400;
int[] fontprops = { f.getSize(), 0, 0, 0, weight, -1 };
byte[] name = getFontName(f);
byte[] fontprops2 = new byte[8+name.length];
if(f.getStyle() == Font.ITALIC) //italic
fontprops2[0] = 1;
else
fontprops2[0] = 0;
fontprops2[1] = 0; //underline
fontprops2[2] = 0; //strikeout
fontprops2[3] = 0; //charset
fontprops2[4] = 0; //outprecision
fontprops2[5] = 0; //clip precision
fontprops2[6] = 0; //quality
fontprops2[7] = 34; //pitch&family
for(int i = 0; i < name.length; i++) {
fontprops2[i+8] = name[i];
}
writeRecord(FONT,fontprops,false,fontprops2);
brushNum++;
int[] select = { brushNum };
writeRecord(SELECT, select, false, null);
//set color
int[] col = { -1 };
writeRecord(TXTCOL,col,true,getBinaryColor(c));
//set alignment
int[] align = { 24 };
writeRecord(TXTALI,align,true,null);
//write string
byte[] strInBytes = getBytes(s);
int[] params = { (int)y, (int)x, strInBytes.length, 0, -1 };
writeRecord(TEXT, params, false, strInBytes);
}
}
public void drawString(String s, int x, int y) {
drawString(s,(float)x,(float)y);
}
public FontMetrics getFontMetrics() {
return superior.getFontMetrics(f);
}
public void setColor(Color c) {
this.c = c;
}
public Color getColor() {
return c;
}
public void setFont(Font f) {
this.f = f;
}
public Font getFont() {
return f;
}
//***********************End Implemented Drawing Commands**************************//
public void setStroke(Stroke s) {
superior.setStroke(s);
}
public void setPaint(Paint p) {
System.out.println(p);
}
public void drawString(AttributedCharacterIterator iterator, float x, float y) {
superior.drawString(iterator, x, y);
}
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
superior.drawString(iterator, x, y);
}
public FontRenderContext getFontRenderContext() {
return superior.getFontRenderContext();
}
public void clip(Shape s) {
superior.clip(s);
}
public Stroke getStroke() {
return superior.getStroke();
}
public Color getBackground() {
return superior.getBackground();
}
public void setBackground(Color c) {
superior.setBackground(c);
}
public Composite getComposite() {
return superior.getComposite();
}
public Paint getPaint() {
return superior.getPaint();
}
public AffineTransform getTransform() {
return superior.getTransform();
}
public void setTransform(AffineTransform at) {
superior.setTransform(at);
}
public void transform(AffineTransform at) {
superior.transform(at);
}
public void shear(double shx, double shy) {
superior.shear(shx, shy);
}
public void scale(double sx, double sy) {
superior.scale(sx, sy);
}
public void rotate(double theta, double x, double y) {
superior.rotate(theta, x, y);
}
public void rotate(double theta) {
superior.rotate(theta);
}
public void translate(double tx, double ty) {
superior.translate(tx, ty);
}
public void translate(int tx, int ty) {
superior.translate(tx, ty);
}
public RenderingHints getRenderingHints() {
return superior.getRenderingHints();
}
public void addRenderingHints(Map m) {
superior.addRenderingHints(m);
}
public void setRenderingHints(Map m) {
superior.setRenderingHints(m);
}
public Object getRenderingHint(RenderingHints.Key hintKey) {
return superior.getRenderingHint(hintKey);
}
public void setRenderingHint(RenderingHints.Key hintKey, Object o) {
superior.setRenderingHint(hintKey, o);
}
public void setComposite(Composite c) {
superior.setComposite(c);
}
public GraphicsConfiguration getDeviceConfiguration() {
return superior.getDeviceConfiguration();
}
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
return superior.hit(rect, s, onStroke);
}
public void drawGlyphVector(GlyphVector g, float x, float y) {
superior.drawGlyphVector(g, x, y);
}
public void drawRenderableImage(RenderableImage image, AffineTransform at) {
superior.drawRenderableImage(image, at);
}
public void drawRenderedImage(RenderedImage image, AffineTransform at) {
superior.drawRenderedImage(image, at);
}
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
superior.drawImage(img, op, x, y);
}
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
return superior.drawImage(img, xform, obs);
}
public void dispose() {
}
public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
return superior.drawImage(img, x, y, width, height, bgcolor, observer);
}
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) {
return superior.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
}
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) {
return superior.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
}
public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
return superior.drawImage(img, x, y, bgcolor, observer);
}
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
return superior.drawImage(img, x, y, width, height, observer);
}
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
return superior.drawImage(img, x, y, observer);
}
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
superior.fillPolygon(xPoints, yPoints, nPoints);
}
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
superior.drawPolygon(xPoints, yPoints, nPoints);
}
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
superior.drawPolyline(xPoints, yPoints, nPoints);
}
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
superior.fillArc(x, y, width, height, startAngle, arcAngle);
}
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
superior.drawArc(x, y, width, height, startAngle, arcAngle);
}
public void fillOval(int x, int y, int width, int height) {
superior.fillOval(x, y, width, height);
}
public void drawOval(int x, int y, int width, int height) {
superior.drawOval(x, y, width, height);
}
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
superior.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
}
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
superior.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
}
public void clearRect(int x, int y, int width, int height) {
superior.clearRect(x, y, width, height);
}
public void fillRect(int x, int y, int width, int height) {
superior.fillRect(x, y, width, height);
}
public void drawLine(int x1, int y1, int x2, int y2) {
superior.drawLine(x1, y1, x2, y2);
}
public void copyArea(int x, int y, int width, int height, int dx, int dy) {
superior.copyArea(x, y, width, height, dx, dy);
}
public void setClip(int x, int y, int width, int height) {
superior.setClip(x, y, width, height);
}
public void setClip(Shape s) {
superior.setClip(s);
}
public Shape getClip() {
return superior.getClip();
}
public void clipRect(int x, int y, int width, int height) {
superior.clipRect(x, y, width, height);
}
public Rectangle getClipBounds() {
return superior.getClipBounds();
}
public FontMetrics getFontMetrics(Font f) {
return superior.getFontMetrics(f);
}
public void setXORMode(Color c1) {
superior.setXORMode(c1);
}
public void setPaintMode() {
superior.setPaintMode();
}
public Graphics create() {
return superior;
}
}