/* * Richard A. DeVenezia * June 1, 2004 * Copyright 2004 * * Graphics adaptor for use with SAS javaobj */ package jdsgi; import java.awt.*; import java.awt.image.*; import java.awt.geom.*; import java.io.*; import java.net.*; import java.util.*; import java.util.regex.*; import javax.imageio.*; import java.lang.reflect.*; public class Graphics { private BufferedImage buffer; private BufferedImage readin; private Graphics2D g; private BasicStroke stroke = new BasicStroke(); private Font initialFont; private AffineTransform initialTransform; private ViewportTransform viewportTransform[] = new ViewportTransform[20]; private boolean clip = true; private int activeTransno = 1; private boolean fillmode = false; private double rotationTheta = 0; // rotate any drawn transformed shape this much about its bounding box private DoubleArray xData; private DoubleArray yData; private DoubleArray nData; void createBuffer (double width, double height) { buffer = new BufferedImage ( (int) width, (int) height, BufferedImage.TYPE_INT_RGB ); this.g = buffer.createGraphics(); this.g.setRenderingHint (RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); this.g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (int i=0;i<20;i++) { viewportTransform[i] = new ViewportTransform(this); } this.initialTransform = this.g.getTransform(); this.initialFont = this.g.getFont(); } void setRenderingHint (String keyFieldName, String valueFieldName) { try { Class c = Class.forName ("java.awt.RenderingHints"); Field kf = c.getDeclaredField (keyFieldName); Field vf = c.getDeclaredField (valueFieldName); Object key = kf.get(c); Object value = vf.get(c); this.g.setRenderingHint ((RenderingHints.Key)key, value); } catch (Exception e) { System.out.println (e); } } void setXData (DoubleArray data) { this.xData = data; } void setYData (DoubleArray data) { this.yData = data; } void setNData (DoubleArray data) { this.nData = data; } void clearRect ( double x, double y, double width, double height ) { this.g.clearRect ( (int) x, (int) y, (int) width, (int) height ); } void draw3DRect (double x, double y, double width, double height, double raised) { this.g.draw3DRect ( (int) x, (int) y, (int) width, (int) height, (raised != 0) ); } void drawArc ( double x, double y, double width, double height, double startAngle, double arcAngle ) { this.g.drawArc ( (int) x, (int) y, (int) width, (int) height, (int) startAngle, (int) arcAngle ); } void drawImage ( double x, double y, double bgcolor ) { this.g.drawImage ( readin, (int) x, (int) y, new Color ((int) bgcolor), null ); } void drawLine ( double x1, double y1, double x2, double y2 ) { this.g.drawLine ( (int) x1, (int) y1, (int) x2, (int) y2 ); } void drawOval ( double x, double y, double width, double height ) { this.g.drawOval ( (int) x, (int) y, (int) width, (int) height ); } void drawPolygon ( double x[], double y[] ) { int[] xi = new int[x.length]; int[] yi = new int[y.length]; for (int i=0; i _2_31) rgb = rgb - _2_32; int irgb = (int) rgb; Color c = new Color ( irgb ); this.g.setColor (c); } private static final double _2_32 = 65536.0 * 65536.0; private static final double _2_31 = _2_32 / 2.0; void setColor (double rgb, double hasAlpha) { if (rgb > _2_31) rgb = rgb - _2_32; int irgb = (int) rgb; Color c = new Color ( irgb, (hasAlpha != 0)); this.g.setColor (c); } void setColor (double r, double g, double b) { Color c = new Color ( (int) r, (int) g, (int) b ); this.g.setColor (c); } void setColor (double r, double g, double b, double a) { Color c = new Color ( (int) r, (int) g, (int) b, (int) a ); this.g.setColor (c); } void setColorBrighter () { this.g.setColor (this.g.getColor().brighter()); } void setColorDarker () { this.g.setColor (this.g.getColor().darker()); } void setColorHSB (double hue, double saturation, double brightness) { this.g.setColor (new Color(Color.HSBtoRGB((float)hue,(float)saturation,(float)brightness))); } void setPaintMode () { this.g.setPaintMode(); } void setPaintColor (double rgb) { Color c = new Color ( (int) rgb); this.g.setPaint (c); } void resetPen () { this.stroke = new BasicStroke (); this.g.setStroke (this.stroke); } void resetPenDash () { this.stroke = new BasicStroke ( this.stroke.getLineWidth() , this.stroke.getEndCap() , this.stroke.getLineJoin() , this.stroke.getMiterLimit() , null , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenWidth (double w) { this.stroke = new BasicStroke ( (float) w , this.stroke.getEndCap() , this.stroke.getLineJoin() , this.stroke.getMiterLimit() , this.stroke.getDashArray() , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenEndCap (double p) { this.stroke = new BasicStroke ( this.stroke.getLineWidth() , (int) p , this.stroke.getLineJoin() , this.stroke.getMiterLimit() , this.stroke.getDashArray() , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenLineJoin (double p) { this.stroke = new BasicStroke ( this.stroke.getLineWidth() , this.stroke.getEndCap() , (int) p , this.stroke.getMiterLimit() , this.stroke.getDashArray() , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenMiterLimit (double p) { this.stroke = new BasicStroke ( this.stroke.getLineWidth() , this.stroke.getEndCap() , this.stroke.getLineJoin() , (float) p , this.stroke.getDashArray() , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenDash (double[] dashes) { int n = dashes.length; float dash[] = new float [n]; //System.out.print ("{"); for (int i=0; i0) System.out.print (","); //System.out.print (dash[i]); } //System.out.println ("}"); this.stroke = new BasicStroke ( this.stroke.getLineWidth() , this.stroke.getEndCap() , this.stroke.getLineJoin() , this.stroke.getMiterLimit() , dash , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenDash (DoubleArray dashes) { /* 9.1 bug avoidance, prior use of setNData required */ setPenDash ( dashes.values ); } void setPenDash2 (double p1, double p2) { float dash[] = new float [2]; dash[0] = (float) p1; dash[1] = (float) p2; this.stroke = new BasicStroke ( this.stroke.getLineWidth() , this.stroke.getEndCap() , this.stroke.getLineJoin() , this.stroke.getMiterLimit() , dash , this.stroke.getDashPhase() ); this.g.setStroke (this.stroke); } void setPenDashPhase (double p) { this.stroke = new BasicStroke ( this.stroke.getLineWidth() , this.stroke.getEndCap() , this.stroke.getLineJoin() , this.stroke.getMiterLimit() , this.stroke.getDashArray() , (float) p ); this.g.setStroke (this.stroke); } void tsetViewport (double n, double x1, double y1, double x2, double y2) { ViewportTransform vt = this.viewportTransform [ (int) n ]; vt . setViewport2Point (x1,y1,x2,y2); } void tsetWindow (double n, double x1, double y1, double x2, double y2) { ViewportTransform vt = this.viewportTransform [ (int) n ]; vt . setWindow2Point (x1,y1,x2,y2); } void tsetWindowAspectedForWidth (double n, double x1, double y1, double w) { ViewportTransform vt = this.viewportTransform [ (int) n ]; vt . setWindow1PointWidth (x1,y1,w); } void tsetWindowAspectedForHeight (double n, double x1, double y1, double h) { ViewportTransform vt = this.viewportTransform [ (int) n ]; vt . setWindow1PointHeight (x1,y1,h); } void tgetViewport (double n, DoubleArray data) { ViewportTransform vt = this.viewportTransform [ (int) n ]; double vdata[] = new double[4]; vt.getViewport (vdata); data.setLength(4); System.arraycopy (vdata,0,data.values,0,vdata.length); } void tcomputeAspectedViewport (double n, double x1, double y1, double x2, double y2, DoubleArray data) { ViewportTransform vt = this.viewportTransform [ (int) n ]; double wdata[] = new double[4]; vt.getWindow (wdata); double ww = wdata[2] - wdata[0]; double wh = wdata[3] - wdata[1]; double vw = x2 - x1; double vh = y2 - y1; double kw = ww / wh; double kv = vw / vh; if (kv > kw) x2 = x1 + vh * kw; else if (kv < kw) y2 = y1 + vw / kw; data.setLength(4); data.values[0] = x1; data.values[1] = y1; data.values[2] = x2; data.values[3] = y2; } void tgetWindow (double n, DoubleArray data) { ViewportTransform vt = this.viewportTransform [ (int) n ]; double wdata[] = new double[4]; vt.getWindow (wdata); data.setLength(4); System.arraycopy (wdata,0,data.values,0,wdata.length); } void tgetClipRect (double n, DoubleArray data) { ViewportTransform vt = this.viewportTransform [ (int) n ]; double cdata[] = new double[4]; vt.getClipRect (cdata); data.setLength(4); System.arraycopy (cdata,0,data.values,0,cdata.length); } void tsetClip (double onoff) { this.clip = (onoff != 0); } boolean tgetClip () { return this.clip; } void tsetTransno (double n) { this.activeTransno = (int) n; } int tgetTransno () { return this.activeTransno; } void tsetFillMode (double n) { this.fillmode = (n != 0); } void tsetRotation (double angle) { this.rotationTheta = angle / 180. * Math.PI ; } void tstring (String s, double x, double y) { ViewportTransform vt = this.viewportTransform [ this.activeTransno ]; vt.computePixels (x,y,0,0); AffineTransform at = this.g.getTransform(); this.g.translate (vt.tx,vt.ty); this.g.rotate (-this.rotationTheta); this.g.drawString (s,0,0); this.g.setTransform (at); } void tstringCenter (String s, double x, double y) { AffineTransform at = this.g.getTransform(); Rectangle2D r; ViewportTransform vt = this.viewportTransform [ this.activeTransno ]; vt.computePixels (x,y,0,0); // compute tx & ty r = this.g.getFontMetrics().getStringBounds (s,this.g); this.g.translate (vt.tx, vt.ty); this.g.rotate (-this.rotationTheta); r = this.g.getFontMetrics().getStringBounds (s,this.g); this.g.translate (-r.getWidth()/2,0); this.g.drawString (s,0,0); this.g.setTransform (at); } void tstringRight (String s, double x, double y) { AffineTransform at = this.g.getTransform(); Rectangle2D r; ViewportTransform vt = this.viewportTransform [ this.activeTransno ]; vt.computePixels (x,y,0,0); // compute tx & ty r = this.g.getFontMetrics().getStringBounds (s,this.g); this.g.translate (vt.tx, vt.ty); this.g.rotate (-this.rotationTheta); r = this.g.getFontMetrics().getStringBounds (s,this.g); this.g.translate (-r.getWidth(),0); this.g.drawString (s,0,0); this.g.setTransform (at); } private void drawTransformedShape (Shape s) { ViewportTransform vt; AffineTransform at ; AffineTransform rt ; vt = this.viewportTransform [ this.activeTransno ]; at = vt.getAffineTransform(); if (this.rotationTheta != 0) { Rectangle2D r = s.getBounds2D(); Shape rs; rt = new AffineTransform (); double cx = r.getCenterX(); double cy = r.getCenterY(); // rt.setToIdentity (); // rs = rt.createTransformedShape (s); rs = s; //Shape xs; //xs = at.createTransformedShape (rs); //this.g.setColor (Color.red); //this.g.draw (xs); rt.setToTranslation (-cx,-cy); rs = rt.createTransformedShape (rs); //xs = at.createTransformedShape (rs); //this.g.setColor (Color.blue); //this.g.draw (xs); rt.setToRotation (this.rotationTheta); rs = rt.createTransformedShape (rs); //xs = at.createTransformedShape (rs); //this.g.setColor (Color.green); //this.g.draw (xs); rt.setToTranslation (cx,cy); rs = rt.createTransformedShape (rs); //xs = at.createTransformedShape (rs); //this.g.setColor (Color.blue); //this.g.draw (xs); s = rs; } s = at.createTransformedShape (s); if (clip) vt.clip(); if (this.fillmode) { this.g.fill(s); } else { this.g.draw(s); } vt.clipOff(); } private void tarc (double cx, double cy, double r, double start, double end, double type) { double st = Math.IEEEremainder(start,360.); double en = Math.IEEEremainder(end,360.); if (st < 0) st += 360.; if (en < 0) en += 360.; if (st > en) en += 360.; if (st == en && start != end) en = st + 360; double ex = en - st; double x = cx-r; double y = cy-r; double w = 2*r; double h = 2*r; Arc2D.Double a = new Arc2D.Double (x,y,w,h,-st,-ex,(int)type); drawTransformedShape (a); } void tline (double x1, double y1, double x2, double y2) { Line2D.Double l = new Line2D.Double (x1,y1,x2,y2); drawTransformedShape (l); } void tpolyline (double n, double x[], double y[] ) { GeneralPath p = new GeneralPath(); for (int i=0; i en) en += 360.; if (st == en && start != end) en = st + 360; double ex = en - st; double x = -major; double y = -minor; double w = 2*major; double h = 2*minor; Arc2D.Double a = new Arc2D.Double (x,y,w,h,-st,-ex,(int)type); AffineTransform at = new AffineTransform (); at.rotate (angle / 180. * Math.PI); at.translate (cx,-cy); Shape ea = at.createTransformedShape (a); drawTransformedShape (ea); } void setXORMode (String rgbHex) { Color c = new Color (Integer.parseInt(rgbHex,16)); this.g.setXORMode(c); } void readImage (String source) { readin = null; try { this.readin = ImageIO.read (new File(source)); } catch (Exception e1) { try { this.readin = ImageIO.read (new URL(source)); } catch (Exception e2) { System.out.println (source+" could not be read as a File or URL"); } } } String saveAs ( String type, String name ) { try { Iterator i = ImageIO.getImageWritersByFormatName(type); if (!i.hasNext()) { System.out.println ("No image writer registered for type "+type); return ""; } } catch (Exception e) { System.out.println (e); return ""; } String savedAs = ""; try { File file = new File(name); savedAs = file.getCanonicalPath(); ImageIO.write (this.buffer, type, new File(savedAs)); } catch (Exception e) { System.out.println (e); savedAs = ""; } return savedAs; } void reportFormats () { try { String readFormats[] = ImageIO.getReaderMIMETypes(); String writeFormats[] = ImageIO.getWriterMIMETypes(); System.out.println("\nReaders: " + Arrays.asList(readFormats) .toString().replaceAll(",|;","\n")); System.out.println("\nWriters: " + Arrays.asList(writeFormats).toString().replaceAll(",|;","\n")); System.out.println("\nSystem properties: "+System.getProperties().toString().replaceAll(",|;","\n")); } catch (Exception e) { System.out.println (e); } } private int wfni = -1; String getWriterFormatNames () { wfni ++; if (wfni >= ImageIO.getWriterFormatNames().length) { wfni = -1; return ""; } else return ImageIO.getWriterFormatNames()[wfni]; } private int mni = -1; String getMethodNames () { mni ++; Class c = this.getClass(); if (mni >= c.getDeclaredMethods().length) { mni =- 1; return ""; } else return c.getDeclaredMethods()[mni].toString(); } }