/* ======================================================================== * PlantUML : a free UML diagram generator * ======================================================================== * * (C) Copyright 2009-2017, Arnaud Roques * * Project Info: http://plantuml.com * * This file is part of PlantUML. * * Licensed under The MIT License (Massachusetts Institute of Technology License) * * See http://opensource.org/licenses/MIT * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * Original Author: Arnaud Roques */ package net.sourceforge.plantuml.ugraphic.g2d; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import net.sourceforge.plantuml.EnsureVisible; import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.anim.AffineTransformation; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.StringBounderUtils; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.png.PngIO; import net.sourceforge.plantuml.posimo.DotPath; import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic; import net.sourceforge.plantuml.ugraphic.AbstractUGraphic; import net.sourceforge.plantuml.ugraphic.ColorMapper; import net.sourceforge.plantuml.ugraphic.UAntiAliasing; import net.sourceforge.plantuml.ugraphic.UCenteredCharacter; import net.sourceforge.plantuml.ugraphic.UChange; import net.sourceforge.plantuml.ugraphic.UClip; import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGraphic2; import net.sourceforge.plantuml.ugraphic.UImage; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UPath; import net.sourceforge.plantuml.ugraphic.UPixel; import net.sourceforge.plantuml.ugraphic.UPolygon; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UText; public class UGraphicG2d extends AbstractUGraphic implements EnsureVisible, UGraphic2 { private BufferedImage bufferedImage; private final double dpiFactor; private UAntiAliasing antiAliasing = UAntiAliasing.ANTI_ALIASING_ON; private/* final */List urls = new ArrayList(); private Set allUrls = new HashSet(); private final boolean hasAffineTransform; public final Set getAllUrlsEncountered() { return Collections.unmodifiableSet(allUrls); } @Override public UGraphic apply(UChange change) { final UGraphicG2d copy = (UGraphicG2d) super.apply(change); if (change instanceof UAntiAliasing) { copy.antiAliasing = (UAntiAliasing) change; } return copy; } @Override protected AbstractCommonUGraphic copyUGraphic() { return new UGraphicG2d(this); } private UGraphicG2d(UGraphicG2d other) { super(other); this.hasAffineTransform = other.hasAffineTransform; this.dpiFactor = other.dpiFactor; this.bufferedImage = other.bufferedImage; this.urls = other.urls; this.allUrls = other.allUrls; this.antiAliasing = other.antiAliasing; register(dpiFactor); } public UGraphicG2d(ColorMapper colorMapper, Graphics2D g2d, double dpiFactor) { this(colorMapper, g2d, dpiFactor, null, 0, 0); } public UGraphicG2d(ColorMapper colorMapper, Graphics2D g2d, double dpiFactor, AffineTransformation affineTransform, double dx, double dy) { super(colorMapper, g2d); this.hasAffineTransform = affineTransform != null; this.dpiFactor = dpiFactor; if (dpiFactor != 1.0) { g2d.scale(dpiFactor, dpiFactor); } if (this.hasAffineTransform) { if (dx != 0 || dy != 0) { getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy)); } getGraphicObject().transform(affineTransform.getAffineTransform()); } register(dpiFactor); } private void register(double dpiFactor) { registerDriver(URectangle.class, new DriverRectangleG2d(dpiFactor, this)); if (this.hasAffineTransform || dpiFactor != 1.0) { registerDriver(UText.class, new DriverTextAsPathG2d(this, TextBlockUtils.getFontRenderContext())); } else { registerDriver(UText.class, new DriverTextG2d(this)); } registerDriver(ULine.class, new DriverLineG2d(dpiFactor)); registerDriver(UPixel.class, new DriverPixelG2d()); registerDriver(UPolygon.class, new DriverPolygonG2d(dpiFactor, this)); registerDriver(UEllipse.class, new DriverEllipseG2d(dpiFactor, this)); registerDriver(UImage.class, new DriverImageG2d(this)); registerDriver(DotPath.class, new DriverDotPathG2d(this)); registerDriver(UPath.class, new DriverPathG2d(dpiFactor)); registerDriver(UCenteredCharacter.class, new DriverCenteredCharacterG2d()); } public StringBounder getStringBounder() { if (hasAffineTransform) { return TextBlockUtils.getDummyStringBounder(); } return StringBounderUtils.asStringBounder(); } @Override protected void beforeDraw() { super.beforeDraw(); applyClip(); antiAliasing.apply(getGraphicObject()); } private void applyClip() { final UClip uclip = getClip(); if (uclip == null) { getGraphicObject().setClip(null); } else { final Shape clip = new Rectangle2D.Double(uclip.getX(), uclip.getY(), uclip.getWidth(), uclip.getHeight()); getGraphicObject().setClip(clip); } } protected final double getDpiFactor() { return dpiFactor; } public void startUrl(Url url) { urls.add(url); allUrls.add(url); } public void closeAction() { urls.remove(urls.size() - 1); } public void ensureVisible(double x, double y) { for (Url u : urls) { u.ensureVisible(x, y); } } public BufferedImage getBufferedImage() { return bufferedImage; } public void setBufferedImage(BufferedImage bufferedImage) { this.bufferedImage = bufferedImage; } public Graphics2D getGraphics2D() { return getGraphicObject(); } public void writeImageTOBEMOVED(OutputStream os, String metadata, int dpi) throws IOException { final BufferedImage im = getBufferedImage(); PngIO.write(im, os, metadata, dpi); } }