001package com.hfg.graphics; 002 003import java.awt.BasicStroke; 004import java.awt.Color; 005import java.awt.Composite; 006import java.awt.Font; 007import java.awt.FontMetrics; 008import java.awt.Graphics; 009import java.awt.Graphics2D; 010import java.awt.GraphicsConfiguration; 011import java.awt.Image; 012import java.awt.Paint; 013import java.awt.Point; 014import java.awt.Rectangle; 015import java.awt.RenderingHints; 016import java.awt.Shape; 017import java.awt.Stroke; 018import java.awt.font.GlyphVector; 019import java.awt.font.FontRenderContext; 020import java.awt.geom.Point2D; 021import java.awt.image.ImageObserver; 022import java.awt.image.BufferedImage; 023import java.awt.image.BufferedImageOp; 024import java.awt.image.RenderedImage; 025import java.awt.image.renderable.RenderableImage; 026import java.awt.geom.AffineTransform; 027import java.awt.geom.Line2D; 028import java.text.AttributedCharacterIterator; 029import java.util.Map; 030import java.util.Stack; 031 032import com.hfg.css.CSS; 033import com.hfg.exception.UnimplementedMethodException; 034import com.hfg.xml.XMLTag; 035import com.hfg.svg.*; 036 037//------------------------------------------------------------------------------ 038/** 039 * Simple Graphics2D class which can be used to generate SVG. Not yet with full functionality. 040 * <div> 041 * @author J. Alex Taylor, hairyfatguy.com 042 * </div> 043 */ 044//------------------------------------------------------------------------------ 045// com.hfg XML/HTML Coding Library 046// 047// This library is free software; you can redistribute it and/or 048// modify it under the terms of the GNU Lesser General Public 049// License as published by the Free Software Foundation; either 050// version 2.1 of the License, or (at your option) any later version. 051// 052// This library is distributed in the hope that it will be useful, 053// but WITHOUT ANY WARRANTY; without even the implied warranty of 054// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 055// Lesser General Public License for more details. 056// 057// You should have received a copy of the GNU Lesser General Public 058// License along with this library; if not, write to the Free Software 059// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 060// 061// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 062// jataylor@hairyfatguy.com 063//------------------------------------------------------------------------------ 064 065public class SvgGraphics2D extends Graphics2D 066{ 067 private Paint mCurrentPaint = sDefaultPaint; 068 private Color mCurrentBackground = Color.BLACK; 069 private Font mCurrentFont = new Font("sanserif", Font.PLAIN, 12); 070 private Stroke mCurrentStroke = sDefaultStroke; 071 private int mCurrentX; 072 private int mCurrentY; 073 074 private SVG mRootTag = new SVG(); 075 private Stack<XMLTag> mTagStack = new Stack<>(); 076 private Stack<AffineTransform> mTransformStack = new Stack<>(); 077 078 079 private static Paint sDefaultPaint = Color.BLACK; 080 private static Stroke sDefaultStroke = null; //new BasicStroke(); 081 /** 082 * Used to create proper font metrics 083 */ 084 private static Graphics2D sG2D = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).createGraphics(); 085 086 private static FontRenderContext sFRC; 087 088 static 089 { 090 AffineTransform frcTransform = new AffineTransform(); 091 frcTransform.scale(96f/72f, 1); 092 sFRC = new FontRenderContext(frcTransform, false, false); 093 } 094 095 //########################################################################## 096 // CONSTRUCTORS 097 //########################################################################## 098 099 //-------------------------------------------------------------------------- 100 public SvgGraphics2D() 101 { 102 mTagStack.push(mRootTag); 103 mTransformStack.push(new AffineTransform()); 104 } 105 106 //########################################################################## 107 // PUBLIC METHODS 108 //########################################################################## 109 110 //-------------------------------------------------------------------------- 111 public SVG getRootTag() 112 { 113 return mRootTag; 114 } 115 116 //-------------------------------------------------------------------------- 117 public void draw(Shape shape) 118 { 119 throw new UnimplementedMethodException(); 120 } 121 122 //-------------------------------------------------------------------------- 123 public boolean drawImage(Image image, AffineTransform affineTransform, ImageObserver imageObserver) 124 { 125 throw new UnimplementedMethodException(); 126 } 127 128 //-------------------------------------------------------------------------- 129 public void drawImage(BufferedImage bufferedImage, BufferedImageOp bufferedImageOp, int i, int i1) 130 { 131 throw new UnimplementedMethodException(); 132 } 133 134 //-------------------------------------------------------------------------- 135 public void drawRenderedImage(RenderedImage renderedImage, AffineTransform affineTransform) 136 { 137 throw new UnimplementedMethodException(); 138 } 139 140 //-------------------------------------------------------------------------- 141 public void drawRenderableImage(RenderableImage renderableImage, AffineTransform affineTransform) 142 { 143 throw new UnimplementedMethodException(); 144 } 145 146 //-------------------------------------------------------------------------- 147 public void drawString(String inString, int x, int y) 148 { 149 drawString(inString, (float)x, (float)y); 150 } 151 152 //-------------------------------------------------------------------------- 153 public void drawString(String inString, float x, float y) 154 { 155 SvgText textTag = new SvgText(inString, getFont(), new Point2D.Float(x, y)); 156 textTag.addStyle("font-family:" + getFont().getFamily()); 157 textTag.addStyle(CSS.fontSize(getFont().getSize())); 158 if (mCurrentPaint instanceof Color) textTag.addStyle("fill:#" + ColorUtil.colorToHex(getColor())); 159 mTagStack.peek().addSubtag(textTag); 160 } 161 162 //-------------------------------------------------------------------------- 163 public void drawString(AttributedCharacterIterator attributedCharacterIterator, int i, int i1) 164 { 165 throw new UnimplementedMethodException(); 166 } 167 168 //-------------------------------------------------------------------------- 169 public void drawString(AttributedCharacterIterator attributedCharacterIterator, float v, float v1) 170 { 171 throw new UnimplementedMethodException(); 172 } 173 174 //-------------------------------------------------------------------------- 175 public boolean drawImage(Image image, int i, int i1, ImageObserver imageObserver) 176 { 177 throw new UnimplementedMethodException(); 178 } 179 180 //-------------------------------------------------------------------------- 181 public boolean drawImage(Image image, int i, int i1, int i2, int i3, ImageObserver imageObserver) 182 { 183 throw new UnimplementedMethodException(); 184 } 185 186 //-------------------------------------------------------------------------- 187 public boolean drawImage(Image image, int i, int i1, Color color, ImageObserver imageObserver) 188 { 189 throw new UnimplementedMethodException(); 190 } 191 192 //-------------------------------------------------------------------------- 193 public boolean drawImage(Image image, int i, int i1, int i2, int i3, Color color, ImageObserver imageObserver) 194 { 195 throw new UnimplementedMethodException(); 196 } 197 198 //-------------------------------------------------------------------------- 199 public boolean drawImage(Image image, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7, ImageObserver imageObserver) 200 { 201 throw new UnimplementedMethodException(); 202 } 203 204 //-------------------------------------------------------------------------- 205 public boolean drawImage(Image image, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7, Color color, ImageObserver imageObserver) 206 { 207 throw new UnimplementedMethodException(); 208 } 209 210 //-------------------------------------------------------------------------- 211 public void dispose() 212 { 213 throw new UnimplementedMethodException(); 214 } 215 216 //-------------------------------------------------------------------------- 217 public void drawGlyphVector(GlyphVector glyphVector, float v, float v1) 218 { 219 throw new UnimplementedMethodException(); 220 } 221 222 //-------------------------------------------------------------------------- 223 public void fill(Shape shape) 224 { 225 if (shape instanceof Rectangle) 226 { 227 fill((Rectangle) shape); 228 } 229 else 230 { 231 throw new UnimplementedMethodException(); 232 } 233 } 234 235 //-------------------------------------------------------------------------- 236 public boolean hit(Rectangle rectangle, Shape shape, boolean b) 237 { 238 throw new UnimplementedMethodException(); 239 } 240 241 //-------------------------------------------------------------------------- 242 public GraphicsConfiguration getDeviceConfiguration() 243 { 244 throw new UnimplementedMethodException(); 245 } 246 247 //-------------------------------------------------------------------------- 248 public void setComposite(Composite composite) 249 { 250 throw new UnimplementedMethodException(); 251 } 252 253 //-------------------------------------------------------------------------- 254 public void setRenderingHint(RenderingHints.Key key, Object object) 255 { 256 throw new UnimplementedMethodException(); 257 } 258 259 //-------------------------------------------------------------------------- 260 public Object getRenderingHint(RenderingHints.Key key) 261 { 262 throw new UnimplementedMethodException(); 263 } 264 265 //-------------------------------------------------------------------------- 266 public void setRenderingHints(Map<?, ?> map) 267 { 268 throw new UnimplementedMethodException(); 269 } 270 271 //-------------------------------------------------------------------------- 272 public void addRenderingHints(Map<?, ?> map) 273 { 274 throw new UnimplementedMethodException(); 275 } 276 277 //-------------------------------------------------------------------------- 278 public RenderingHints getRenderingHints() 279 { 280 throw new UnimplementedMethodException(); 281 } 282 283 //-------------------------------------------------------------------------- 284 public Graphics create() 285 { 286 throw new UnimplementedMethodException(); 287 } 288 289 //-------------------------------------------------------------------------- 290 public Font getFont() 291 { 292 return mCurrentFont; 293 } 294 295 //-------------------------------------------------------------------------- 296 public void setFont(Font inFont) 297 { 298 mCurrentFont = inFont; 299 } 300 301 //-------------------------------------------------------------------------- 302 public FontMetrics getFontMetrics(Font inFont) 303 { 304 return sG2D.getFontMetrics(inFont); 305 } 306 307 //-------------------------------------------------------------------------- 308 public Rectangle getClipBounds() 309 { 310 throw new UnimplementedMethodException(); 311 } 312 313 //-------------------------------------------------------------------------- 314 public void clipRect(int i, int i1, int i2, int i3) 315 { 316 throw new UnimplementedMethodException(); 317 } 318 319 //-------------------------------------------------------------------------- 320 public void setClip(int i, int i1, int i2, int i3) 321 { 322 throw new UnimplementedMethodException(); 323 } 324 325 //-------------------------------------------------------------------------- 326 public Shape getClip() 327 { 328 throw new UnimplementedMethodException(); 329 } 330 331 //-------------------------------------------------------------------------- 332 public void setClip(Shape shape) 333 { 334 throw new UnimplementedMethodException(); 335 } 336 337 //-------------------------------------------------------------------------- 338 public void copyArea(int i, int i1, int i2, int i3, int i4, int i5) 339 { 340 throw new UnimplementedMethodException(); 341 } 342 343 //-------------------------------------------------------------------------- 344 public void drawLine(int x1, int y1, int x2, int y2) 345 { 346 if (! mCurrentStroke.equals(sDefaultStroke)) 347 { 348 draw(mCurrentStroke.createStrokedShape(new Line2D.Float(x1, y1, x2, y2))); 349 } 350 else 351 { 352 SvgLine lineTag = new SvgLine(new Point(x1, y1), new Point(x2, y2)); 353 if (! mCurrentPaint.equals(sDefaultPaint)) lineTag.addStyle(CSS.color(getColor())); 354 mTagStack.peek().addSubtag(lineTag); 355 } 356 } 357 358 //-------------------------------------------------------------------------- 359 // A convenience method 360 public void fill(Rectangle inRect) 361 { 362 fillRect(inRect.x, inRect.y, inRect.x + inRect.width, inRect.y + inRect.height); 363 } 364 365 //-------------------------------------------------------------------------- 366 public void fillRect(int x1, int y1, int x2, int y2) 367 { 368 Rectangle rect = new Rectangle(x1, y1, x2, y2); 369 if (null == mCurrentStroke 370 || mCurrentStroke instanceof BasicStroke) 371 { 372 SvgRect rectTag = new SvgRect(rect); 373 if (mCurrentPaint instanceof Color) rectTag.addStyle("fill:#" + ColorUtil.colorToHex(getColor())); 374 float lineWidth = mCurrentStroke != null ? ((BasicStroke) mCurrentStroke).getLineWidth() : 0; 375 if (lineWidth > 0) 376 { 377 rectTag.addStyle("stroke-width:" + lineWidth + "px"); 378 rectTag.addStyle("stroke:#" + ColorUtil.colorToHex(mCurrentBackground)); 379 } 380 mTagStack.peek().addSubtag(rectTag); 381 } 382 else 383 { 384 draw(mCurrentStroke.createStrokedShape(rect)); 385 } 386 387 } 388 389 //-------------------------------------------------------------------------- 390 public void clearRect(int i, int i1, int i2, int i3) 391 { 392 throw new UnimplementedMethodException(); 393 } 394 395 //-------------------------------------------------------------------------- 396 public void drawRoundRect(int i, int i1, int i2, int i3, int i4, int i5) 397 { 398 throw new UnimplementedMethodException(); 399 } 400 401 //-------------------------------------------------------------------------- 402 public void fillRoundRect(int i, int i1, int i2, int i3, int i4, int i5) 403 { 404 throw new UnimplementedMethodException(); 405 } 406 407 //-------------------------------------------------------------------------- 408 public void drawOval(int i, int i1, int i2, int i3) 409 { 410 throw new UnimplementedMethodException(); 411 } 412 413 //-------------------------------------------------------------------------- 414 public void fillOval(int i, int i1, int i2, int i3) 415 { 416 throw new UnimplementedMethodException(); 417 } 418 419 //-------------------------------------------------------------------------- 420 public void drawArc(int i, int i1, int i2, int i3, int i4, int i5) 421 { 422 throw new UnimplementedMethodException(); 423 } 424 425 //-------------------------------------------------------------------------- 426 public void fillArc(int i, int i1, int i2, int i3, int i4, int i5) 427 { 428 throw new UnimplementedMethodException(); 429 } 430 431 //-------------------------------------------------------------------------- 432 public void drawPolyline(int[] ints, int[] ints1, int i) 433 { 434 throw new UnimplementedMethodException(); 435 } 436 437 //-------------------------------------------------------------------------- 438 public void drawPolygon(int[] ints, int[] ints1, int i) 439 { 440 throw new UnimplementedMethodException(); 441 } 442 443 //-------------------------------------------------------------------------- 444 public void fillPolygon(int[] ints, int[] ints1, int i) 445 { 446 throw new UnimplementedMethodException(); 447 } 448 449 //-------------------------------------------------------------------------- 450 public void translate(int x, int y) 451 { 452 SvgGroup group = new SvgGroup(); 453 group.setTransform(String.format("translate(%d,%d)", x, y)); 454 mTagStack.peek().addSubtag(group); 455 mTagStack.push(group); 456 AffineTransform transform = new AffineTransform(mTransformStack.peek()); 457 transform.setToTranslation(x, y); 458 mTransformStack.push(transform); 459 } 460 461 //-------------------------------------------------------------------------- 462 public void translate(double x, double y) 463 { 464 SvgGroup group = new SvgGroup(); 465 group.setTransform(String.format("translate(%.1f,%.1f)", x, y)); 466 mTagStack.peek().addSubtag(group); 467 mTagStack.push(group); 468 AffineTransform transform = new AffineTransform(mTransformStack.peek()); 469 transform.setToTranslation(x, y); 470 mTransformStack.push(transform); 471 } 472 473 //-------------------------------------------------------------------------- 474 public void rotate(double v) 475 { 476 SvgGroup group = new SvgGroup(); 477 group.setTransform(String.format("rotate(%.1f)", v)); 478 mTagStack.peek().addSubtag(group); 479 mTagStack.push(group); 480 AffineTransform transform = new AffineTransform(mTransformStack.peek()); 481 transform.setToRotation(v); 482 mTransformStack.push(transform); 483 } 484 485 //-------------------------------------------------------------------------- 486 public void rotate(double v, double v1, double v2) 487 { 488 SvgGroup group = new SvgGroup(); 489 group.setTransform(String.format("rotate(%.1f, %.1f, %.1f)", v, v1, v2)); 490 mTagStack.peek().addSubtag(group); 491 mTagStack.push(group); 492 AffineTransform transform = new AffineTransform(mTransformStack.peek()); 493 transform.setToRotation(v, v1, v2); 494 mTransformStack.push(transform); 495 } 496 497 //-------------------------------------------------------------------------- 498 public void scale(double v, double v1) 499 { 500 throw new UnimplementedMethodException(); 501 } 502 503 //-------------------------------------------------------------------------- 504 public void shear(double v, double v1) 505 { 506 throw new UnimplementedMethodException(); 507 } 508 509 //-------------------------------------------------------------------------- 510 public void transform(AffineTransform inAffineTransform) 511 { 512 AffineTransform transform = new AffineTransform(mTransformStack.peek()); 513 transform.concatenate(inAffineTransform); 514 mTransformStack.push(transform); 515 } 516 517 //-------------------------------------------------------------------------- 518 public void setTransform(AffineTransform inAffineTransform) 519 { 520 while (mTagStack.size() > 1 && ! inAffineTransform.equals(mTransformStack.peek())) 521 { 522 mTagStack.pop(); 523 mTransformStack.pop(); 524 } 525 526 if (! inAffineTransform.equals(mTransformStack.peek())) 527 { 528 mTransformStack.pop(); 529 mTransformStack.push(new AffineTransform(inAffineTransform)); 530 } 531 } 532 533 //-------------------------------------------------------------------------- 534 public AffineTransform getTransform() 535 { 536 return new AffineTransform(mTransformStack.peek()); // Return a copy 537 } 538 539 //-------------------------------------------------------------------------- 540 public void setPaint(Paint inPaint) 541 { 542 mCurrentPaint = inPaint; 543 } 544 545 //-------------------------------------------------------------------------- 546 public Paint getPaint() 547 { 548 return mCurrentPaint; 549 } 550 551 //-------------------------------------------------------------------------- 552 public Color getColor() 553 { 554 return (mCurrentPaint instanceof Color ? (Color) mCurrentPaint : null); 555 } 556 557 //-------------------------------------------------------------------------- 558 public void setColor(Color inColor) 559 { 560 mCurrentPaint = inColor; 561 } 562 563 //-------------------------------------------------------------------------- 564 /** 565 Sets the paint mode of this graphics context to overwrite the destination 566 with this graphics context's current color. This sets the logical pixel 567 operation function to the paint or overwrite mode. All subsequent rendering 568 operations will overwrite the destination with the current color. 569 */ 570 public void setPaintMode() 571 { 572 throw new UnimplementedMethodException(); 573 } 574 575 //-------------------------------------------------------------------------- 576 /** 577 <b>Not implemented</b>. 578 <p> 579 Sets the paint mode of this graphics context to alternate between this 580 graphics context's current color and the new specified color. This specifies 581 that logical pixel operations are performed in the XOR mode, which alternates 582 pixels between the current color and a specified XOR color. 583 </p> 584 <p> 585 When drawing operations are performed, pixels which are the current color are 586 changed to the specified color, and vice versa. 587 </p> 588 <p> 589 Pixels that are of colors other than those two colors are changed in an 590 unpredictable but reversible manner; if the same figure is drawn twice, then 591 all pixels are restored to their original values. 592 </p> 593 @param inColor the color to alternate with the current default color of the graphics context 594 */ 595 public void setXORMode(Color inColor) 596 { 597 throw new UnimplementedMethodException(); 598 } 599 600 //-------------------------------------------------------------------------- 601 public Composite getComposite() 602 { 603 throw new UnimplementedMethodException(); 604 } 605 606 //-------------------------------------------------------------------------- 607 public void setBackground(Color inValue) 608 { 609 mCurrentBackground = inValue; 610 } 611 612 //-------------------------------------------------------------------------- 613 public Color getBackground() 614 { 615 return mCurrentBackground; 616 } 617 618 //-------------------------------------------------------------------------- 619 public void setStroke(Stroke inStroke) 620 { 621 mCurrentStroke = inStroke; 622 } 623 624 //-------------------------------------------------------------------------- 625 public Stroke getStroke() 626 { 627 return mCurrentStroke; 628 } 629 630 //-------------------------------------------------------------------------- 631 public void clip(Shape shape) 632 { 633 throw new UnimplementedMethodException(); 634 } 635 636 //-------------------------------------------------------------------------- 637 public FontRenderContext getFontRenderContext() 638 { 639 return sFRC; 640 } 641 642}