mirror of
https://github.com/octoleo/plantuml.git
synced 2024-12-22 10:59:01 +00:00
Add Support for Font Selection in Ditaa
This adds support for selecting the font in ditaa diagrams by specifying --font-family, --font-size and/or --font-variant in the ditaa() line. The change is actually taken over from @pepijnve who implemented in https://github.com/pepijnve/ditaa/issues/1. I extended it for supporting the necessary flags from plantuml.
This commit is contained in:
parent
87cbe82cd0
commit
8066a3f730
@ -34,6 +34,7 @@
|
||||
*/
|
||||
package net.sourceforge.plantuml.ditaa;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@ -61,11 +62,12 @@ public class PSystemDitaa extends AbstractPSystem {
|
||||
private final boolean dropShadows;
|
||||
private final String data;
|
||||
private final float scale;
|
||||
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, float scale, Font font) {
|
||||
super(source);
|
||||
this.data = data;
|
||||
this.dropShadows = dropShadows;
|
||||
@ -84,11 +86,12 @@ public class PSystemDitaa extends AbstractPSystem {
|
||||
this.processingOptions = null;
|
||||
}
|
||||
this.scale = scale;
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
PSystemDitaa add(String line) {
|
||||
return new PSystemDitaa(getSource(), data + line + BackSlash.NEWLINE, performSeparationOfCommonEdges,
|
||||
dropShadows, allCornersAreRound, scale);
|
||||
dropShadows, allCornersAreRound, scale, font);
|
||||
}
|
||||
|
||||
public DiagramDescription getDescription() {
|
||||
@ -113,6 +116,10 @@ public class PSystemDitaa extends AbstractPSystem {
|
||||
final Field f_renderingOptions = options.getClass().getField("renderingOptions");
|
||||
final Object renderingOptions = f_renderingOptions.get(options);
|
||||
|
||||
// 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);
|
||||
|
@ -34,6 +34,7 @@
|
||||
*/
|
||||
package net.sourceforge.plantuml.ditaa;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -70,10 +71,11 @@ public class PSystemDitaaFactory extends PSystemBasicFactory<PSystemDitaa> {
|
||||
allCornersAreRound = 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, scale, font);
|
||||
else
|
||||
throw new IllegalStateException(getDiagramType().name());
|
||||
|
||||
@ -95,7 +97,8 @@ public class PSystemDitaaFactory extends PSystemBasicFactory<PSystemDitaa> {
|
||||
allCornersAreRound = 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, scale, font);
|
||||
}
|
||||
if (system == null)
|
||||
return null;
|
||||
@ -115,4 +118,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);
|
||||
}
|
||||
}
|
||||
|
@ -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,8 @@ public class RenderingOptions {
|
||||
|
||||
private float scale = 1;
|
||||
|
||||
private Font font = new Font("Dialog", Font.BOLD, 12);
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@ -113,4 +116,14 @@ public class RenderingOptions {
|
||||
antialias = b;
|
||||
}
|
||||
|
||||
public Font getFont()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setFont(Font font)
|
||||
{
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user