The LuciadFusion Platform allows you to customize the legend encoding for the WMS and WMTS services.
By default, the LuciadFusion Platform responds with an icon graphic if it receives a GetLegendGraphic
request from a WMS or WMTS service.
The icon depends on the type of model linked to the server layer: elevation, raster or vector.
For more information about these default implementations, see TLcdDefaultWMSGetLegendGraphicEncoder
for WMS and TLcdDefaultWMTSGetLegendGraphicEncoder
for WMTS.
If you want to offer something other than an icon as a legend, you can customize the response of the LuciadFusion Platform by implementing your own legend encoder.
This only affects WMS and WMTS services. |
Customizing the legend encoding
You can customize the encoding by plugging in your own legend encoder.
To plug in a custom legend decoder, you register it with the service loader using the @LcdService
annotation. You don’t have to specify a priority in the LcdService
. By default, your custom legend encoder already has a higher priority than the pre-configured legend encoder.
For more information about the services mechanism, see Working with the services mechanism.
The sample code includes three examples of custom legend encoders for WMS and WMTS.
Using OGC Symbology Encoding to encode a legend for a raster style with a color map
The first example illustrates the legend encoding of an SLD feature type style with a TLcdSLDRasterSymbolizer
. Figure 1, “Example raster style legend generated by the Custom WMTS legend encoder” shows you a possible result.
package samples.wms.server;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Optional;
import javax.imageio.ImageIO;
import com.luciad.util.service.LcdService;
import com.luciad.model.ILcdModel;
import com.luciad.ogc.sld.model.TLcdSLDColorMap;
import com.luciad.wms.server.ILcdWMSGetLegendGraphicRequestEncoder;
import com.luciad.wms.server.TLcdWMSGetLegendGraphicRequestContext;
import com.luciad.wms.server.TLcdWMSRequestContext;
/**
* This WMS legend encoder creates a legend based upon the SLD color map if one is part of the SLD Feature Type Style.
*/
@LcdService(service = ILcdWMSGetLegendGraphicRequestEncoder.class)
public class SLDRasterWMSGetLegendGraphicEncoder implements ILcdWMSGetLegendGraphicRequestEncoder {
private final SLDColorMapLegendProvider fSLDColorMapLegendProvider = new SLDColorMapLegendProvider();
@Override
public String getContentType() {
return "image/png";
}
@Override
public boolean encode(TLcdWMSGetLegendGraphicRequestContext aWMSGetLegendGraphicRequestContext,
TLcdWMSRequestContext aWMSRequestContext, OutputStream aOutputStream) throws IOException {
if (aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles() == null ||
aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles().length != 1) {
return false;
}
Optional<TLcdSLDColorMap> colorMap =
fSLDColorMapLegendProvider.getColorMap(aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles()[0]);
if (!colorMap.isPresent()) {
return false;
}
ILcdModel model = aWMSGetLegendGraphicRequestContext.getModelSupplier().get().length > 0 ?
aWMSGetLegendGraphicRequestContext.getModelSupplier().get()[0] : null;
ImageIO.write(fSLDColorMapLegendProvider.getLegend(colorMap.get(), model), "PNG", aOutputStream);
return true;
}
}
package samples.wmts.server;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Optional;
import javax.imageio.ImageIO;
import samples.wms.server.SLDColorMapLegendProvider;
import com.luciad.util.service.LcdService;
import com.luciad.model.ILcdModel;
import com.luciad.ogc.sld.model.TLcdSLDColorMap;
import com.luciad.wmts.server.ILcdWMTSGetLegendGraphicRequestEncoder;
import com.luciad.wmts.server.TLcdWMTSGetLegendGraphicRequestContext;
/**
* This WMTS legend encoder creates a legend based upon the SLD color map if one is part of the SLD Feature Type Style.
*/
@LcdService(service = ILcdWMTSGetLegendGraphicRequestEncoder.class)
public class SLDRasterWMTSGetLegendGraphicEncoder implements ILcdWMTSGetLegendGraphicRequestEncoder {
private final SLDColorMapLegendProvider fSLDColorMapLegendProvider = new SLDColorMapLegendProvider();
@Override
public String getContentType() {
return "image/png";
}
@Override
public boolean encode(TLcdWMTSGetLegendGraphicRequestContext aWMTSGetLegendGraphicRequestContext,
OutputStream aOutputStream) throws IOException {
if (aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles() == null ||
aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles().length != 1) {
return false;
}
Optional<TLcdSLDColorMap> colorMap =
fSLDColorMapLegendProvider.getColorMap(aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles()[0]);
if (!colorMap.isPresent()) {
return false;
}
ILcdModel model = aWMTSGetLegendGraphicRequestContext.getModelSupplier().get();
ImageIO.write(fSLDColorMapLegendProvider.getLegend(colorMap.get(), model), "PNG", aOutputStream);
return true;
}
}
For a closer look at this legend code, see the implementations samples.wms.server.SLDRasterWMSGetLegendGraphicEncoder
for WMS and samples.wmts.server.SLDRasterWMTSGetLegendGraphicEncoder
for WMTS.
Using OGC Symbology Encoding to encode a legend for a vector style
The second example illustrates the legend encoding of a vector SLD feature type style, containing one or more TLcdSLDPointSymbolizer
, TLcdSLDLineSymbolizer
and/or TLcdSLDPolygonSymbolizer
elements.
Figure 2, “Example vector style legend generated by the Custom WMTS legend encoder” shows you a possible result.
package samples.wms.server;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.luciad.util.service.LcdService;
import com.luciad.wms.server.ILcdWMSGetLegendGraphicRequestEncoder;
import com.luciad.wms.server.TLcdWMSGetLegendGraphicRequestContext;
import com.luciad.wms.server.TLcdWMSRequestContext;
/**
* This WMS legend encoder creates a legend based upon the SLD vector symbolizers (point, line, polygon) if
* they are part of the SLD feature type style.
*/
@LcdService(service = ILcdWMSGetLegendGraphicRequestEncoder.class)
public class SLDVectorWMSGetLegendGraphicEncoder implements ILcdWMSGetLegendGraphicRequestEncoder {
private final SLDVectorLegendProvider fSLDVectorLegendProvider = new SLDVectorLegendProvider();
@Override
public String getContentType() {
return "image/png";
}
@Override
public boolean encode(TLcdWMSGetLegendGraphicRequestContext aWMSGetLegendGraphicRequestContext,
TLcdWMSRequestContext aWMSRequestContext, OutputStream aOutputStream) throws IOException {
if (aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles() == null ||
aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles().length != 1) {
return false;
}
if (!fSLDVectorLegendProvider.hasVectorSymbolizer(aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles()[0])) {
return false;
}
ImageIO.write(fSLDVectorLegendProvider.getLegend(aWMSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles()[0]), "PNG", aOutputStream);
return true;
}
}
package samples.wmts.server;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import samples.wms.server.SLDVectorLegendProvider;
import com.luciad.util.service.LcdService;
import com.luciad.wmts.server.ILcdWMTSGetLegendGraphicRequestEncoder;
import com.luciad.wmts.server.TLcdWMTSGetLegendGraphicRequestContext;
/**
* This WMTS legend encoder creates a legend based upon the SLD vector symbolizers (point, line, polygon) if
* they are part of the SLD feature type style.
*/
@LcdService(service = ILcdWMTSGetLegendGraphicRequestEncoder.class)
public class SLDVectorWMTSGetLegendGraphicEncoder implements ILcdWMTSGetLegendGraphicRequestEncoder {
private final SLDVectorLegendProvider fSLDVectorLegendProvider = new SLDVectorLegendProvider();
@Override
public String getContentType() {
return "image/png";
}
@Override
public boolean encode(TLcdWMTSGetLegendGraphicRequestContext aWMTSGetLegendGraphicRequestContext, OutputStream aOutputStream) throws IOException {
if (aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles() == null ||
aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles().length != 1) {
return false;
}
if (!fSLDVectorLegendProvider.hasVectorSymbolizer(aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles()[0])) {
return false;
}
ImageIO.write(fSLDVectorLegendProvider.getLegend(aWMTSGetLegendGraphicRequestContext.getSLDFeatureTypeStyles()[0]), "PNG", aOutputStream);
return true;
}
}
For a closer look at this legend code, see the implementations samples.wms.server.SLDVectorWMSGetLegendGraphicEncoder
for WMS and samples.wmts.server.SLDVectorWMTSGetLegendGraphicEncoder
for WMTS.
Using a static image file to encode a legend
This encoder looks for a static legend image that is placed next to the original model source. With this encoder, you can author an appropriate legend image yourself from scratch, or re-use existing legend images.
package samples.wms.server;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import com.luciad.model.ILcdModel;
import com.luciad.model.ILcdModelTreeNode;
import com.luciad.util.service.LcdService;
import com.luciad.wms.server.ILcdWMSGetLegendGraphicRequestEncoder;
import com.luciad.wms.server.TLcdWMSGetLegendGraphicRequestContext;
import com.luciad.wms.server.TLcdWMSRequestContext;
/**
* This legend encoder picks up a {@code .legend.png} image that's in the same directory as the original data source.
* For example, if the original data source is {@code C:\Data\SHP\world.shp}, the encoder looks for
* {@code C:\Data\SHP\world.legend.png}.
*/
@LcdService(service = ILcdWMSGetLegendGraphicRequestEncoder.class)
public class FileBasedWMSGetLegendGraphicRequestEncoder implements ILcdWMSGetLegendGraphicRequestEncoder {
@Override
public String getContentType() {
return "image/png";
}
@Override
public boolean encode(TLcdWMSGetLegendGraphicRequestContext aWMSGetLegendGraphicRequestContext, TLcdWMSRequestContext aWMSRequestContext, OutputStream aOutputStream) throws IOException {
ILcdModel[] models = aWMSGetLegendGraphicRequestContext.getModelSupplier().get();
for (ILcdModel model : models) {
if (encode(aOutputStream, model)) {
return true;
}
}
return false;
}
public static boolean encode(OutputStream aOutputStream, ILcdModel aModel) throws IOException {
String dataSource = aModel.getModelDescriptor().getSourceName();
String legendSource = getFileNameNoExtension(dataSource) + ".legend.png";
if (Files.exists(Paths.get(legendSource))) {
Files.copy(Paths.get(legendSource), aOutputStream);
return true;
} else if (aModel instanceof ILcdModelTreeNode) {
for (ILcdModel child : ((ILcdModelTreeNode) aModel).getModels()) {
if (encode(aOutputStream, child)) {
return true;
}
}
}
return false;
}
private static String getFileNameNoExtension(String aFileName) {
String fileName = null;
int pointIndex = aFileName.lastIndexOf('.');
if (pointIndex > 0 && pointIndex < aFileName.length() - 1) {
fileName = aFileName.substring(0, pointIndex);
}
return fileName;
}
}
package samples.wmts.server;
import java.io.IOException;
import java.io.OutputStream;
import com.luciad.model.ILcdModel;
import com.luciad.util.service.LcdService;
import com.luciad.wmts.server.ILcdWMTSGetLegendGraphicRequestEncoder;
import com.luciad.wmts.server.TLcdWMTSGetLegendGraphicRequestContext;
import samples.wms.server.FileBasedWMSGetLegendGraphicRequestEncoder;
/**
* This legend encoder picks up a {@code .legend.png} image that's in the same directory as the original data source.
* For example, if the original data source would be {@code C:\Data\SHP\world.shp}, the encoder would look for
* {@code C:\Data\SHP\world.legend.png}.
*/
@LcdService(service = ILcdWMTSGetLegendGraphicRequestEncoder.class)
public class FileBasedWMTSGetLegendGraphicRequestEncoder implements ILcdWMTSGetLegendGraphicRequestEncoder {
@Override
public String getContentType() {
return "image/png";
}
@Override
public boolean encode(TLcdWMTSGetLegendGraphicRequestContext aWMTSGetLegendGraphicRequestContext, OutputStream aOutputStream) throws IOException {
ILcdModel model = aWMTSGetLegendGraphicRequestContext.getModelSupplier().get();
return FileBasedWMSGetLegendGraphicRequestEncoder.encode(aOutputStream, model);
}
}
See the implementations samples.wms.server.FileBasedWMSGetLegendGraphicRequestEncoder
for WMS and samples.wmts.server.FileBasedWMTSGetLegendGraphicRequestEncoder
for WMTS.