diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index ce26c053bf..6bf65925da 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -3,6 +3,7 @@ name: Continuous integration on: push: + pull_request: jobs: build: diff --git a/core/src/main/java/org/mapfish/print/map/tiled/CoverageTask.java b/core/src/main/java/org/mapfish/print/map/tiled/CoverageTask.java index af8c3a0505..1650b89fb6 100644 --- a/core/src/main/java/org/mapfish/print/map/tiled/CoverageTask.java +++ b/core/src/main/java/org/mapfish/print/map/tiled/CoverageTask.java @@ -100,7 +100,25 @@ public GridCoverage2D call() { } Tile tile = task.call(); if (tile.getImage() != null) { - graphics.drawImage(tile.getImage(), + // crop the image here + BufferedImage noBufferTileImage; + if (this.tiledLayer.getTileBufferWidth() > 0 || + this.tiledLayer.getTileBufferHeight() > 0) { + int noBufferWidth = Math.min( + this.tiledLayer.getTileSize().width, + tile.getImage().getWidth() - this.tiledLayer.getTileBufferWidth()); + int noBufferHeight = Math.min( + this.tiledLayer.getTileSize().height, + tile.getImage().getHeight() - this.tiledLayer.getTileBufferHeight()); + noBufferTileImage = tile.getImage().getSubimage( + this.tiledLayer.getTileBufferWidth(), + this.tiledLayer.getTileBufferHeight(), + noBufferWidth, + noBufferHeight); + } else { + noBufferTileImage = tile.getImage(); + } + graphics.drawImage(noBufferTileImage, tile.getxIndex() * this.tiledLayer.getTileSize().width, tile.getyIndex() * this.tiledLayer.getTileSize().height, null); } diff --git a/core/src/main/java/org/mapfish/print/map/tiled/TileCacheInformation.java b/core/src/main/java/org/mapfish/print/map/tiled/TileCacheInformation.java index ab321e467c..bc55685c64 100644 --- a/core/src/main/java/org/mapfish/print/map/tiled/TileCacheInformation.java +++ b/core/src/main/java/org/mapfish/print/map/tiled/TileCacheInformation.java @@ -94,6 +94,19 @@ public abstract ClientHttpRequest getTileRequest( * Obtain the image tile size of the tiles that will be loaded from the server. */ public abstract Dimension getTileSize(); + + /** + * Obtain the buffer width for meta tiling. + */ + public int getTileBufferWidth() { + return 0; + } + /** + * Obtain the buffer height for meta tiling. + */ + public int getTileBufferHeight() { + return 0; + } /** * Return the full bounds of the tileCache. diff --git a/core/src/main/java/org/mapfish/print/map/tiled/TilePreparationTask.java b/core/src/main/java/org/mapfish/print/map/tiled/TilePreparationTask.java index 1a49963431..27b10c6853 100644 --- a/core/src/main/java/org/mapfish/print/map/tiled/TilePreparationTask.java +++ b/core/src/main/java/org/mapfish/print/map/tiled/TilePreparationTask.java @@ -79,10 +79,19 @@ public TilePreparationInfo call() { final ReferencedEnvelope mapGeoBounds = this.bounds.toReferencedEnvelope(this.paintArea); final CoordinateReferenceSystem mapProjection = mapGeoBounds.getCoordinateReferenceSystem(); Dimension tileSizeOnScreen = this.tiledLayer.getTileSize(); + int tileBufferWidth = this.tiledLayer.getTileBufferWidth(); + int tileBufferHeight = this.tiledLayer.getTileBufferHeight(); + + Dimension tileSizeOnScreenWithBuffer = new Dimension( + tileSizeOnScreen.width + 2 * tileBufferWidth, + tileSizeOnScreen.height + 2 * tileBufferHeight); final double resolution = this.tiledLayer.getResolution(); - Coordinate tileSizeInWorld = new Coordinate(tileSizeOnScreen.width * resolution, - tileSizeOnScreen.height * resolution); + Coordinate tileSizeInWorld = new Coordinate( + tileSizeOnScreen.width * resolution, + tileSizeOnScreen.height * resolution); + Coordinate bufferSizeInWorld = new Coordinate( + tileBufferWidth * resolution, tileBufferHeight * resolution); // The minX minY of the first (minY, minY) tile Coordinate gridCoverageOrigin = @@ -122,6 +131,13 @@ public TilePreparationInfo call() { ReferencedEnvelope tileBounds = new ReferencedEnvelope( geoX, gridCoverageMaxX, geoY, gridCoverageMaxY, mapProjection); + ReferencedEnvelope tileBoundsWithBuffer = new ReferencedEnvelope( + geoX - bufferSizeInWorld.x, + gridCoverageMaxX + bufferSizeInWorld.x, + geoY - bufferSizeInWorld.y, + gridCoverageMaxY + bufferSizeInWorld.y, + mapProjection); + int row = (int) Math.round((tileCacheBounds.getMaxY() - tileBounds.getMaxY()) * rowFactor); int column = (int) Math.round((tileBounds.getMinX() - @@ -129,8 +145,8 @@ public TilePreparationInfo call() { ClientHttpRequest tileRequest = this.tiledLayer.getTileRequest(this.httpRequestFactory, - commonUrl, tileBounds, - tileSizeOnScreen, column, + commonUrl, tileBoundsWithBuffer, + tileSizeOnScreenWithBuffer, column, row); if (isInTileCacheBounds(tileCacheBounds, tileBounds)) { if (isTileVisible(tileBounds)) { diff --git a/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayer.java b/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayer.java index 5fc3178059..0eec5317ba 100644 --- a/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayer.java +++ b/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayer.java @@ -56,10 +56,14 @@ public TiledWmsLayer( * * @param wmsLayer The source layer * @param tileSize The size of the tiles + * @param tileBufferWidth The width of the the buffer tile for meta tile + * @param tileBufferHeight The height of the the buffer tile for meta tile */ - public TiledWmsLayer(final WmsLayer wmsLayer, final Dimension tileSize) { + public TiledWmsLayer(final WmsLayer wmsLayer, final Dimension tileSize, final int tileBufferWidth, + final int tileBufferHeight) { super(wmsLayer, wmsLayer.getStyleSupplier(), wmsLayer.getRegistry(), wmsLayer.getConfiguration()); - this.param = new TiledWmsLayerParam(wmsLayer.getParams(), tileSize); + this.param = new TiledWmsLayerParam( + wmsLayer.getParams(), tileSize, tileBufferWidth, tileBufferHeight); } /** @@ -161,6 +165,16 @@ public Dimension getTileSize() { return TiledWmsLayer.this.param.getTileSize(); } + @Override + public int getTileBufferHeight() { + return TiledWmsLayer.this.param.getTileBufferHeight(); + } + + @Override + public int getTileBufferWidth() { + return TiledWmsLayer.this.param.getTileBufferWidth(); + } + @Nonnull @Override protected ReferencedEnvelope getTileCacheBounds() { diff --git a/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayerParam.java b/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayerParam.java index 14296b827e..eaa9438550 100644 --- a/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayerParam.java +++ b/core/src/main/java/org/mapfish/print/map/tiled/wms/TiledWmsLayerParam.java @@ -1,7 +1,9 @@ package org.mapfish.print.map.tiled.wms; import org.locationtech.jts.util.Assert; + import org.mapfish.print.map.image.wms.WmsLayerParam; +import org.mapfish.print.parser.HasDefaultValue; import java.awt.Dimension; import java.net.URISyntaxException; @@ -19,6 +21,12 @@ public final class TiledWmsLayerParam extends WmsLayerParam { */ public int[] tileSize; + /** + * A two element array of integers indicating the width and height tile buffer. + */ + @HasDefaultValue + public int[] tileBufferSize = new int[] {0, 0}; + /** * Constructor. */ @@ -31,10 +39,14 @@ public TiledWmsLayerParam() { * * @param params the WMS parameters to convert * @param tileSize The size of the tiles + * @param tileBufferWidth The width of the the buffer tile for meta tile + * @param tileBufferHeight The height of the the buffer tile for meta tile */ - public TiledWmsLayerParam(final WmsLayerParam params, final Dimension tileSize) { + public TiledWmsLayerParam(final WmsLayerParam params, final Dimension tileSize, + final int tileBufferWidth, final int tileBufferHeight) { super(params); this.tileSize = new int[]{tileSize.width, tileSize.height}; + this.tileBufferSize = new int[]{tileBufferWidth, tileBufferHeight}; } @Override @@ -49,4 +61,12 @@ public Dimension getTileSize() { return new Dimension(this.tileSize[0], this.tileSize[1]); } + public int getTileBufferWidth() { + return this.tileBufferSize[0]; + } + + public int getTileBufferHeight() { + return this.tileBufferSize[1]; + } + } diff --git a/core/src/main/java/org/mapfish/print/processor/map/SetTiledWmsProcessor.java b/core/src/main/java/org/mapfish/print/processor/map/SetTiledWmsProcessor.java index 102a88f47b..fc2457a718 100644 --- a/core/src/main/java/org/mapfish/print/processor/map/SetTiledWmsProcessor.java +++ b/core/src/main/java/org/mapfish/print/processor/map/SetTiledWmsProcessor.java @@ -103,7 +103,13 @@ public final Void execute(final Input values, final ExecutionContext context) th String.join(", ", wmsLayer.getParams().layers), tileSize.width, tileSize.height); } - values.map.replaceLayer(i, new TiledWmsLayer(wmsLayer, tileSize)); + // Notes(IS): Honestly I have no idea where should I put these buffer size. + // It is needed for TiledWmsLayer (so that the values are accessible) + final int tileBufferWidth = 0; + final int tileBufferHeight = 0; + + values.map.replaceLayer(i, new TiledWmsLayer( + wmsLayer, tileSize, tileBufferWidth, tileBufferHeight)); } } } diff --git a/examples/src/test/resources/examples/printtiledwms/expected_output/requestData-bbox-meta-tiled-wms1_1_1.png b/examples/src/test/resources/examples/printtiledwms/expected_output/requestData-bbox-meta-tiled-wms1_1_1.png new file mode 100644 index 0000000000..9b9285e49a Binary files /dev/null and b/examples/src/test/resources/examples/printtiledwms/expected_output/requestData-bbox-meta-tiled-wms1_1_1.png differ diff --git a/examples/src/test/resources/examples/printtiledwms/requestData-bbox-meta-tiled-wms1_1_1.json b/examples/src/test/resources/examples/printtiledwms/requestData-bbox-meta-tiled-wms1_1_1.json new file mode 100644 index 0000000000..3adf578ce3 --- /dev/null +++ b/examples/src/test/resources/examples/printtiledwms/requestData-bbox-meta-tiled-wms1_1_1.json @@ -0,0 +1,40 @@ +{ + "layout": "A4 landscape", + "outputFormat": "pdf", + "attributes": { + "map": { + "projection": "EPSG:4326", + "dpi": 72, + "rotation": 0, + "bbox": [ + -130, + 20, + -60, + 50 + ], + "longitudeFirst": true, + "layers": [ + { + "type": "tiledwms", + "layers": [ + "topp:states" + ], + "baseURL": "http://geoserver:8080/wms", + "imageFormat": "image/png", + "version": "1.1.1", + "customParams": { + "TRANSPARENT": "true" + }, + "tileSize": [ + 256, + 256 + ], + "tileBufferSize": [ + 60, + 60 + ] + } + ] + } + } +}