org.mapfish.print.map.image.ImageLayer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of print-lib Show documentation
Show all versions of print-lib Show documentation
Library for generating PDFs and images from online webmapping services
package org.mapfish.print.map.image;
import com.google.common.collect.Maps;
import com.google.common.io.Closer;
import com.vividsolutions.jts.util.Assert;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.GridCoverageLayer;
import org.geotools.map.MapContent;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.styling.Style;
import org.mapfish.print.Constants;
import org.mapfish.print.attribute.map.MapBounds;
import org.mapfish.print.attribute.map.MapfishMapContext;
import org.mapfish.print.config.Configuration;
import org.mapfish.print.config.Template;
import org.mapfish.print.http.MfClientHttpRequestFactory;
import org.mapfish.print.map.AbstractLayerParams;
import org.mapfish.print.map.MapLayerFactoryPlugin;
import org.mapfish.print.map.geotools.AbstractGridCoverageLayerPlugin;
import org.mapfish.print.map.geotools.StyleSupplier;
import org.mapfish.print.map.style.json.ColorParser;
import org.mapfish.print.parser.HasDefaultValue;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import javax.annotation.Nonnull;
import javax.imageio.ImageIO;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE;
/**
* Reads a image file from an URL.
*
* @author MaxComse on 11/08/16.
*/
public final class ImageLayer extends AbstractSingleImageLayer {
private final ImageParam params;
private final StyleSupplier styleSupplier;
private final ExecutorService executorService;
private final Configuration configuration;
/**
* Constructor.
*
* @param executorService the thread pool for doing the rendering.
* @param styleSupplier the style to use when drawing the constructed grid coverage on the map.
* @param params the params from the request data.
* @param configuration the configuration.
*/
protected ImageLayer(
@Nonnull final ExecutorService executorService,
@Nonnull final StyleSupplier styleSupplier,
@Nonnull final ImageParam params,
@Nonnull final Configuration configuration) {
super(executorService, styleSupplier, params);
this.params = params;
this.styleSupplier = styleSupplier;
this.executorService = executorService;
this.configuration = configuration;
}
@Override
protected BufferedImage loadImage(
final MfClientHttpRequestFactory requestFactory,
final MapfishMapContext transformer) throws Throwable {
final ImageParam layerParam = this.params;
final URI commonUri = new URI(layerParam.getBaseUrl());
final Double extentMinX = layerParam.extent[0];
final Double extentMinY = layerParam.extent[1];
final Double extentMaxX = layerParam.extent[2];
final Double extentMaxY = layerParam.extent[3];
final Rectangle paintArea = transformer.getPaintArea();
final ReferencedEnvelope envelope = transformer.getBounds().toReferencedEnvelope(paintArea);
final CoordinateReferenceSystem mapProjection = envelope.getCoordinateReferenceSystem();
final BufferedImage bufferedImage = new BufferedImage(paintArea.width, paintArea.height,
TYPE_INT_ARGB_PRE);
final Graphics2D graphics = bufferedImage.createGraphics();
final MapBounds bounds = transformer.getBounds();
final MapContent content = new MapContent();
try (Closer closer = Closer.create()) {
final ClientHttpRequest request = requestFactory.createRequest(commonUri, HttpMethod.GET);
final ClientHttpResponse httpResponse = closer.register(request.execute());
final BufferedImage image = ImageIO.read(httpResponse.getBody());
if (image == null) {
return createErrorImage(paintArea);
}
GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
GeneralEnvelope gridEnvelope = new GeneralEnvelope(mapProjection);
gridEnvelope.setEnvelope(extentMinX, extentMinY, extentMaxX, extentMaxY);
GridCoverage2D coverage = factory.create(layerParam.getBaseUrl(), image, gridEnvelope,
null, null, null);
Style style = this.styleSupplier.load(requestFactory, coverage);
GridCoverageLayer l = new GridCoverageLayer(coverage, style);
content.addLayers(Collections.singletonList(l));
StreamingRenderer renderer = new StreamingRenderer();
RenderingHints hints = new RenderingHints(Collections.emptyMap());
hints.add(new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY));
hints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON));
hints.add(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY));
hints.add(new RenderingHints(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE));
hints.add(new RenderingHints(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON));
hints.add(new RenderingHints(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC));
hints.add(new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY));
hints.add(new RenderingHints(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE));
hints.add(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
graphics.addRenderingHints(hints);
renderer.setJava2DHints(hints);
Map renderHints = Maps.newHashMap();
if (transformer.isForceLongitudeFirst() != null) {
renderHints.put(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY,
transformer.isForceLongitudeFirst());
}
renderer.setRendererHints(renderHints);
renderer.setMapContent(content);
renderer.setThreadPool(this.executorService);
final ReferencedEnvelope mapArea = bounds.toReferencedEnvelope(paintArea);
renderer.paint(graphics, paintArea, mapArea);
return bufferedImage;
} finally {
graphics.dispose();
content.dispose();
}
}
private BufferedImage createErrorImage(final Rectangle area) {
final BufferedImage bufferedImage = new BufferedImage(area.width, area.height, TYPE_INT_ARGB_PRE);
final Graphics2D graphics = bufferedImage.createGraphics();
try {
graphics.setBackground(ColorParser.toColor(this.configuration.getTransparentTileErrorColor()));
graphics.clearRect(0, 0, area.width, area.height);
return bufferedImage;
} finally {
graphics.dispose();
}
}
@Override
public RenderType getRenderType() {
return RenderType.UNKNOWN;
}
/**
* Renders an image as layer.
* Type: image
*/
public static final class ImageLayerPlugin extends AbstractGridCoverageLayerPlugin
implements MapLayerFactoryPlugin {
private static final String TYPE = "image";
@Autowired
private ForkJoinPool forkJoinPool;
@Override
public Set getTypeNames() {
return Collections.singleton(TYPE);
}
@Override
public ImageParam createParameter() {
return new ImageParam();
}
@Nonnull
@Override
public ImageLayer parse(
@Nonnull final Template template,
@Nonnull final ImageParam layerData) {
String styleRef = layerData.style;
return new ImageLayer(this.forkJoinPool,
super.createStyleSupplier(template, styleRef),
layerData, template.getConfiguration());
}
}
/**
* The parameters for reading an image file, either from the server or from a URL.
*/
public static final class ImageParam extends AbstractLayerParams {
private static final int NUMBER_OF_EXTENT_COORDS = 4;
/**
* The base URL for the image file. Used for making request.
*/
public String baseURL;
/**
* The extent of the image. Used for placing image on map.
*/
public double[] extent;
/**
* The styles to apply to the image.
*/
@HasDefaultValue
public String style = Constants.Style.Raster.NAME;
/**
* Validate the properties have the correct values.
*/
public void postConstruct() {
Assert.equals(NUMBER_OF_EXTENT_COORDS, this.extent.length,
"maxExtent must have exactly 4 elements to the array. Was: " +
Arrays.toString(this.extent));
}
public String getBaseUrl() {
return this.baseURL;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy