📄 defaultrasterlegendproducer.java
字号:
* @param g - the Graphics2D that will be used to render this label
* @return a {@link BufferedImage} of the properly rendered label.
*/
public static BufferedImage renderLabel(String label, Graphics2D g, GetLegendGraphicRequest req) {
// We'll accept '/n' as a text string
//to indicate a line break, as well as a traditional 'real' line-break in the XML.
BufferedImage renderedLabel;
Color labelColor = getLabelFontColor(req);
if ((label.indexOf("\n") != -1) || (label.indexOf("\\n") != -1)) {
//this is a label WITH line-breaks...we need to figure out it's height *and*
//width, and then adjust the legend size accordingly
Rectangle2D bounds = new Rectangle2D.Double(0, 0, 0, 0);
ArrayList lineHeight = new ArrayList();
// four backslashes... "\\" -> '\', so "\\\\n" -> '\' + '\' + 'n'
final String realLabel = label.replaceAll("\\\\n", "\n");
StringTokenizer st = new StringTokenizer(realLabel, "\n\r\f");
while (st.hasMoreElements()) {
final String token = st.nextToken();
Rectangle2D thisLineBounds = g.getFontMetrics().getStringBounds(token, g);
//if this is directly added as thisLineBounds.getHeight(), then there are rounding errors
//because we can only DRAW fonts at discrete integer coords.
final int thisLineHeight = (int) Math.ceil(thisLineBounds.getHeight());
bounds.add(0, thisLineHeight + bounds.getHeight());
bounds.add(thisLineBounds.getWidth(), 0);
lineHeight.add(new Integer((int) Math.ceil(thisLineBounds.getHeight())));
}
//make the actual label image
renderedLabel = new BufferedImage((int) Math.ceil(bounds.getWidth()),
(int) Math.ceil(bounds.getHeight()), BufferedImage.TYPE_INT_ARGB);
st = new StringTokenizer(realLabel, "\n\r\f");
Graphics2D rlg = renderedLabel.createGraphics();
rlg.setColor(labelColor);
rlg.setFont(g.getFont());
rlg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
g.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING));
int y = 0 - g.getFontMetrics().getDescent();
int c = 0;
while (st.hasMoreElements()) {
y += ((Integer) lineHeight.get(c++)).intValue();
rlg.drawString(st.nextToken(), 0, y);
}
} else {
//this is a traditional 'regular-old' label. Just figure the
//size and act accordingly.
int height = (int) Math.ceil(g.getFontMetrics().getStringBounds(label, g).getHeight());
int width = (int) Math.ceil(g.getFontMetrics().getStringBounds(label, g).getWidth());
renderedLabel = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D rlg = renderedLabel.createGraphics();
rlg.setColor(labelColor);
rlg.setFont(g.getFont());
rlg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
g.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING));
rlg.drawString(label, 0, height - rlg.getFontMetrics().getDescent());
}
return renderedLabel;
}
/**
* Returns a <code>java.awt.Shape</code> appropiate to render a legend
* graphic given the symbolizer type and the legend dimensions.
*
* @param symbolizer the Symbolizer for whose type a sample shape will be
* created
* @param legendWidth the requested width, in output units, of the legend
* graphic
* @param legendHeight the requested height, in output units, of the legend
* graphic
*
* @return an appropiate Line2D, Rectangle2D or LiteShape(Point) for the
* symbolizer, wether it is a LineSymbolizer, a PolygonSymbolizer,
* or a Point ot Text Symbolizer
*
* @throws IllegalArgumentException if an unknown symbolizer impl was
* passed in.
*/
private LiteShape2 getSampleShape(Symbolizer symbolizer, int legendWidth, int legendHeight) {
LiteShape2 sampleShape;
final float hpad = (legendWidth * hpaddingFactor);
final float vpad = (legendHeight * vpaddingFactor);
if (symbolizer instanceof LineSymbolizer) {
if (this.sampleLine == null) {
Coordinate[] coords = {
new Coordinate(hpad, legendHeight - vpad),
new Coordinate(legendWidth - hpad, vpad)
};
LineString geom = geomFac.createLineString(coords);
try {
this.sampleLine = new LiteShape2(geom, null, null, false);
} catch (Exception e) {
this.sampleLine = null;
}
}
sampleShape = this.sampleLine;
} else if ((symbolizer instanceof PolygonSymbolizer)
|| (symbolizer instanceof RasterSymbolizer)) {
if (this.sampleRect == null) {
final float w = legendWidth - (2 * hpad);
final float h = legendHeight - (2 * vpad);
Coordinate[] coords = {
new Coordinate(hpad, vpad), new Coordinate(hpad, vpad + h),
new Coordinate(hpad + w, vpad + h), new Coordinate(hpad + w, vpad),
new Coordinate(hpad, vpad)
};
LinearRing shell = geomFac.createLinearRing(coords);
Polygon geom = geomFac.createPolygon(shell, null);
try {
this.sampleRect = new LiteShape2(geom, null, null, false);
} catch (Exception e) {
this.sampleRect = null;
}
}
sampleShape = this.sampleRect;
} else if (symbolizer instanceof PointSymbolizer || symbolizer instanceof TextSymbolizer) {
if (this.samplePoint == null) {
Coordinate coord = new Coordinate(legendWidth / 2, legendHeight / 2);
try {
this.samplePoint = new LiteShape2(geomFac.createPoint(coord), null, null, false);
} catch (Exception e) {
this.samplePoint = null;
}
}
sampleShape = this.samplePoint;
} else {
throw new IllegalArgumentException("Unknown symbolizer: " + symbolizer);
}
return sampleShape;
}
/**
* Creates a sample Feature instance in the hope that it can be used in the
* rendering of the legend graphic.
*
* @param schema the schema for which to create a sample Feature instance
*
* @return
*
* @throws WmsException
*/
private Feature createSampleFeature(FeatureType schema)
throws WmsException {
Feature sampleFeature;
try {
AttributeType[] atts = schema.getAttributeTypes();
Object[] attributes = new Object[atts.length];
for (int i = 0; i < atts.length; i++)
attributes[i] = atts[i].createDefaultValue();
sampleFeature = schema.create(attributes);
} catch (IllegalAttributeException e) {
e.printStackTrace();
throw new WmsException(e);
}
return sampleFeature;
}
/**
* Finds the applicable Rules for the given scale denominator.
*
* @param ftStyles
* @param scaleDenominator
*
* @return
*/
private Rule[] getApplicableRules(FeatureTypeStyle[] ftStyles, double scaleDenominator) {
/**
* Holds both the rules that apply and the ElseRule's if any, in the
* order they appear
*/
final List ruleList = new ArrayList();
// get applicable rules at the current scale
for (int i = 0; i < ftStyles.length; i++) {
FeatureTypeStyle fts = ftStyles[i];
Rule[] rules = fts.getRules();
for (int j = 0; j < rules.length; j++) {
Rule r = rules[j];
if (isWithInScale(r, scaleDenominator)) {
ruleList.add(r);
/*
* I'm commented this out since I guess it has no sense
* for producing the legend, since wether or not the rule
* has an else filter, the legend is drawn only if the
* scale denominator lies inside the rule's scale range.
if (r.hasElseFilter()) {
ruleList.add(r);
}
*/
}
}
}
return (Rule[]) ruleList.toArray(new Rule[ruleList.size()]);
}
/**
* Checks if a rule can be triggered at the current scale level
*
* @param r The rule
* @param scaleDenominator the scale denominator to check if it is between
* the rule's scale range. -1 means that it allways is.
*
* @return true if the scale is compatible with the rule settings
*/
private boolean isWithInScale(Rule r, double scaleDenominator) {
return (scaleDenominator == -1)
|| (((r.getMinScaleDenominator() - TOLERANCE) <= scaleDenominator)
&& ((r.getMaxScaleDenominator() + TOLERANCE) > scaleDenominator));
}
/**
* DOCUMENT ME!
*
* @return
*
* @throws IllegalStateException DOCUMENT ME!
*/
public BufferedImage getLegendGraphic() {
if (this.legendGraphic == null) {
throw new IllegalStateException();
}
return this.legendGraphic;
}
/**
* Asks the rendering to stop processing.
*/
public void abort() {
this.renderingStopRequested = true;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -