1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-25 06:17:33 +00:00

Improve theme support

This commit is contained in:
Arnaud Roques 2021-05-03 22:11:48 +02:00
parent 8540a8b875
commit 1048a07d7d
30 changed files with 1013 additions and 48 deletions

View File

@ -53,6 +53,7 @@ import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.VerticalAlignment;
import net.sourceforge.plantuml.stats.StatsUtilsIncrement;
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
import net.sourceforge.plantuml.style.StyleBuilder;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException;
import net.sourceforge.plantuml.version.License;
@ -146,6 +147,13 @@ public abstract class AbstractPSystem implements Diagram {
throws IOException {
final long now = System.currentTimeMillis();
try {
// if (this instanceof TitledDiagram) {
// final TitledDiagram titledDiagram = (TitledDiagram) this;
// final StyleBuilder styleBuilder = titledDiagram.getCurrentStyleBuilder();
// if (styleBuilder != null) {
// styleBuilder.printMe();
// }
// }
return exportDiagramNow(os, index, fileFormatOption);
} finally {
if (OptionFlags.getInstance().isEnableStats()) {
@ -168,8 +176,8 @@ public abstract class AbstractPSystem implements Diagram {
}
// TODO "index" isnt really being used
protected abstract ImageData exportDiagramNow(OutputStream os, int index, FileFormatOption fileFormatOption
) throws IOException;
protected abstract ImageData exportDiagramNow(OutputStream os, int index, FileFormatOption fileFormatOption)
throws IOException;
public ClockwiseTopRightBottomLeft getDefaultMargins() {
return ClockwiseTopRightBottomLeft.same(0);

View File

@ -223,6 +223,12 @@ public class Option {
this.failfast2 = true;
} else if (s.equalsIgnoreCase("-checkonly")) {
this.checkOnly = true;
} else if (s.equalsIgnoreCase("-theme")) {
i++;
if (i == arg.length) {
continue;
}
this.config.add(0, "!theme " + arg[i]);
} else if (s.equalsIgnoreCase("-config")) {
i++;
if (i == arg.length) {

View File

@ -108,6 +108,7 @@ public class OptionPrint {
+ "file\tTo include file as if '!include file' were used");
System.out.println(
" -I" + separator + "path" + separator + "to" + separator + "*.puml\tTo include files with pattern");
System.out.println(" -theme xxx\\t\\tTo use a specific theme");
System.out.println(" -charset xxx\tTo use a specific charset (default is " + charset + ")");
System.out.println(" -e[x]clude pattern\tTo exclude files that match the provided pattern");
System.out.println(" -metadata\t\tTo retrieve PlantUML sources from PNG images");

View File

@ -59,6 +59,7 @@ import net.sourceforge.plantuml.ugraphic.UText;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorAutomatic;
import net.sourceforge.plantuml.ugraphic.color.HColorAutomaticLegacy;
import net.sourceforge.plantuml.ugraphic.color.HColorSimple;
import net.sourceforge.plantuml.utils.CharHidder;
@ -144,10 +145,15 @@ public final class AtomText extends AbstractAtom implements Atom {
}
HColor textColor = fontConfiguration.getColor();
FontConfiguration useFontConfiguration = fontConfiguration;
if (textColor instanceof HColorAutomatic && ug.getParam().getBackcolor() != null) {
if (textColor instanceof HColorAutomaticLegacy && ug.getParam().getBackcolor() != null) {
textColor = ((HColorSimple) ug.getParam().getBackcolor()).opposite();
useFontConfiguration = fontConfiguration.changeColor(textColor);
}
if (textColor instanceof HColorAutomatic) {
final HColor backcolor = ug.getParam().getBackcolor();
textColor = ((HColorAutomatic) textColor).getAppropriateColor(backcolor);
useFontConfiguration = fontConfiguration.changeColor(textColor);
}
if (marginLeft != AtomTextUtils.ZERO) {
ug = ug.apply(UTranslate.dx(marginLeft.getDouble(ug.getStringBounder())));
}

View File

@ -67,6 +67,7 @@ import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignature;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
@ -196,7 +197,8 @@ public class SequenceDiagramFileMakerPuma2 implements FileMaker {
}
if (compTitle != null) {
compTitle.drawU(ug.apply(new UTranslate(area.getTitleX(), area.getTitleY())));
final HColor back = ImageBuilder.calculateBackColor(diagram);
compTitle.drawU(ug.apply(back.bg()).apply(new UTranslate(area.getTitleX(), area.getTitleY())));
}
caption.drawU(ug.apply(new UTranslate(area.getCaptionX(), area.getCaptionY())));
@ -218,9 +220,7 @@ public class SequenceDiagramFileMakerPuma2 implements FileMaker {
}
};
return diagram.createImageBuilder(fileFormatOption)
.drawable(drawable)
.write(os);
return diagram.createImageBuilder(fileFormatOption).drawable(drawable).write(os);
}
private void drawFooter(SequenceDiagramArea area, UGraphic ug, int page) {

View File

@ -67,6 +67,19 @@ public class Style {
this.signature = signature;
}
public void printMe() {
if (map.size() == 0) {
return;
}
System.err.println(signature + " {");
for (Entry<PName, Value> ent : map.entrySet()) {
System.err.println(" " + ent.getKey() + ": " + ent.getValue().asString());
}
System.err.println("}");
}
@Override
public String toString() {
return signature + " " + map;

View File

@ -52,6 +52,12 @@ public class StyleBuilder implements AutomaticCounter {
private final SkinParam skinParam;
private int counter;
public void printMe() {
for (Entry<StyleSignature, Style> ent : styles.entrySet()) {
ent.getValue().printMe();
}
}
private StyleBuilder(SkinParam skinParam, Set<StyleSignature> printedForLog) {
this.skinParam = skinParam;
this.printedForLog = new LinkedHashSet<StyleSignature>();

View File

@ -38,7 +38,6 @@ package net.sourceforge.plantuml.style;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@ -72,7 +71,7 @@ public class StyleSignature {
if (url == null) {
return this;
}
final Set<String> result = new HashSet<String>(names);
final Set<String> result = new LinkedHashSet<String>(names);
result.add(SName.clickable.name());
return new StyleSignature(result);
@ -85,7 +84,7 @@ public class StyleSignature {
if (s.contains("*") || s.contains("&") || s.contains("-")) {
throw new IllegalArgumentException();
}
final Set<String> result = new HashSet<String>(names);
final Set<String> result = new LinkedHashSet<String>(names);
result.add(clean(s));
return new StyleSignature(result);
}
@ -95,7 +94,7 @@ public class StyleSignature {
}
public StyleSignature addStar() {
final Set<String> result = new HashSet<String>(names);
final Set<String> result = new LinkedHashSet<String>(names);
result.add("*");
return new StyleSignature(result);
}

View File

@ -184,6 +184,7 @@ public class LanguageDescriptor {
preproc.add("!exit");
preproc.add("!include");
preproc.add("!theme");
preproc.add("!pragma");
preproc.add("!define");
preproc.add("!undef");

View File

@ -82,8 +82,10 @@ import net.sourceforge.plantuml.tim.iterator.CodeIteratorWhile;
import net.sourceforge.plantuml.tim.stdlib.AlwaysFalse;
import net.sourceforge.plantuml.tim.stdlib.AlwaysTrue;
import net.sourceforge.plantuml.tim.stdlib.CallUserFunction;
import net.sourceforge.plantuml.tim.stdlib.Darken;
import net.sourceforge.plantuml.tim.stdlib.DateFunction;
import net.sourceforge.plantuml.tim.stdlib.Dirpath;
import net.sourceforge.plantuml.tim.stdlib.Feature;
import net.sourceforge.plantuml.tim.stdlib.FileExists;
import net.sourceforge.plantuml.tim.stdlib.Filename;
import net.sourceforge.plantuml.tim.stdlib.FunctionExists;
@ -92,6 +94,9 @@ import net.sourceforge.plantuml.tim.stdlib.GetVersion;
import net.sourceforge.plantuml.tim.stdlib.Getenv;
import net.sourceforge.plantuml.tim.stdlib.IntVal;
import net.sourceforge.plantuml.tim.stdlib.InvokeProcedure;
import net.sourceforge.plantuml.tim.stdlib.IsDark;
import net.sourceforge.plantuml.tim.stdlib.IsLight;
import net.sourceforge.plantuml.tim.stdlib.Lighten;
import net.sourceforge.plantuml.tim.stdlib.LogicalNot;
import net.sourceforge.plantuml.tim.stdlib.Lower;
import net.sourceforge.plantuml.tim.stdlib.Newline;
@ -149,15 +154,20 @@ public class TContext {
functionsSet.addFunction(new Lower());
functionsSet.addFunction(new StringFunction());
functionsSet.addFunction(new Newline());
functionsSet.addFunction(new Feature());
functionsSet.addFunction(new Lighten());
functionsSet.addFunction(new Darken());
functionsSet.addFunction(new IsDark());
functionsSet.addFunction(new IsLight());
// %standard_exists_function
// %str_replace
// !exit
// !log
// %min
// %max
// Regexp
// %plantuml_version
// %time
// %trim
// %str_replace
}
public TContext(ImportedFiles importedFiles, Defines defines, String charset,

View File

@ -0,0 +1,75 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* 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
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* 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.tim.stdlib;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException;
public class Darken extends SimpleReturnFunction {
// Inspired from https://github.com/Qix-/color
public TFunctionSignature getSignature() {
return new TFunctionSignature("%darken", 2);
}
public boolean canCover(int nbArg, Set<String> namedArgument) {
return nbArg == 2;
}
public TValue executeReturnFunction(TContext context, TMemory memory, LineLocation location, List<TValue> values,
Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final String colorString = values.get(0).toString();
final int ratio = values.get(1).toInt();
try {
HColor color = HColorSet.instance().getColor(colorString);
color = color.darken(ratio);
return TValue.fromString(color.asString());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
}
}
}

View File

@ -0,0 +1,70 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* 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
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* 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.tim.stdlib;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;
public class Feature extends SimpleReturnFunction {
public TFunctionSignature getSignature() {
return new TFunctionSignature("%feature", 1);
}
public boolean canCover(int nbArg, Set<String> namedArgument) {
return nbArg == 1;
}
public TValue executeReturnFunction(TContext context, TMemory memory, LineLocation location, List<TValue> values,
Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final String arg = values.get(0).toString();
if ("style".equalsIgnoreCase(arg)) {
return TValue.fromInt(1);
}
if ("theme".equalsIgnoreCase(arg)) {
return TValue.fromInt(1);
}
return TValue.fromInt(0);
}
}

View File

@ -0,0 +1,73 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* 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
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* 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.tim.stdlib;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException;
public class IsDark extends SimpleReturnFunction {
// Inspired from https://github.com/Qix-/color
public TFunctionSignature getSignature() {
return new TFunctionSignature("%is_dark", 1);
}
public boolean canCover(int nbArg, Set<String> namedArgument) {
return nbArg == 1;
}
public TValue executeReturnFunction(TContext context, TMemory memory, LineLocation location, List<TValue> values,
Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final String colorString = values.get(0).toString();
try {
final HColor color = HColorSet.instance().getColor(colorString);
return TValue.fromBoolean(color.isDark());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
}
}
}

View File

@ -0,0 +1,73 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* 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
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* 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.tim.stdlib;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException;
public class IsLight extends SimpleReturnFunction {
// Inspired from https://github.com/Qix-/color
public TFunctionSignature getSignature() {
return new TFunctionSignature("%is_light", 1);
}
public boolean canCover(int nbArg, Set<String> namedArgument) {
return nbArg == 1;
}
public TValue executeReturnFunction(TContext context, TMemory memory, LineLocation location, List<TValue> values,
Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final String colorString = values.get(0).toString();
try {
final HColor color = HColorSet.instance().getColor(colorString);
return TValue.fromBoolean(!color.isDark());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
}
}
}

View File

@ -0,0 +1,75 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* 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
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* 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.tim.stdlib;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException;
public class Lighten extends SimpleReturnFunction {
// Inspired from https://github.com/Qix-/color
public TFunctionSignature getSignature() {
return new TFunctionSignature("%lighten", 2);
}
public boolean canCover(int nbArg, Set<String> namedArgument) {
return nbArg == 2;
}
public TValue executeReturnFunction(TContext context, TMemory memory, LineLocation location, List<TValue> values,
Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final String colorString = values.get(0).toString();
final int ratio = values.get(1).toInt();
try {
HColor color = HColorSet.instance().getColor(colorString);
color = color.lighten(ratio);
return TValue.fromString(color.asString());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
}
}
}

View File

@ -35,6 +35,8 @@
*/
package net.sourceforge.plantuml.ugraphic;
import static net.sourceforge.plantuml.ugraphic.ImageBuilder.plainPngBuilder;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Shape;
@ -61,8 +63,6 @@ import net.sourceforge.plantuml.svg.LengthAdjust;
import net.sourceforge.plantuml.svg.SvgGraphics;
import net.sourceforge.plantuml.ugraphic.color.HColorUtils;
import static net.sourceforge.plantuml.ugraphic.ImageBuilder.plainPngBuilder;
public class FontChecker {
final private UFont font;

View File

@ -35,6 +35,8 @@
*/
package net.sourceforge.plantuml.ugraphic;
import static net.sourceforge.plantuml.SkinParam.DEFAULT_PRESERVE_ASPECT_RATIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
@ -105,8 +107,6 @@ import net.sourceforge.plantuml.ugraphic.tikz.UGraphicTikz;
import net.sourceforge.plantuml.ugraphic.txt.UGraphicTxt;
import net.sourceforge.plantuml.ugraphic.visio.UGraphicVdx;
import static net.sourceforge.plantuml.SkinParam.DEFAULT_PRESERVE_ASPECT_RATIO;
public class ImageBuilder {
private Animation animation;
@ -484,7 +484,7 @@ public class ImageBuilder {
return ug;
}
private static HColor calculateBackColor(TitledDiagram diagram) {
public static HColor calculateBackColor(TitledDiagram diagram) {
if (UseStyle.useBetaStyle()) {
final Style style = StyleSignature
.of(SName.root, SName.document, diagram.getUmlDiagramType().getStyleName())

View File

@ -40,7 +40,7 @@ import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import net.sourceforge.plantuml.ugraphic.color.ColorChangerMonochrome;
import net.sourceforge.plantuml.ugraphic.color.ColorUtils;
public class PixelImage implements MutableImage {
@ -131,8 +131,8 @@ public class PixelImage implements MutableImage {
// if (isTransparent(color)) {
// continue;
// }
final int grey = ColorChangerMonochrome.getGrayScale(rgb);
if (darkerRgb == -1 || grey < ColorChangerMonochrome.getGrayScale(darkerRgb)) {
final int grey = ColorUtils.getGrayScale(rgb);
if (darkerRgb == -1 || grey < ColorUtils.getGrayScale(darkerRgb)) {
darkerRgb = rgb;
}
}

View File

@ -43,21 +43,8 @@ public class ColorChangerMonochrome {
if (color == null) {
return null;
}
final int grayScale = getGrayScale(color);
final int grayScale = ColorUtils.getGrayScale(color);
return new Color(grayScale, grayScale, grayScale);
}
private static int getGrayScale(Color color) {
final int red = color.getRed();
final int green = color.getGreen();
final int blue = color.getBlue();
return (int) (red * .3 + green * .59 + blue * .11);
}
public static int getGrayScale(int rgb) {
final int red = rgb & 0x00FF0000;
final int green = (rgb & 0x0000FF00) >> 8;
final int blue = (rgb & 0x000000FF) >> 16;
return (int) (red * .3 + green * .59 + blue * .11);
}
}

View File

@ -52,6 +52,9 @@ public class ColorMapperIdentity extends AbstractColorMapper implements ColorMap
if (color instanceof HColorMiddle) {
return ((HColorMiddle) color).getMappedColor(this);
}
if (color instanceof HColorAutomatic) {
throw new IllegalStateException();
}
return ((HColorSimple) color).getColor999();
}
}

View File

@ -39,11 +39,23 @@ import java.awt.Color;
public class ColorUtils {
static int getGrayScale(Color color) {
final int grayScale = (int) (color.getRed() * .3 + color.getGreen() * .59 + color.getBlue() * .11);
public static int getGrayScale(Color color) {
return getGrayScale(color.getRed(), color.getGreen(), color.getBlue());
}
public static int getGrayScale(int red, int green, int blue) {
// YIQ equation from http://24ways.org/2010/calculating-color-contrast
final int grayScale = (red * 299 + green * 587 + blue * 114) / 1000;
return grayScale;
}
public static int getGrayScale(int rgb) {
final int red = (rgb & 0x00FF0000) >> 16;
final int green = (rgb & 0x0000FF00) >> 8;
final int blue = (rgb & 0x000000FF);
return getGrayScale(red, green, blue);
}
public static Color getGrayScaleColor(Color color) {
final int grayScale = getGrayScale(color);
return new Color(grayScale, grayScale, grayScale);

View File

@ -42,4 +42,12 @@ public interface HColor extends UChange {
public UBackground bg();
public HColor darken(int ratio);
public HColor lighten(int ratio);
public String asString();
public boolean isDark();
}

View File

@ -38,7 +38,7 @@ import net.sourceforge.plantuml.ugraphic.UBackground;
abstract class HColorAbstract implements HColor {
final public UBackground bg() {
public UBackground bg() {
return new UBackground() {
public HColor getBackColor() {
return HColorAbstract.this;
@ -46,4 +46,21 @@ abstract class HColorAbstract implements HColor {
};
}
public HColor lighten(int ratio) {
return this;
}
public HColor darken(int ratio) {
return this;
}
@Override
public boolean isDark() {
return true;
}
public String asString() {
return "?" + getClass().getSimpleName();
}
}

View File

@ -36,4 +36,22 @@ package net.sourceforge.plantuml.ugraphic.color;
public class HColorAutomatic extends HColorAbstract implements HColor {
private final HColor color1;
private final HColor color2;
public HColorAutomatic(HColor color1, HColor color2) {
this.color1 = color1;
this.color2 = color2;
}
public HColor getAppropriateColor(HColor back) {
if (back == null) {
return color2;
}
if (back.isDark()) {
return color2;
}
return color1;
}
}

View File

@ -0,0 +1,39 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* 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
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* 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.ugraphic.color;
public class HColorAutomaticLegacy extends HColorAbstract implements HColor {
}

View File

@ -36,8 +36,9 @@ package net.sourceforge.plantuml.ugraphic.color;
import net.sourceforge.plantuml.ugraphic.UBackground;
public class HColorNone implements HColor {
public class HColorNone extends HColorAbstract implements HColor {
@Override
public UBackground bg() {
return new UBackground() {
public HColor getBackColor() {

View File

@ -238,17 +238,36 @@ public class HColorSet {
this.s2 = s2;
}
boolean isGradientValid() {
boolean isValid() {
return isColorValid(s1) && isColorValid(s2);
}
HColorGradient buildGradient(HColor background) {
HColorGradient buildInternal(HColor background) {
return new HColorGradient(build(s1, background), build(s2, background), sep);
}
}
private Gradient fromString(String s) {
class Automatic {
private final String s1;
private final String s2;
Automatic(String s1, String s2) {
this.s1 = s1;
this.s2 = s2;
}
boolean isValid() {
return isColorValid(s1) && isColorValid(s2);
}
HColorAutomatic buildInternal(HColor background) {
return new HColorAutomatic(build(s1, background), build(s2, background));
}
}
private Gradient gradientFromString(String s) {
final Matcher2 m = MyPattern.cmpile("[-\\\\|/]").matcher(s);
if (m.find()) {
final char sep = m.group(0).charAt(0);
@ -260,6 +279,22 @@ public class HColorSet {
return null;
}
private Automatic automaticFromString(String s) {
if (s.startsWith("#")) {
s = s.substring(1);
}
if (s.startsWith("?") == false) {
return null;
}
final int idx = s.indexOf(':');
if (idx != -1) {
final String s1 = s.substring(1, idx);
final String s2 = s.substring(idx + 1);
return new Automatic(s1, s2);
}
return null;
}
public HColor getColorOrWhite(String s) {
return getColorOrWhite(s, null);
}
@ -290,9 +325,13 @@ public class HColorSet {
if (isColorValid(s) == false) {
throw new NoSuchColorException();
}
final Gradient gradient = fromString(s);
final Automatic automatic = automaticFromString(s);
if (automatic != null) {
return automatic.buildInternal(background);
}
final Gradient gradient = gradientFromString(s);
if (gradient != null) {
return gradient.buildGradient(background);
return gradient.buildInternal(background);
}
if (background == null && (s.equalsIgnoreCase("#transparent") || s.equalsIgnoreCase("transparent")))
s = "#00000000";
@ -301,9 +340,13 @@ public class HColorSet {
private boolean isColorValid(String s) {
s = removeFirstDieseAndgoLowerCase(s);
final Gradient gradient = fromString(s);
final Automatic automatic = automaticFromString(s);
if (automatic != null) {
return automatic.isValid();
}
final Gradient gradient = gradientFromString(s);
if (gradient != null) {
return gradient.isGradientValid();
return gradient.isValid();
}
if (s.matches("[0-9A-Fa-f]{3}")) {
return true;
@ -333,7 +376,7 @@ public class HColorSet {
if (s.equalsIgnoreCase("transparent") || s.equalsIgnoreCase("background")) {
return new HColorBackground(background);
} else if (s.equalsIgnoreCase("automatic")) {
return new HColorAutomatic();
return new HColorAutomaticLegacy();
} else if (s.matches("[0-9A-Fa-f]{3}")) {
s = "" + s.charAt(0) + s.charAt(0) + s.charAt(1) + s.charAt(1) + s.charAt(2) + s.charAt(2);
color = new Color(Integer.parseInt(s, 16));

View File

@ -37,6 +37,8 @@ package net.sourceforge.plantuml.ugraphic.color;
import java.awt.Color;
import net.sourceforge.plantuml.svek.DotStringFactory;
public class HColorSimple extends HColorAbstract implements HColor {
private final Color color;
@ -55,6 +57,36 @@ public class HColorSimple extends HColorAbstract implements HColor {
return color.toString() + " alpha=" + color.getAlpha() + " monochrome=" + monochrome;
}
@Override
public String asString() {
if (isTransparent()) {
return "transparent";
}
if (color.getAlpha() == 255) {
return DotStringFactory.sharp000000(color.getRGB());
}
return super.asString();
}
@Override
public HColor lighten(int ratio) {
final float[] hsl = new HSLColor(color).getHSL();
hsl[2] += hsl[2] * (ratio / 100.0);
return new HColorSimple(new HSLColor(hsl).getRGB(), false);
}
@Override
public HColor darken(int ratio) {
final float[] hsl = new HSLColor(color).getHSL();
hsl[2] -= hsl[2] * (ratio / 100.0);
return new HColorSimple(new HSLColor(hsl).getRGB(), false);
}
@Override
public boolean isDark() {
return ColorUtils.getGrayScale(color) < 128;
}
public boolean isTransparent() {
return color.getAlpha() == 0;
}

View File

@ -0,0 +1,389 @@
package net.sourceforge.plantuml.ugraphic.color;
import java.awt.Color;
/**
* Taken from http://www.camick.com/java/source/HSLColor.java
*
* The HSLColor class provides methods to manipulate HSL (Hue, Saturation
* Luminance) values to create a corresponding Color object using the RGB
* ColorSpace.
*
* The HUE is the color, the Saturation is the purity of the color (with respect
* to grey) and Luminance is the brightness of the color (with respect to black
* and white)
*
* The Hue is specified as an angel between 0 - 360 degrees where red is 0,
* green is 120 and blue is 240. In between you have the colors of the rainbow.
* Saturation is specified as a percentage between 0 - 100 where 100 is fully
* saturated and 0 approaches gray. Luminance is specified as a percentage
* between 0 - 100 where 0 is black and 100 is white.
*
* In particular the HSL color space makes it easier change the Tone or Shade of
* a color by adjusting the luminance value.
*/
public class HSLColor {
private Color rgb;
private float[] hsl;
private float alpha;
/**
* Create a HSLColor object using an RGB Color object.
*
* @param rgb the RGB Color object
*/
public HSLColor(Color rgb) {
this.rgb = rgb;
hsl = fromRGB(rgb);
alpha = rgb.getAlpha() / 255.0f;
}
/**
* Create a HSLColor object using individual HSL values and a default alpha
* value of 1.0.
*
* @param h is the Hue value in degrees between 0 - 360
* @param s is the Saturation percentage between 0 - 100
* @param l is the Lumanance percentage between 0 - 100
*/
public HSLColor(float h, float s, float l) {
this(h, s, l, 1.0f);
}
/**
* Create a HSLColor object using individual HSL values.
*
* @param h the Hue value in degrees between 0 - 360
* @param s the Saturation percentage between 0 - 100
* @param l the Lumanance percentage between 0 - 100
* @param alpha the alpha value between 0 - 1
*/
public HSLColor(float h, float s, float l, float alpha) {
hsl = new float[] { h, s, l };
this.alpha = alpha;
rgb = toRGB(hsl, alpha);
}
/**
* Create a HSLColor object using an an array containing the individual HSL
* values and with a default alpha value of 1.
*
* @param hsl array containing HSL values
*/
public HSLColor(float[] hsl) {
this(hsl, 1.0f);
}
/**
* Create a HSLColor object using an an array containing the individual HSL
* values.
*
* @param hsl array containing HSL values
* @param alpha the alpha value between 0 - 1
*/
public HSLColor(float[] hsl, float alpha) {
this.hsl = hsl;
this.alpha = alpha;
rgb = toRGB(hsl, alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different Hue value.
* The degrees specified is an absolute value.
*
* @param degrees - the Hue value between 0 - 360
* @return the RGB Color object
*/
public Color adjustHue(float degrees) {
return toRGB(degrees, hsl[1], hsl[2], alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different Luminance
* value. The percent specified is an absolute value.
*
* @param percent - the Luminance value between 0 - 100
* @return the RGB Color object
*/
public Color adjustLuminance(float percent) {
return toRGB(hsl[0], hsl[1], percent, alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different Saturation
* value. The percent specified is an absolute value.
*
* @param percent - the Saturation value between 0 - 100
* @return the RGB Color object
*/
public Color adjustSaturation(float percent) {
return toRGB(hsl[0], percent, hsl[2], alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different Shade.
* Changing the shade will return a darker color. The percent specified is a
* relative value.
*
* @param percent - the value between 0 - 100
* @return the RGB Color object
*/
public Color adjustShade(float percent) {
float multiplier = (100.0f - percent) / 100.0f;
float l = Math.max(0.0f, hsl[2] * multiplier);
return toRGB(hsl[0], hsl[1], l, alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different Tone.
* Changing the tone will return a lighter color. The percent specified is a
* relative value.
*
* @param percent - the value between 0 - 100
* @return the RGB Color object
*/
public Color adjustTone(float percent) {
float multiplier = (100.0f + percent) / 100.0f;
float l = Math.min(100.0f, hsl[2] * multiplier);
return toRGB(hsl[0], hsl[1], l, alpha);
}
/**
* Get the Alpha value.
*
* @return the Alpha value.
*/
public float getAlpha() {
return alpha;
}
/**
* Create a RGB Color object that is the complementary color of this HSLColor.
* This is a convenience method. The complementary color is determined by adding
* 180 degrees to the Hue value.
*
* @return the RGB Color object
*/
public Color getComplementary() {
float hue = (hsl[0] + 180.0f) % 360.0f;
return toRGB(hue, hsl[1], hsl[2]);
}
/**
* Get the Hue value.
*
* @return the Hue value.
*/
public float getHue() {
return hsl[0];
}
/**
* Get the HSL values.
*
* @return the HSL values.
*/
public float[] getHSL() {
return hsl;
}
/**
* Get the Luminance value.
*
* @return the Luminance value.
*/
public float getLuminance() {
return hsl[2];
}
/**
* Get the RGB Color object represented by this HDLColor.
*
* @return the RGB Color object.
*/
public Color getRGB() {
return rgb;
}
/**
* Get the Saturation value.
*
* @return the Saturation value.
*/
public float getSaturation() {
return hsl[1];
}
public String toString() {
String toString = "HSLColor[h=" + hsl[0] + ",s=" + hsl[1] + ",l=" + hsl[2] + ",alpha=" + alpha + "]";
return toString;
}
/**
* Convert a RGB Color to it corresponding HSL values.
*
* @return an array containing the 3 HSL values.
*/
public static float[] fromRGB(Color color) {
// Get RGB values in the range 0 - 1
float[] rgb = color.getRGBColorComponents(null);
float r = rgb[0];
float g = rgb[1];
float b = rgb[2];
// Minimum and Maximum RGB values are used in the HSL calculations
float min = Math.min(r, Math.min(g, b));
float max = Math.max(r, Math.max(g, b));
// Calculate the Hue
float h = 0;
if (max == min)
h = 0;
else if (max == r)
h = ((60 * (g - b) / (max - min)) + 360) % 360;
else if (max == g)
h = (60 * (b - r) / (max - min)) + 120;
else if (max == b)
h = (60 * (r - g) / (max - min)) + 240;
// Calculate the Luminance
float l = (max + min) / 2;
// Calculate the Saturation
float s = 0;
if (max == min)
s = 0;
else if (l <= .5f)
s = (max - min) / (max + min);
else
s = (max - min) / (2 - max - min);
return new float[] { h, s * 100, l * 100 };
}
/**
* Convert HSL values to a RGB Color with a default alpha value of 1. H (Hue) is
* specified as degrees in the range 0 - 360. S (Saturation) is specified as a
* percentage in the range 1 - 100. L (Lumanance) is specified as a percentage
* in the range 1 - 100.
*
* @param hsl an array containing the 3 HSL values
*
* @returns the RGB Color object
*/
public static Color toRGB(float[] hsl) {
return toRGB(hsl, 1.0f);
}
/**
* Convert HSL values to a RGB Color. H (Hue) is specified as degrees in the
* range 0 - 360. S (Saturation) is specified as a percentage in the range 1 -
* 100. L (Lumanance) is specified as a percentage in the range 1 - 100.
*
* @param hsl an array containing the 3 HSL values
* @param alpha the alpha value between 0 - 1
*
* @returns the RGB Color object
*/
public static Color toRGB(float[] hsl, float alpha) {
return toRGB(hsl[0], hsl[1], hsl[2], alpha);
}
/**
* Convert HSL values to a RGB Color with a default alpha value of 1.
*
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Lumanance is specified as a percentage in the range 1 - 100.
*
* @returns the RGB Color object
*/
public static Color toRGB(float h, float s, float l) {
return toRGB(h, s, l, 1.0f);
}
/**
* Convert HSL values to a RGB Color.
*
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Lumanance is specified as a percentage in the range 1 - 100.
* @param alpha the alpha value between 0 - 1
*
* @returns the RGB Color object
*/
public static Color toRGB(float h, float s, float l, float alpha) {
if (s < 0.0f || s > 100.0f) {
String message = "Color parameter outside of expected range - Saturation";
throw new IllegalArgumentException(message);
}
if (l < 0.0f || l > 100.0f) {
String message = "Color parameter outside of expected range - Luminance";
throw new IllegalArgumentException(message);
}
if (alpha < 0.0f || alpha > 1.0f) {
String message = "Color parameter outside of expected range - Alpha";
throw new IllegalArgumentException(message);
}
// Formula needs all values between 0 - 1.
h = h % 360.0f;
h /= 360f;
s /= 100f;
l /= 100f;
float q = 0;
if (l < 0.5)
q = l * (1 + s);
else
q = (l + s) - (s * l);
float p = 2 * l - q;
float r = Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f)));
float g = Math.max(0, HueToRGB(p, q, h));
float b = Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f)));
r = Math.min(r, 1.0f);
g = Math.min(g, 1.0f);
b = Math.min(b, 1.0f);
return new Color(r, g, b, alpha);
}
private static float HueToRGB(float p, float q, float h) {
if (h < 0)
h += 1;
if (h > 1)
h -= 1;
if (6 * h < 1) {
return p + ((q - p) * 6 * h);
}
if (2 * h < 1) {
return q;
}
if (3 * h < 2) {
return p + ((q - p) * 6 * ((2.0f / 3.0f) - h));
}
return p;
}
}

View File

@ -80,7 +80,7 @@ public class Version {
}
public static int beta() {
final int beta = 2;
final int beta = 4;
return beta;
}