1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-06-01 08:00:48 +00:00

Merge pull request #933 from kolrami/chru-ditaa-font

Add Support for Font Selection and Transparent Background in Ditaa
This commit is contained in:
PlantUML 2022-02-28 14:19:34 +01:00 committed by GitHub
commit d8cbe985ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 125 deletions

View File

@ -34,6 +34,8 @@
*/
package net.sourceforge.plantuml.ditaa;
import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
@ -61,11 +63,13 @@ public class PSystemDitaa extends AbstractPSystem {
private final boolean dropShadows;
private final String data;
private final float scale;
private final boolean transparentBackground;
private final Font font;
private final boolean performSeparationOfCommonEdges;
private final boolean allCornersAreRound;
public PSystemDitaa(UmlSource source, String data, boolean performSeparationOfCommonEdges, boolean dropShadows,
boolean allCornersAreRound, float scale) {
boolean allCornersAreRound, boolean transparentBackground, float scale, Font font) {
super(source);
this.data = data;
this.dropShadows = dropShadows;
@ -83,12 +87,14 @@ public class PSystemDitaa extends AbstractPSystem {
e.printStackTrace();
this.processingOptions = null;
}
this.transparentBackground = transparentBackground;
this.scale = scale;
this.font = font;
}
PSystemDitaa add(String line) {
return new PSystemDitaa(getSource(), data + line + BackSlash.NEWLINE, performSeparationOfCommonEdges,
dropShadows, allCornersAreRound, scale);
dropShadows, allCornersAreRound, transparentBackground, scale, font);
}
public DiagramDescription getDescription() {
@ -113,6 +119,14 @@ public class PSystemDitaa extends AbstractPSystem {
final Field f_renderingOptions = options.getClass().getField("renderingOptions");
final Object renderingOptions = f_renderingOptions.get(options);
// renderingOptions.setBackgroundColor(font);
final Method setBackgroundColor = renderingOptions.getClass().getMethod("setBackgroundColor", Color.class);
setBackgroundColor.invoke(renderingOptions, transparentBackground ? new Color(0, 0, 0, 0) : Color.WHITE);
// renderingOptions.setFont(font);
final Method setFont = renderingOptions.getClass().getMethod("setFont", Font.class);
setFont.invoke(renderingOptions, font);
// renderingOptions.setScale(scale);
final Method setScale = renderingOptions.getClass().getMethod("setScale", float.class);
setScale.invoke(renderingOptions, scale);

View File

@ -34,6 +34,7 @@
*/
package net.sourceforge.plantuml.ditaa;
import java.awt.Font;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -69,11 +70,16 @@ public class PSystemDitaaFactory extends PSystemBasicFactory<PSystemDitaa> {
if (startLine != null && (startLine.contains("-r") || startLine.contains("--round-corners")))
allCornersAreRound = true;
boolean transparentBackground = false;
if (startLine != null && (startLine.contains("-T") || startLine.contains("--transparent")))
transparentBackground = true;
final float scale = extractScale(startLine);
final Font font = extractFont(startLine);
if (getDiagramType() == DiagramType.UML)
return null;
else if (getDiagramType() == DiagramType.DITAA)
return new PSystemDitaa(source, "", performSeparationOfCommonEdges, dropShadows, allCornersAreRound, scale);
return new PSystemDitaa(source, "", performSeparationOfCommonEdges, dropShadows, allCornersAreRound, transparentBackground, scale, font);
else
throw new IllegalStateException(getDiagramType().name());
@ -94,8 +100,13 @@ public class PSystemDitaaFactory extends PSystemBasicFactory<PSystemDitaa> {
if (line.contains("-r") || line.contains("--round-corners"))
allCornersAreRound = true;
boolean transparentBackground = false;
if (line.contains("-T") || line.contains("--transparent"))
transparentBackground = true;
final float scale = extractScale(line);
return new PSystemDitaa(source, "", performSeparationOfCommonEdges, dropShadows, allCornersAreRound, scale);
final Font font = extractFont(line);
return new PSystemDitaa(source, "", performSeparationOfCommonEdges, dropShadows, allCornersAreRound, transparentBackground, scale, font);
}
if (system == null)
return null;
@ -115,4 +126,46 @@ public class PSystemDitaaFactory extends PSystemBasicFactory<PSystemDitaa> {
}
return 1;
}
private Font extractFont(String line) {
if (line == null)
return new Font("Dialog", Font.BOLD, 12);
final Pattern pName = Pattern.compile("font-family=([a-zA-Z0-0 ]+)");
final Matcher mName = pName.matcher(line);
String fontName = "Dialog";
if (mName.find())
{
fontName = mName.group(1);
}
final Pattern pVariant = Pattern.compile("font-variant=(BOLD|ITALIC|PLAIN)");
final Matcher mVariant = pVariant.matcher(line);
int fontVariant = Font.BOLD;
if (mVariant.find())
{
switch (mVariant.group(1))
{
case "BOLD":
fontVariant = Font.BOLD;
break;
case "ITALIC":
fontVariant = Font.ITALIC;
break;
case "PLAIN":
fontVariant = Font.PLAIN;
break;
}
}
final Pattern pSize = Pattern.compile("font-size=([\\d]+)");
final Matcher mSize = pSize.matcher(line);
int fontSize = 12;
if (mSize.find())
{
fontSize = Integer.parseInt(mSize.group(1));
}
return new Font(fontName, fontVariant, fontSize);
}
}

View File

@ -20,6 +20,7 @@
*/
package org.stathissideris.ascii2image.core;
import java.awt.*;
import java.util.HashMap;
import org.stathissideris.ascii2image.graphics.CustomShapeDefinition;
@ -41,6 +42,10 @@ public class RenderingOptions {
private float scale = 1;
private Color backgroundColor = Color.white;
private Font font = new Font("Dialog", Font.BOLD, 12);
/**
* @return
*/
@ -113,4 +118,26 @@ public class RenderingOptions {
antialias = b;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(Color backgroundColor) {
this.backgroundColor = backgroundColor;
}
public boolean needsTransparency() {
return backgroundColor.getAlpha() < 255;
}
public Font getFont()
{
return font;
}
public void setFont(Font font)
{
this.font = font;
}
}

View File

@ -54,17 +54,23 @@ public class BitmapRenderer {
Stroke normalStroke;
Stroke dashStroke;
public RenderedImage renderToImage(Diagram diagram, RenderingOptions options){
BufferedImage image = new BufferedImage(
public RenderedImage renderToImage(Diagram diagram, RenderingOptions options){
BufferedImage image;
if(options.needsTransparency()) {
image = new BufferedImage(
diagram.getWidth(),
diagram.getHeight(),
BufferedImage.TYPE_INT_ARGB);
} else {
image = new BufferedImage(
diagram.getWidth(),
diagram.getHeight(),
BufferedImage.TYPE_INT_RGB);
}
return render(diagram, image, options);
}
public RenderedImage render(Diagram diagram, BufferedImage image, RenderingOptions options){
RenderedImage renderedImage = image;
Graphics2D g2 = image.createGraphics();
@ -75,7 +81,7 @@ public class BitmapRenderer {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialiasSetting);
g2.setColor(Color.white);
g2.setColor(options.getBackgroundColor());
//TODO: find out why the next line does not work
g2.fillRect(0, 0, image.getWidth()+10, image.getHeight()+10);
/*for(int y = 0; y < diagram.getHeight(); y ++)

View File

@ -111,6 +111,8 @@ public class Diagram {
this.cellWidth = options.renderingOptions.getCellWidth();
this.cellHeight = options.renderingOptions.getCellHeight();
FontMeasurer fontMeasurer = new FontMeasurer(options.renderingOptions.getFont());
width = grid.getWidth() * cellWidth;
height = grid.getHeight() * cellHeight;
@ -526,7 +528,7 @@ public class Diagram {
ArrayList textGroups = nonBlank.breakIntoDistinctBoundaries();
if(DEBUG) System.out.println(textGroups.size()+" text groups found");
Font font = FontMeasurer.instance().getFontFor(cellHeight);
Font font = fontMeasurer.getFontFor(cellHeight);
Iterator textGroupIt = textGroups.iterator();
while(textGroupIt.hasNext()){
@ -550,10 +552,10 @@ public class Diagram {
int maxX = getCellMaxX(lastCell);
DiagramText textObject;
if(FontMeasurer.instance().getWidthFor(string, font) > maxX - minX){ //does not fit horizontally
Font lessWideFont = FontMeasurer.instance().getFontFor(maxX - minX, string);
textObject = new DiagramText(minX, y, string, lessWideFont);
} else textObject = new DiagramText(minX, y, string, font);
if(fontMeasurer.getWidthFor(string, font) > maxX - minX){ //does not fit horizontally
Font lessWideFont = fontMeasurer.getFontFor(maxX - minX, string);
textObject = new DiagramText(minX, y, string, lessWideFont, fontMeasurer);
} else textObject = new DiagramText(minX, y, string, font, fontMeasurer);
textObject.centerVerticallyBetween(getCellMinY(cell), getCellMaxY(cell));

View File

@ -39,8 +39,9 @@ public class DiagramText extends DiagramComponent {
private boolean isTextOnLine = false;
private boolean hasOutline = false;
private Color outlineColor = Color.white;
private final FontMeasurer fontMeasurer;
public DiagramText(int x, int y, String text, Font font){
public DiagramText(int x, int y, String text, Font font, FontMeasurer fontMeasurer){
if(text == null) throw new IllegalArgumentException("DiagramText cannot be initialised with a null string");
if(font == null) throw new IllegalArgumentException("DiagramText cannot be initialised with a null font");
@ -48,6 +49,7 @@ public class DiagramText extends DiagramComponent {
this.yPos = y;
this.text = text;
this.font = font;
this.fontMeasurer = fontMeasurer;
}
public void centerInBounds(Rectangle2D bounds){
@ -56,20 +58,20 @@ public class DiagramText extends DiagramComponent {
}
public void centerHorizontallyBetween(int minX, int maxX){
int width = FontMeasurer.instance().getWidthFor(text, font);
int width = fontMeasurer.getWidthFor(text, font);
int center = Math.abs(maxX - minX) / 2;
xPos += Math.abs(center - width / 2);
}
public void centerVerticallyBetween(int minY, int maxY){
int zHeight = FontMeasurer.instance().getZHeight(font);
int zHeight = fontMeasurer.getZHeight(font);
int center = Math.abs(maxY - minY) / 2;
yPos -= Math.abs(center - zHeight / 2);
}
public void alignRightEdgeTo(int x){
int width = FontMeasurer.instance().getWidthFor(text, font);
int width = fontMeasurer.getWidthFor(text, font);
xPos = x - width;
}
@ -145,7 +147,7 @@ public class DiagramText extends DiagramComponent {
}
public Rectangle2D getBounds(){
Rectangle2D bounds = FontMeasurer.instance().getBoundsFor(text, font);
Rectangle2D bounds = fontMeasurer.getBoundsFor(text, font);
bounds.setRect(
bounds.getMinX() + xPos,
bounds.getMinY() + yPos,

View File

@ -26,32 +26,25 @@ import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Locale;
/**
*
* @author Efstathios Sideris
*/
public class FontMeasurer {
private static final String fontFamilyName = "Dialog";
//private static final String fontFamilyName = "Helvetica";
private static final boolean DEBUG = false;
private static final FontMeasurer instance = new FontMeasurer();
FontRenderContext fakeRenderContext;
Graphics2D fakeGraphics;
{
private final Font baseFont;
private FontRenderContext fakeRenderContext;
private Graphics2D fakeGraphics;
public FontMeasurer(Font font){
baseFont = font;
BufferedImage image = new BufferedImage(1,1, BufferedImage.TYPE_INT_RGB);
fakeGraphics = image.createGraphics();
if (DEBUG) System.out.println("Locale: "+Locale.getDefault());
fakeRenderContext = fakeGraphics.getFontRenderContext();
}
}
public int getWidthFor(String str, int pixelHeight){
Font font = getFontFor(pixelHeight);
@ -74,125 +67,86 @@ public class FontMeasurer {
Rectangle2D rectangle = font.getStringBounds(str, fakeRenderContext);
return (int) rectangle.getHeight();
}
public Rectangle2D getBoundsFor(String str, Font font){
return font.getStringBounds(str, fakeRenderContext);
}
public Font getFontFor(int pixelHeight){
BufferedImage image = new BufferedImage(1,1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
return getFontFor(pixelHeight, fakeRenderContext);
}
public int getAscent(Font font){
fakeGraphics.setFont(font);
FontMetrics metrics = fakeGraphics.getFontMetrics();
if(DEBUG) System.out.println("Ascent: "+metrics.getAscent());
return metrics.getAscent();
}
public int getZHeight(Font font){
int height = (int) font.createGlyphVector(fakeRenderContext, "Z").getOutline().getBounds().getHeight();
if(DEBUG) System.out.println("Z height: "+height);
return height;
return (int) font.createGlyphVector(fakeRenderContext, "Z").getOutline().getBounds().getHeight();
}
public Font getFontFor(int maxWidth, String string){
float size = 12;
Font currentFont = new Font(fontFamilyName, Font.BOLD, (int) size);
//ascent is the distance between the baseline and the tallest character
int width = getWidthFor(string, currentFont);
public Font getFontFor(final int maxWidth, final String string){
FontPredicate predicate = new FontPredicate() {
@Override
public boolean test(Font font)
{
int width = getWidthFor(string, font);
return width > maxWidth;
}
};
return deriveFont(predicate, 1.0f);
}
public Font getFontFor(final int pixelHeight){
FontPredicate predicate = new FontPredicate() {
@Override
public boolean test(Font font)
{
//ascent is the distance between the baseline and the tallest character
int ascent = getAscent(font);
return ascent > pixelHeight;
}
};
return deriveFont(predicate, 0.5f);
}
private Font deriveFont(FontPredicate predicate, float sizeDelta)
{
Font currentFont = baseFont;
float size = baseFont.getSize2D();
int direction; //direction of size change (towards smaller or bigger)
if(width > maxWidth){
currentFont = currentFont.deriveFont(size - 1);
if(predicate.test(currentFont)){
currentFont = currentFont.deriveFont(size - 1f);
size--;
direction = -1;
direction = -1;
} else {
currentFont = currentFont.deriveFont(size + 1);
currentFont = currentFont.deriveFont(size + 1f);
size++;
direction = 1;
}
while(size > 0){
currentFont = currentFont.deriveFont(size);
//rectangle = currentFont.getStringBounds(testString, frc);
width = getWidthFor(string, currentFont);
if(direction == 1){
if(width > maxWidth){
size = size - 1;
if (direction == 1) {
if (predicate.test(currentFont)) {
size = size - sizeDelta;
return currentFont.deriveFont(size);
} else {
size = size + sizeDelta;
}
else size = size + 1;
} else {
if(width < maxWidth)
if (!predicate.test(currentFont)) {
return currentFont;
else size = size - 1;
} else {
size = size - sizeDelta;
}
}
}
return null;
}
public Font getFontFor(int pixelHeight, FontRenderContext frc){
float size = 12;
Font currentFont = new Font(fontFamilyName, Font.BOLD, (int) size);
// Font currentFont = new Font("Times", Font.BOLD, (int) size);
if (DEBUG) System.out.println(currentFont.getFontName());
//ascent is the distance between the baseline and the tallest character
int ascent = getAscent(currentFont);
int direction; //direction of size change (towards smaller or bigger)
if(ascent > pixelHeight){
currentFont = currentFont.deriveFont(size - 1);
size--;
direction = -1;
} else {
currentFont = currentFont.deriveFont(size + 1);
size++;
direction = 1;
}
while(size > 0){
currentFont = currentFont.deriveFont(size);
//rectangle = currentFont.getStringBounds(testString, frc);
ascent = getAscent(currentFont);
if(direction == 1){
if(ascent > pixelHeight){
size = size - 0.5f;
return currentFont.deriveFont(size);
}
else size = size + 0.5f;
} else {
if(ascent < pixelHeight)
return currentFont;
else size = size - 0.5f;
}
}
return null;
}
public static FontMeasurer instance(){
return instance;
}
public FontMeasurer(){
}
public static void main(String[] args) {
//FontMeasurer.instance().getFontFor(7);
float size = 12;
Font currentFont = new Font("Sans", Font.BOLD, (int) size);
System.out.println(currentFont.getSize());
currentFont = currentFont.deriveFont(--size);
System.out.println(currentFont.getSize());
currentFont = currentFont.deriveFont(--size);
System.out.println(currentFont.getSize());
currentFont = currentFont.deriveFont(--size);
System.out.println(currentFont.getSize());
currentFont = currentFont.deriveFont(--size);
System.out.println(currentFont.getSize());
currentFont = currentFont.deriveFont(--size);
System.out.println(currentFont.getSize());
private interface FontPredicate {
boolean test(Font font);
}
}