org.mapfish.print.map.style.json.JsonStyleParserHelper Maven / Gradle / Ivy
package org.mapfish.print.map.style.json;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.styling.AnchorPoint;
import org.geotools.styling.Displacement;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Font;
import org.geotools.styling.Graphic;
import org.geotools.styling.Halo;
import org.geotools.styling.LabelPlacement;
import org.geotools.styling.LinePlacement;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.PointPlacement;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.styling.TextSymbolizer;
import org.mapfish.print.ExceptionUtils;
import org.mapfish.print.config.Configuration;
import org.mapfish.print.wrapper.json.PJsonObject;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import java.awt.Color;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import static org.mapfish.print.FileUtils.testForLegalFileUrl;
import static org.mapfish.print.map.style.json.MapfishJsonStyleParserPlugin.Versions;
/**
* Methods shared by various style versions for creating geotools SLD styles from the json format mapfish supports.
*
* @author Jesse on 7/25/2014.
*/
public final class JsonStyleParserHelper {
static final String JSON_FONT_FAMILY = "fontFamily";
static final String JSON_FONT_SIZE = "fontSize";
static final String JSON_FONT_WEIGHT = "fontWeight";
static final String JSON_FONT_STYLE = "fontStyle";
static final String JSON_LABEL = "label";
static final String JSON_LABEL_ANCHOR_POINT_X = "labelAnchorPointX";
static final String JSON_LABEL_ANCHOR_POINT_Y = "labelAnchorPointY";
static final String JSON_LABEL_ALIGN = "labelAlign";
static final String JSON_LABEL_X_OFFSET = "labelXOffset";
static final String JSON_LABEL_Y_OFFSET = "labelYOffset";
static final String JSON_LABEL_ROTATION = "labelRotation";
static final String JSON_LABEL_PERPENDICULAR_OFFSET = "labelPerpendicularOffset";
static final String JSON_FILL_COLOR = "fillColor";
static final String JSON_STROKE_COLOR = "strokeColor";
static final String JSON_STROKE_OPACITY = "strokeOpacity";
static final String JSON_STROKE_WIDTH = "strokeWidth";
static final String JSON_STROKE_DASHSTYLE = "strokeDashstyle";
static final String JSON_STROKE_LINECAP = "strokeLinecap";
static final String JSON_FILL_OPACITY = "fillOpacity";
static final String JSON_EXTERNAL_GRAPHIC = "externalGraphic";
static final String JSON_GRAPHIC_NAME = "graphicName";
static final String JSON_GRAPHIC_OPACITY = "graphicOpacity";
static final String JSON_POINT_RADIUS = "pointRadius";
static final String JSON_GRAPHIC_WIDTH = "graphicWidth";
static final String JSON_ROTATION = "rotation";
static final String JSON_HALO_RADIUS = "haloRadius";
static final String JSON_HALO_COLOR = "haloColor";
static final String JSON_HALO_OPACITY = "haloOpacity";
static final String JSON_LABEL_OUTLINE_COLOR = "labelOutlineColor";
static final String JSON_LABEL_OUTLINE_WIDTH = "labelOutlineWidth";
static final String JSON_FONT_COLOR = "fontColor";
static final String JSON_FONT_OPACITY = "fontOpacity";
static final String JSON_GRAPHIC_FORMAT = "graphicFormat";
static final String STROKE_DASHSTYLE_SOLID = "solid";
static final String STROKE_DASHSTYLE_DOT = "dot";
static final String STROKE_DASHSTYLE_DASH = "dash";
static final String STROKE_DASHSTYLE_DASHDOT = "dashdot";
static final String STROKE_DASHSTYLE_LONGDASH = "longdash";
static final String STROKE_DASHSTYLE_LONGDASHDOT = "longdashdot";
static final Set> COMPATIBLE_MIMETYPES = Sets.newIdentityHashSet();
static {
COMPATIBLE_MIMETYPES.add(Sets.newHashSet("image/jpeg", "image/jpg"));
COMPATIBLE_MIMETYPES.add(Sets.newHashSet("image/jpeg1000", "image/jpg2000"));
COMPATIBLE_MIMETYPES.add(Sets.newHashSet("image/tiff", "image/tif"));
}
private static final String[] SUPPORTED_MIME_TYPES = ImageIO.getReaderMIMETypes();
private static final String DEFAULT_POINT_MARK = "circle";
private final Configuration configuration;
private boolean allowNullSymbolizer;
private StyleBuilder styleBuilder;
private Versions version;
/**
* Constructor.
*
* @param configuration the configuration to use for resolving relative files or other settings.
* @param styleBuilder a style builder to use for creating the style objects.
* @param allowNullSymbolizer If true then create*Symbolizer() methods can return null if expected params are missing.
* @param version the version being parsed.
*/
public JsonStyleParserHelper(@Nonnull final Configuration configuration,
@Nonnull final StyleBuilder styleBuilder,
final boolean allowNullSymbolizer,
final Versions version) {
this.configuration = configuration;
this.styleBuilder = styleBuilder;
this.allowNullSymbolizer = allowNullSymbolizer;
this.version = version;
}
void setAllowNullSymbolizer(final boolean allowNullSymbolizer) {
this.allowNullSymbolizer = allowNullSymbolizer;
}
/**
* Create a style from a list of rules.
*
* @param styleRules the rules
*/
public Style createStyle(final List styleRules) {
final Rule[] rulesArray = styleRules.toArray(new Rule[styleRules.size()]);
final FeatureTypeStyle featureTypeStyle = this.styleBuilder.createFeatureTypeStyle(null, rulesArray);
final Style style = this.styleBuilder.createStyle();
style.featureTypeStyles().add(featureTypeStyle);
return style;
}
/**
* Add a point symbolizer definition to the rule.
*
* @param styleJson The old style.
*/
@Nullable
public PointSymbolizer createPointSymbolizer(final PJsonObject styleJson) {
if (this.allowNullSymbolizer && !(styleJson.has(JSON_EXTERNAL_GRAPHIC) || styleJson.has(JSON_GRAPHIC_NAME) ||
styleJson.has(JSON_POINT_RADIUS))) {
return null;
}
Graphic graphic = this.styleBuilder.createGraphic();
graphic.graphicalSymbols().clear();
if (styleJson.has(JSON_EXTERNAL_GRAPHIC)) {
String externalGraphicUrl = validateURL(styleJson.getString(JSON_EXTERNAL_GRAPHIC));
final String graphicFormat = getGraphicFormat(externalGraphicUrl, styleJson);
final ExternalGraphic externalGraphic = this.styleBuilder.createExternalGraphic(externalGraphicUrl, graphicFormat);
graphic.graphicalSymbols().add(externalGraphic);
}
if (styleJson.has(JSON_GRAPHIC_NAME)) {
Expression graphicName = parseProperty(styleJson.getString(JSON_GRAPHIC_NAME), new Function() {
public Object apply(final String input) {
return input;
}
});
Fill fill = createFill(styleJson);
Stroke stroke = createStroke(styleJson, false);
final Mark mark = this.styleBuilder.createMark(graphicName, fill, stroke);
graphic.graphicalSymbols().add(mark);
}
if (graphic.graphicalSymbols().isEmpty()) {
Fill fill = createFill(styleJson);
Stroke stroke = createStroke(styleJson, false);
final Mark mark = this.styleBuilder.createMark(DEFAULT_POINT_MARK, fill, stroke);
graphic.graphicalSymbols().add(mark);
}
graphic.setOpacity(parseExpression(null, styleJson, JSON_GRAPHIC_OPACITY, new Function() {
@Nullable
@Override
public Object apply(final String opacityString) {
return Double.parseDouble(opacityString);
}
}));
if (!Strings.isNullOrEmpty(styleJson.optString(JSON_POINT_RADIUS))) {
Expression size = parseExpression(null, styleJson, JSON_POINT_RADIUS, new Function() {
@Nullable
@Override
public Object apply(final String input) {
return Double.parseDouble(input) * 2;
}
});
graphic.setSize(size);
} else if (!Strings.isNullOrEmpty(styleJson.optString(JSON_GRAPHIC_WIDTH))) {
Expression size = parseExpression(null, styleJson, JSON_GRAPHIC_WIDTH, new Function() {
@Nullable
@Override
public Object apply(final String input) {
return Double.parseDouble(input);
}
});
graphic.setSize(size);
}
if (!Strings.isNullOrEmpty(styleJson.optString(JSON_ROTATION))) {
final Expression rotation = parseExpression(null, styleJson, JSON_ROTATION, new Function() {
@Nullable
@Override
public Object apply(final String rotation) {
return Double.parseDouble(rotation);
}
});
graphic.setRotation(rotation);
}
return this.styleBuilder.createPointSymbolizer(graphic);
}
private String validateURL(final String externalGraphicUrl) {
try {
new URL(externalGraphicUrl);
} catch (MalformedURLException e) {
// not a url so assume a file url and verify that it is valid
try {
final URL fileURL = new URL("file://" + externalGraphicUrl);
return testForLegalFileUrl(this.configuration, fileURL).toExternalForm();
} catch (MalformedURLException e1) {
// unable to convert to file url so give up and throw exception;
throw ExceptionUtils.getRuntimeException(e);
}
}
return externalGraphicUrl;
}
/**
* Add a line symbolizer definition to the rule.
*
* @param styleJson The old style.
*/
@VisibleForTesting
@Nullable
protected LineSymbolizer createLineSymbolizer(final PJsonObject styleJson) {
final Stroke stroke = createStroke(styleJson, true);
if (stroke == null) {
return null;
} else {
return this.styleBuilder.createLineSymbolizer(stroke);
}
}
/**
* Add a polygon symbolizer definition to the rule.
*
* @param styleJson The old style.
*/
@Nullable
@VisibleForTesting
protected PolygonSymbolizer createPolygonSymbolizer(final PJsonObject styleJson) {
if (this.allowNullSymbolizer && !styleJson.has(JSON_FILL_COLOR)) {
return null;
}
final PolygonSymbolizer symbolizer = this.styleBuilder.createPolygonSymbolizer();
symbolizer.setFill(createFill(styleJson));
symbolizer.setStroke(createStroke(styleJson, false));
return symbolizer;
}
/**
* Add a text symbolizer definition to the rule.
*
* @param styleJson The old style.
*/
@VisibleForTesting
protected TextSymbolizer createTextSymbolizer(final PJsonObject styleJson) {
final TextSymbolizer textSymbolizer = this.styleBuilder.createTextSymbolizer();
if (styleJson.has(JSON_LABEL)) {
final Expression label = parseExpression(null, styleJson, JSON_LABEL, new Function() {
@Nullable
@Override
public Object apply(final String labelValue) {
return labelValue.replace("${", "").replace("}", "");
}
});
textSymbolizer.setLabel(label);
} else {
return null;
}
textSymbolizer.setFont(createFont(textSymbolizer.getFont(), styleJson));
if (styleJson.has(JSON_LABEL_ANCHOR_POINT_X) ||
styleJson.has(JSON_LABEL_ANCHOR_POINT_Y) ||
styleJson.has(JSON_LABEL_ALIGN) ||
styleJson.has(JSON_LABEL_X_OFFSET) ||
styleJson.has(JSON_LABEL_Y_OFFSET) ||
styleJson.has(JSON_LABEL_ROTATION) ||
styleJson.has(JSON_LABEL_PERPENDICULAR_OFFSET)) {
textSymbolizer.setLabelPlacement(createLabelPlacement(styleJson));
}
if (!Strings.isNullOrEmpty(styleJson.optString(JSON_HALO_RADIUS)) ||
!Strings.isNullOrEmpty(styleJson.optString(JSON_HALO_COLOR)) ||
!Strings.isNullOrEmpty(styleJson.optString(JSON_HALO_OPACITY)) ||
!Strings.isNullOrEmpty(styleJson.optString(JSON_LABEL_OUTLINE_WIDTH)) ||
!Strings.isNullOrEmpty(styleJson.optString(JSON_LABEL_OUTLINE_COLOR))) {
textSymbolizer.setHalo(createHalo(styleJson));
}
if (!Strings.isNullOrEmpty(styleJson.optString(JSON_FONT_COLOR)) ||
!Strings.isNullOrEmpty(styleJson.optString(JSON_FONT_OPACITY))) {
textSymbolizer.setFill(addFill(styleJson.optString(JSON_FONT_COLOR, "black"), styleJson.optString(JSON_FONT_OPACITY, "1.0")));
}
return textSymbolizer;
}
private Font createFont(final Font defaultFont, final PJsonObject styleJson) {
Expression fontFamily = parseExpression(null, styleJson, JSON_FONT_FAMILY, new Function() {
@Override
public String apply(final String fontFamily) {
return fontFamily;
}
});
if (fontFamily == null) {
fontFamily = defaultFont.getFamily().get(0);
}
List fontFamilies = getFontExpressions(fontFamily);
Expression fontSize = parseExpression(null, styleJson, JSON_FONT_SIZE, new Function() {
@Nullable
@Override
public Object apply(final String input) {
String fontSizeString = input;
if (fontSizeString.endsWith("px")) {
fontSizeString = fontSizeString.substring(0, fontSizeString.length() - 2);
}
return Integer.parseInt(fontSizeString);
}
});
if (fontSize == null) {
fontSize = defaultFont.getSize();
}
Expression fontWeight = parseExpression(null, styleJson, JSON_FONT_WEIGHT, Functions.identity());
if (fontWeight == null) {
fontWeight = defaultFont.getWeight();
}
Expression fontStyle = parseExpression(null, styleJson, JSON_FONT_STYLE, Functions.identity());
if (fontStyle == null) {
fontStyle = defaultFont.getStyle();
}
Font font = this.styleBuilder.createFont(fontFamilies.get(0), fontStyle, fontWeight, fontSize);
if (fontFamilies.size() > 1) {
// add remaining "fallback" fonts
for (int i = 1; i < fontFamilies.size(); i++) {
font.getFamily().add(fontFamilies.get(i));
}
}
return font;
}
private List getFontExpressions(final Expression fontFamily) {
List fontFamilies = new LinkedList();
if (fontFamily instanceof Literal) {
String fonts = (String) ((Literal) fontFamily).getValue();
for (String font : fonts.split(",")) {
font = font.trim();
// translate SVG/CSS font expressions to Java logical fonts
if (font.equalsIgnoreCase("serif")) {
font = "Serif";
} else if (font.equalsIgnoreCase("sans-serif")) {
font = "SansSerif";
} else if (font.equalsIgnoreCase("monospace")) {
font = "Monospaced";
}
fontFamilies.add(this.styleBuilder.literalExpression(font));
}
} else {
fontFamilies.add(fontFamily);
}
return fontFamilies;
}
private LabelPlacement createLabelPlacement(final PJsonObject styleJson) {
if ((styleJson.has(JSON_LABEL_ANCHOR_POINT_X) ||
styleJson.has(JSON_LABEL_ANCHOR_POINT_Y) ||
styleJson.has(JSON_LABEL_ALIGN) ||
styleJson.has(JSON_LABEL_X_OFFSET) ||
styleJson.has(JSON_LABEL_Y_OFFSET) ||
styleJson.has(JSON_LABEL_ROTATION))
&& Strings.isNullOrEmpty(styleJson.optString(JSON_LABEL_PERPENDICULAR_OFFSET))) {
return createPointPlacement(styleJson);
}
return createLinePlacement(styleJson);
}
private LinePlacement createLinePlacement(final PJsonObject styleJson) {
Expression linePlacement = parseExpression(null, styleJson, JSON_LABEL_PERPENDICULAR_OFFSET, new Function() {
@Nullable
@Override
public Object apply(final String input) {
return Double.parseDouble(input);
}
});
if (linePlacement != null) {
return this.styleBuilder.createLinePlacement(linePlacement);
}
return null;
}
@Nullable
private PointPlacement createPointPlacement(final PJsonObject styleJson) {
AnchorPoint anchorPoint = createAnchorPoint(styleJson);
Displacement displacement = null;
if (styleJson.has(JSON_LABEL_X_OFFSET) || styleJson.has(JSON_LABEL_Y_OFFSET)) {
Expression xOffset = parseExpression(0.0, styleJson, JSON_LABEL_X_OFFSET, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
Expression yOffset = parseExpression(0.0, styleJson, JSON_LABEL_Y_OFFSET, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
displacement = this.styleBuilder.createDisplacement(xOffset, yOffset);
}
Expression rotation = parseExpression(0.0, styleJson, JSON_LABEL_ROTATION, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
if (anchorPoint == null) {
anchorPoint = this.styleBuilder.createAnchorPoint(0, 0);
}
if (displacement == null) {
displacement = this.styleBuilder.createDisplacement(0, 0);
}
return this.styleBuilder.createPointPlacement(anchorPoint, displacement, rotation);
}
private AnchorPoint createAnchorPoint(final PJsonObject styleJson) {
Expression anchorX = parseExpression(null, styleJson, JSON_LABEL_ANCHOR_POINT_X, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
Expression anchorY = parseExpression(null, styleJson, JSON_LABEL_ANCHOR_POINT_Y, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
if (anchorX == null && anchorY == null) {
String labelAlign = styleJson.getString(JSON_LABEL_ALIGN);
String xAlign = labelAlign.substring(0, 1);
String yAlign = labelAlign.substring(1, 2);
final double anchorInMiddle = 0.5;
if ("l".equals(xAlign)) {
anchorX = this.styleBuilder.literalExpression(0.0);
} else if ("c".equals(xAlign)) {
anchorX = this.styleBuilder.literalExpression(anchorInMiddle);
} else if ("r".equals(xAlign)) {
anchorX = this.styleBuilder.literalExpression(1.0);
}
if ("b".equals(yAlign)) {
anchorY = this.styleBuilder.literalExpression(0.0);
} else if ("m".equals(yAlign)) {
anchorY = this.styleBuilder.literalExpression(anchorInMiddle);
} else if ("t".equals(yAlign)) {
anchorY = this.styleBuilder.literalExpression(1.0);
}
}
boolean returnNull = true;
if (anchorX == null) {
anchorX = this.styleBuilder.literalExpression(0.0);
} else {
returnNull = false;
}
if (anchorY == null) {
anchorY = this.styleBuilder.literalExpression(0.0);
} else {
returnNull = false;
}
if (returnNull) {
return null;
}
return this.styleBuilder.createAnchorPoint(anchorX, anchorY);
}
private Halo createHalo(final PJsonObject styleJson) {
if (styleJson.has(JSON_HALO_RADIUS)) {
Expression radius = parseExpression(1.0, styleJson, JSON_HALO_RADIUS, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
final Fill fill;
if (styleJson.has(JSON_HALO_COLOR) || styleJson.has(JSON_HALO_OPACITY)) {
fill = addFill(styleJson.optString(JSON_HALO_COLOR, "white"), styleJson.optString(JSON_HALO_OPACITY, "1.0"));
return this.styleBuilder.createHalo(fill, radius);
}
}
// labelOutlineColor and labelOutlineWidth are aliases for halo that is used by some V2 Clients
if (styleJson.has(JSON_LABEL_OUTLINE_COLOR) || styleJson.has(JSON_LABEL_OUTLINE_WIDTH)) {
Expression radius = parseExpression(1.0, styleJson, JSON_LABEL_OUTLINE_WIDTH, new Function() {
@Nullable
@Override
public Double apply(final String input) {
return Double.parseDouble(input);
}
});
Fill fill = addFill(styleJson.optString(JSON_LABEL_OUTLINE_COLOR, "white"), "1.0");
return this.styleBuilder.createHalo(fill, radius);
}
return null;
}
private Fill createFill(final PJsonObject styleJson) {
if (this.allowNullSymbolizer && !styleJson.has(JSON_FILL_COLOR)) {
return null;
}
final String fillColor = styleJson.optString(JSON_FILL_COLOR, "black");
return addFill(fillColor, styleJson.optString(JSON_FILL_OPACITY, "1.0"));
}
private Fill addFill(final String fillColor, final String fillOpacity) {
final Expression finalFillColor = parseProperty(fillColor, new Function() {
@Nullable
@Override
public Object apply(final String fillColor) {
return toColorExpression(fillColor);
}
});
final Expression opacity = parseProperty(fillOpacity, new Function() {
@Nullable
@Override
public Object apply(final String fillOpacity) {
return Double.parseDouble(fillOpacity);
}
});
return this.styleBuilder.createFill(finalFillColor, opacity);
}
private Object toColorExpression(final String color) {
return ((Literal) JsonStyleParserHelper.this.styleBuilder.colorExpression(ColorParser.toColor(color))).getValue();
}
@Nullable
@VisibleForTesting
Stroke createStroke(final PJsonObject styleJson, final boolean allowNull) {
final float defaultDashSpacing = 0.1f;
final int doubleWidth = 2;
final int tripleWidth = 3;
final int quadrupleWidth = 4;
final int quintupleWidth = 5;
if (this.allowNullSymbolizer && allowNull && !styleJson.has(JSON_STROKE_COLOR)) {
return null;
}
Expression strokeColor = parseExpression(Color.black, styleJson, JSON_STROKE_COLOR, new Function() {
@Nullable
@Override
public Object apply(final String input) {
return toColorExpression(input);
}
});
Expression strokeOpacity = parseExpression(1.0, styleJson, JSON_STROKE_OPACITY, new Function() {
@Nullable
@Override
public Object apply(final String input) {
return Double.parseDouble(styleJson.getString(JSON_STROKE_OPACITY));
}
});
Expression widthExpression = parseExpression(1, styleJson, JSON_STROKE_WIDTH, new Function() {
@Nullable
@Override
public Object apply(final String input) {
return Double.parseDouble(styleJson.getString(JSON_STROKE_WIDTH));
}
});
float[] dashArray = null;
if (styleJson.has(JSON_STROKE_DASHSTYLE) && !STROKE_DASHSTYLE_SOLID.equals(styleJson.getString(JSON_STROKE_DASHSTYLE))) {
Double width = 1.0;
if (widthExpression instanceof Literal) {
Literal expression = (Literal) widthExpression;
width = ((Number) expression.getValue()).doubleValue();
}
String dashStyle = styleJson.getString(JSON_STROKE_DASHSTYLE);
if (dashStyle.equalsIgnoreCase(STROKE_DASHSTYLE_DOT)) {
dashArray = new float[]{defaultDashSpacing, (float) (doubleWidth * width)};
} else if (dashStyle.equalsIgnoreCase(STROKE_DASHSTYLE_DASH)) {
dashArray = new float[]{(float) (doubleWidth * width), (float) (doubleWidth * width)};
} else if (dashStyle.equalsIgnoreCase(STROKE_DASHSTYLE_DASHDOT)) {
dashArray = new float[]{
(float) (tripleWidth * width),
(float) (doubleWidth * width),
defaultDashSpacing,
(float) (doubleWidth * width)};
} else if (dashStyle.equalsIgnoreCase(STROKE_DASHSTYLE_LONGDASH)) {
dashArray = new float[]{
(float) (quadrupleWidth * width),
(float) (doubleWidth * width)};
} else if (dashStyle.equalsIgnoreCase(STROKE_DASHSTYLE_LONGDASHDOT)) {
dashArray = new float[]{
(float) (quintupleWidth * width),
(float) (doubleWidth * width),
defaultDashSpacing,
(float) (doubleWidth * width)};
} else if (dashStyle.contains(" ")) {
//check for pattern if empty array, throw.
try {
String[] x = dashStyle.split(" ");
if (x.length > 1) {
dashArray = new float[x.length];
for (int i = 0; i < x.length; i++) {
dashArray[i] = Float.parseFloat(x[i]);
}
}
} catch (NumberFormatException e) {
//assume solid!
}
} else {
throw new IllegalArgumentException("strokeDashstyle does not have a legal value: " + dashStyle);
}
}
Expression lineCap = parseExpression(null, styleJson, JSON_STROKE_LINECAP, Functions.identity());
final Stroke stroke = this.styleBuilder.createStroke(strokeColor, widthExpression);
stroke.setLineCap(lineCap);
stroke.setOpacity(strokeOpacity);
stroke.setDashArray(dashArray);
return stroke;
}
@VisibleForTesting
String getGraphicFormat(final String externalGraphicFile, final PJsonObject styleJson) {
String mimeType = null;
if (!Strings.isNullOrEmpty(styleJson.optString(JSON_GRAPHIC_FORMAT))) {
mimeType = styleJson.getString(JSON_GRAPHIC_FORMAT);
} else {
int separatorPos = externalGraphicFile.lastIndexOf(".");
if (separatorPos >= 0) {
mimeType = "image/" + externalGraphicFile.substring(separatorPos + 1).toLowerCase();
} else {
mimeType = "";
}
}
mimeType = toSupportedMimeType(mimeType);
return mimeType;
}
private String toSupportedMimeType(final String mimeType) {
for (Set compatibleMimeType : COMPATIBLE_MIMETYPES) {
if (compatibleMimeType.contains(mimeType.toLowerCase())) {
for (String compatible : compatibleMimeType) {
if (isSupportedMimetype(compatible)) {
return compatible;
}
}
}
}
return mimeType;
}
private boolean isSupportedMimetype(final String mimeType) {
for (String supported : SUPPORTED_MIME_TYPES) {
if (supported.equalsIgnoreCase(mimeType)) {
return true;
}
}
return false;
}
public void setVersion(final Versions version) {
this.version = version;
}
private Expression parseExpression(final T defaultValue,
final PJsonObject styleJson,
final String propertyName,
final Function staticParser) {
if (!styleJson.has(propertyName)) {
if (defaultValue == null) {
return null;
}
return this.styleBuilder.literalExpression(defaultValue);
}
String propertyValue = styleJson.getString(propertyName);
if (isExpression(propertyValue)) {
return toExpressionFromCQl(propertyValue);
}
return this.styleBuilder.literalExpression(staticParser.apply(propertyValue));
}
private Expression parseProperty(final String property, final Function literalSupplier) {
if (isExpression(property)) {
return toExpressionFromCQl(property);
} else {
return this.styleBuilder.literalExpression(literalSupplier.apply(property));
}
}
private Expression toExpressionFromCQl(final String property) {
try {
return ECQL.toExpression(property, this.styleBuilder.getFilterFactory());
} catch (CQLException e) {
throw ExceptionUtils.getRuntimeException(e);
}
}
private boolean isExpression(final String property) {
return property != null && property.startsWith("[") && property.endsWith("]");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy