2010-11-15 20:35:36 +00:00
|
|
|
/* ========================================================================
|
|
|
|
* PlantUML : a free UML diagram generator
|
|
|
|
* ========================================================================
|
|
|
|
*
|
2019-01-16 18:34:41 +00:00
|
|
|
* (C) Copyright 2009-2020, Arnaud Roques
|
2010-11-15 20:35:36 +00:00
|
|
|
*
|
2016-03-06 16:47:34 +00:00
|
|
|
* Project Info: http://plantuml.com
|
2010-11-15 20:35:36 +00:00
|
|
|
*
|
2017-03-15 19:13:31 +00:00
|
|
|
* If you like this project or if you find it useful, you can support us at:
|
|
|
|
*
|
|
|
|
* http://plantuml.com/patreon (only 1$ per month!)
|
|
|
|
* http://plantuml.com/paypal
|
|
|
|
*
|
2010-11-15 20:35:36 +00:00
|
|
|
* This file is part of PlantUML.
|
|
|
|
*
|
|
|
|
* PlantUML 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 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* PlantUML distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
2013-12-10 19:36:50 +00:00
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
2010-11-15 20:35:36 +00:00
|
|
|
* License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
|
|
* USA.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Original Author: Arnaud Roques
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
package net.sourceforge.plantuml;
|
|
|
|
|
2017-10-07 09:46:53 +00:00
|
|
|
import java.awt.Font;
|
2016-08-25 20:45:37 +00:00
|
|
|
import java.awt.FontMetrics;
|
|
|
|
import java.awt.Graphics2D;
|
2020-05-07 14:12:08 +00:00
|
|
|
import java.awt.RenderingHints;
|
2016-08-25 20:45:37 +00:00
|
|
|
import java.awt.geom.Dimension2D;
|
|
|
|
import java.awt.geom.Rectangle2D;
|
|
|
|
import java.awt.image.BufferedImage;
|
2019-09-14 18:12:04 +00:00
|
|
|
import java.io.IOException;
|
2013-12-10 19:36:50 +00:00
|
|
|
|
2016-08-25 20:45:37 +00:00
|
|
|
import net.sourceforge.plantuml.braille.BrailleCharFactory;
|
|
|
|
import net.sourceforge.plantuml.braille.UGraphicBraille;
|
|
|
|
import net.sourceforge.plantuml.graphic.StringBounder;
|
2021-02-02 10:12:15 +00:00
|
|
|
import net.sourceforge.plantuml.graphic.StringBounderRaw;
|
2019-09-14 18:12:04 +00:00
|
|
|
import net.sourceforge.plantuml.png.MetadataTag;
|
2020-05-30 15:20:23 +00:00
|
|
|
import net.sourceforge.plantuml.security.SFile;
|
2019-09-14 18:12:04 +00:00
|
|
|
import net.sourceforge.plantuml.svg.SvgGraphics;
|
2016-08-25 20:45:37 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.UFont;
|
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
/**
|
|
|
|
* Format for output files generated by PlantUML.
|
|
|
|
*
|
|
|
|
* @author Arnaud Roques
|
|
|
|
*
|
|
|
|
*/
|
2010-11-15 20:35:36 +00:00
|
|
|
public enum FileFormat {
|
2021-02-12 14:09:28 +00:00
|
|
|
PNG("image/png"),
|
|
|
|
SVG("image/svg+xml"),
|
|
|
|
EPS("application/postscript"),
|
|
|
|
EPS_TEXT("application/postscript"),
|
|
|
|
ATXT("text/plain"),
|
|
|
|
UTXT("text/plain;charset=UTF-8"),
|
|
|
|
XMI_STANDARD("application/vnd.xmi+xml"),
|
|
|
|
XMI_STAR("application/vnd.xmi+xml"),
|
|
|
|
XMI_ARGO("application/vnd.xmi+xml"),
|
|
|
|
SCXML("application/scxml+xml"),
|
|
|
|
PDF("application/pdf"),
|
|
|
|
MJPEG("video/x-msvideo"),
|
|
|
|
ANIMATED_GIF("image/gif"),
|
|
|
|
HTML("text/html"),
|
|
|
|
HTML5("text/html"),
|
|
|
|
VDX("application/vnd.visio.xml"),
|
|
|
|
LATEX("application/x-latex"),
|
|
|
|
LATEX_NO_PREAMBLE("application/x-latex"),
|
|
|
|
BASE64("text/plain; charset=x-user-defined"),
|
|
|
|
BRAILLE_PNG("image/png"),
|
2021-03-21 12:52:20 +00:00
|
|
|
PREPROC("text/plain"),
|
|
|
|
DEBUG("text/plain");
|
2021-02-12 14:09:28 +00:00
|
|
|
|
|
|
|
private final String mimeType;
|
|
|
|
|
|
|
|
FileFormat(String mimeType) {
|
|
|
|
this.mimeType = mimeType;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getMimeType() {
|
|
|
|
return mimeType;
|
|
|
|
}
|
2010-11-15 20:35:36 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
/**
|
|
|
|
* Returns the file format to be used for that format.
|
|
|
|
*
|
|
|
|
* @return a string starting by a point.
|
|
|
|
*/
|
2010-11-15 20:35:36 +00:00
|
|
|
public String getFileSuffix() {
|
2011-01-05 18:23:06 +00:00
|
|
|
if (name().startsWith("XMI")) {
|
2013-12-10 19:36:50 +00:00
|
|
|
return ".xmi";
|
2011-01-05 18:23:06 +00:00
|
|
|
}
|
2015-04-07 18:18:37 +00:00
|
|
|
if (this == MJPEG) {
|
|
|
|
return ".avi";
|
|
|
|
}
|
2016-03-06 16:47:34 +00:00
|
|
|
if (this == LATEX_NO_PREAMBLE) {
|
|
|
|
return ".latex";
|
|
|
|
}
|
2015-04-07 18:18:37 +00:00
|
|
|
if (this == ANIMATED_GIF) {
|
|
|
|
return ".gif";
|
|
|
|
}
|
2016-07-25 19:25:28 +00:00
|
|
|
if (this == BRAILLE_PNG) {
|
|
|
|
return ".braille.png";
|
|
|
|
}
|
2011-08-08 17:48:29 +00:00
|
|
|
if (this == EPS_TEXT) {
|
|
|
|
return EPS.getFileSuffix();
|
|
|
|
}
|
2015-04-07 18:18:37 +00:00
|
|
|
return "." + StringUtils.goLowerCase(name());
|
2010-11-15 20:35:36 +00:00
|
|
|
}
|
2011-08-08 17:48:29 +00:00
|
|
|
|
2016-09-29 19:51:18 +00:00
|
|
|
final static private BufferedImage imDummy = new BufferedImage(800, 100, BufferedImage.TYPE_INT_RGB);
|
2020-05-30 15:20:23 +00:00
|
|
|
final static public Graphics2D gg = imDummy.createGraphics();
|
2020-05-07 14:12:08 +00:00
|
|
|
static {
|
|
|
|
// KEY_FRACTIONALMETRICS
|
|
|
|
gg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
|
|
}
|
2016-08-25 20:45:37 +00:00
|
|
|
|
2017-10-07 09:46:53 +00:00
|
|
|
public StringBounder getDefaultStringBounder(TikzFontDistortion tikzFontDistortion) {
|
2020-12-06 21:43:09 +00:00
|
|
|
return getDefaultStringBounder(tikzFontDistortion, SvgCharSizeHack.NO_HACK);
|
|
|
|
}
|
|
|
|
|
|
|
|
public StringBounder getDefaultStringBounder(TikzFontDistortion tikzFontDistortion, SvgCharSizeHack charSizeHack) {
|
2017-10-07 09:46:53 +00:00
|
|
|
if (this == LATEX || this == LATEX_NO_PREAMBLE) {
|
|
|
|
return getTikzStringBounder(tikzFontDistortion);
|
|
|
|
}
|
2016-08-25 20:45:37 +00:00
|
|
|
if (this == BRAILLE_PNG) {
|
2017-10-07 09:46:53 +00:00
|
|
|
return getBrailleStringBounder();
|
2020-12-06 21:43:09 +00:00
|
|
|
}
|
|
|
|
if (this == SVG) {
|
|
|
|
return getSvgStringBounder(charSizeHack);
|
2016-08-25 20:45:37 +00:00
|
|
|
}
|
2017-10-07 09:46:53 +00:00
|
|
|
return getNormalStringBounder();
|
|
|
|
}
|
|
|
|
|
2020-12-06 21:43:09 +00:00
|
|
|
private StringBounder getSvgStringBounder(final SvgCharSizeHack charSizeHack) {
|
2021-02-02 10:12:15 +00:00
|
|
|
return new StringBounderRaw() {
|
2020-12-06 21:43:09 +00:00
|
|
|
public String toString() {
|
|
|
|
return "FileFormat::getSvgStringBounder";
|
|
|
|
}
|
|
|
|
|
2021-02-02 10:12:15 +00:00
|
|
|
protected Dimension2D calculateDimensionInternal(UFont font, String text) {
|
2020-12-06 21:43:09 +00:00
|
|
|
text = charSizeHack.transformStringForSizeHack(text);
|
|
|
|
return getJavaDimension(font, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-10-07 09:46:53 +00:00
|
|
|
private StringBounder getNormalStringBounder() {
|
2021-02-02 10:12:15 +00:00
|
|
|
return new StringBounderRaw() {
|
2017-10-07 09:46:53 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "FileFormat::getNormalStringBounder";
|
|
|
|
}
|
|
|
|
|
2021-02-02 10:12:15 +00:00
|
|
|
protected Dimension2D calculateDimensionInternal(UFont font, String text) {
|
2017-10-07 09:46:53 +00:00
|
|
|
return getJavaDimension(font, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-12-06 21:43:09 +00:00
|
|
|
static private Dimension2DDouble getJavaDimension(UFont font, String text) {
|
2021-02-02 10:12:15 +00:00
|
|
|
final Font javaFont = font.getFont();
|
|
|
|
final FontMetrics fm = gg.getFontMetrics(javaFont);
|
|
|
|
final Rectangle2D rect = fm.getStringBounds(text, gg);
|
|
|
|
return new Dimension2DDouble(rect.getWidth(), rect.getHeight());
|
2017-10-07 09:46:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private StringBounder getBrailleStringBounder() {
|
2021-02-02 10:12:15 +00:00
|
|
|
return new StringBounderRaw() {
|
2017-10-07 09:46:53 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "FileFormat::getBrailleStringBounder";
|
|
|
|
}
|
|
|
|
|
2021-02-02 10:12:15 +00:00
|
|
|
protected Dimension2D calculateDimensionInternal(UFont font, String text) {
|
2017-10-07 09:46:53 +00:00
|
|
|
final int nb = BrailleCharFactory.build(text).size();
|
|
|
|
final double quanta = UGraphicBraille.QUANTA;
|
|
|
|
final double height = 5 * quanta;
|
|
|
|
final double width = 3 * nb * quanta + 1;
|
|
|
|
return new Dimension2DDouble(width, height);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private StringBounder getTikzStringBounder(final TikzFontDistortion tikzFontDistortion) {
|
2021-02-02 10:12:15 +00:00
|
|
|
return new StringBounderRaw() {
|
2017-10-07 09:46:53 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "FileFormat::getTikzStringBounder";
|
|
|
|
}
|
|
|
|
|
2021-02-02 10:12:15 +00:00
|
|
|
protected Dimension2D calculateDimensionInternal(UFont font, String text) {
|
2017-10-07 09:46:53 +00:00
|
|
|
final Dimension2DDouble w1 = getJavaDimension(font.goTikz(-1), text);
|
|
|
|
final Dimension2DDouble w2 = getJavaDimension(font.goTikz(0), text);
|
|
|
|
final Dimension2DDouble w3 = getJavaDimension(font.goTikz(1), text);
|
|
|
|
final double factor = (w3.getWidth() - w1.getWidth()) / w2.getWidth();
|
|
|
|
final double distortion = tikzFontDistortion.getDistortion();
|
|
|
|
final double magnify = tikzFontDistortion.getMagnify();
|
|
|
|
final double delta = (w2.getWidth() - w1.getWidth()) * factor * distortion;
|
|
|
|
return w2.withWidth(Math.max(w1.getWidth(), magnify * w2.getWidth() - delta));
|
2016-08-25 20:45:37 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
/**
|
|
|
|
* Check if this file format is Encapsulated PostScript.
|
|
|
|
*
|
|
|
|
* @return <code>true</code> for EPS.
|
|
|
|
*/
|
2011-08-08 17:48:29 +00:00
|
|
|
public boolean isEps() {
|
|
|
|
if (this == EPS) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (this == EPS_TEXT) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String changeName(String fileName, int cpt) {
|
|
|
|
if (cpt == 0) {
|
2013-12-10 19:36:50 +00:00
|
|
|
return changeName(fileName, getFileSuffix());
|
|
|
|
}
|
2020-05-07 14:12:08 +00:00
|
|
|
return changeName(fileName,
|
|
|
|
OptionFlags.getInstance().getFileSeparator() + String.format("%03d", cpt) + getFileSuffix());
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 15:20:23 +00:00
|
|
|
private SFile computeFilename(SFile pngFile, int i) {
|
2017-04-19 18:30:16 +00:00
|
|
|
if (i == 0) {
|
|
|
|
return pngFile;
|
|
|
|
}
|
2020-05-30 15:20:23 +00:00
|
|
|
final SFile dir = pngFile.getParentFile();
|
|
|
|
return dir.file(computeFilenameInternal(pngFile.getName(), i));
|
2017-04-19 18:30:16 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
private String changeName(String fileName, String replacement) {
|
|
|
|
String result = fileName.replaceAll("\\.\\w+$", replacement);
|
|
|
|
if (result.equals(fileName)) {
|
|
|
|
result = fileName + replacement;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-04-19 18:30:16 +00:00
|
|
|
private String computeFilenameInternal(String name, int i) {
|
2013-12-10 19:36:50 +00:00
|
|
|
if (i == 0) {
|
|
|
|
return name;
|
2011-08-08 17:48:29 +00:00
|
|
|
}
|
2016-11-18 21:12:09 +00:00
|
|
|
return name.replaceAll("\\" + getFileSuffix() + "$",
|
|
|
|
OptionFlags.getInstance().getFileSeparator() + String.format("%03d", i) + getFileSuffix());
|
2011-08-08 17:48:29 +00:00
|
|
|
}
|
2019-09-14 18:12:04 +00:00
|
|
|
|
|
|
|
public boolean doesSupportMetadata() {
|
|
|
|
return this == PNG || this == SVG;
|
|
|
|
}
|
|
|
|
|
2020-05-30 15:20:23 +00:00
|
|
|
public boolean equalsMetadata(String currentMetadata, SFile existingFile) {
|
2019-09-14 18:12:04 +00:00
|
|
|
try {
|
|
|
|
if (this == PNG) {
|
|
|
|
final MetadataTag tag = new MetadataTag(existingFile, "plantuml");
|
|
|
|
final String previousMetadata = tag.getData();
|
|
|
|
final boolean sameMetadata = currentMetadata.equals(previousMetadata);
|
|
|
|
return sameMetadata;
|
|
|
|
}
|
|
|
|
if (this == SVG) {
|
|
|
|
final String svg = FileUtils.readSvg(existingFile);
|
2020-05-30 15:20:23 +00:00
|
|
|
if (svg == null) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-09-14 18:12:04 +00:00
|
|
|
final String currentSignature = SvgGraphics.getMD5Hex(currentMetadata);
|
|
|
|
final int idx = svg.lastIndexOf(SvgGraphics.MD5_HEADER);
|
|
|
|
if (idx != -1) {
|
|
|
|
final String part = svg.substring(idx + SvgGraphics.MD5_HEADER.length());
|
|
|
|
return part.startsWith(currentSignature);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2020-05-07 14:12:08 +00:00
|
|
|
|
2010-11-15 20:35:36 +00:00
|
|
|
}
|