Serve raster tiles in GeoServer and renderer them by Leaflet

GeoServer is an open source server for sharing geospatial data. Designed for interoperability, it publishes data from any major spatial data source using open standards.

Steps to handle raster data

Download

Download GeoServer and install, or create by a docker container

Login

Login the GeoServer by admin user, the default username/password is admin/geoserver.

Image for post
Image for post

Create a raster workspace

Image for post
Image for post

Select a store datasource

Here we select GeoTIFF

Image for post
Image for post

Create a raster store

Here we specify a *.tif file

Image for post
Image for post

Create a layer

Create the layer under new created store and the format is :, and then publish it

Image for post
Image for post

Publish review

Have a review of all the information it reads including the band definitions, and save it

Image for post
Image for post

Layer preview

Go the the layer preview and find the layer, and try to view it by OpenLayers

Image for post
Image for post

Layer preview result

The geotiff file successfully being processed if we can see the layer

Compressed raster layer with only grey band

The geotiff file failed being processed for unknown reason

Image for post
Image for post

Exception stack trace

Caused by: java.lang.NullPointerException
at javax.media.jai.PlanarImage.getData(PlanarImage.java:2110)
......

Please view the full exception stack on the bottom of the page.

QGIS layer preview

Drag the geotiff file into the QGIS for preview

Image for post
Image for post

QGIS geotiff layer export

Display the current layer, Select the menu item “Layer-Save as…” and export the geotiff with 4326 crs

Image for post
Image for post

GeoServer layer preview

Modify the store in GeoServer to connect to the new geotiff file, and preview the layer again. It works with no color scheme

Image for post
Image for post

Cause analysis

The error raster geotiff only has one grey band, and the QGIS exported geotiff file is nearly twice the size of the original one. It is a compressed one, and that’s why QGIS produces a bigger size when we save it as another. QGIS does not compress it, hence the new image is bigger. GeoServer doesn’t accept compressed geotiff data. Regarding the GeoServer color problem, It’s because that the style in GeoServer is not well defined.

Define style in GeoServer

Create style in QGIS

  1. Open QGIS, drag the geotiff file into the QGIS.
  2. Right click on the data layer and select ‘Properties’, then select ‘Style’ on the left side.
  3. Change the render type to ‘Singleband pseudocolor’ and change the style by specifying the color ranges.
Image for post
Image for post

Export style in QGIS

Apply the change to see the new layer. Save the style using the ‘Save Style’ button on the bottom and save as .qml file.

Image for post
Image for post

Copy the .qml content

Open the .qml file with notepad and review the colorrampshader part.

Image for post
Image for post

Generate the style template in GeoServer

  1. Go to the GeoServer admin page and click on ‘Styles’ and add a new style.
  2. Name the style and select the workspace, then choose ‘Copy from existing style’, select ‘dem’ and press ‘copy…’

Specify the style content

  1. Change the name, title and abstract.
  2. Translate the .qml content into the GeoServer style content here. Notice the ‘value’/’label’/’color’ values in .qml match the ‘quantity’/’label’/’color’ in GeoServer. If the opacity is 0.0, it means that the color will not be visible, so it will be white.
  3. Press ‘Validate’ to check if it works. If there are no errors, then ‘submit’.
Image for post
Image for post

Generate .sld in QGIS

Comparing with exporting the .qml style in QGIS, we can directly generate .sld in QGIS and copy the content to create a style in GeoServer.

Image for post
Image for post

Edit layer basic info

Go to ‘Layers’ and select the layer we just created. Make sure ‘Enabled’ and ‘Advertised’ are turned on and check if the ‘Coverage Band Details’ are set correctly, if not adjust them.

Image for post
Image for post

Edit WMS Settings

Select the ‘Publishing’ tab. With the ‘WMS Settings’ select ‘Default Style’ and change it to the style we just created. ‘Save’ the layer again.

Image for post
Image for post

Preview layer

View the layer again with the ‘Layer preview’ and ‘Open Layers’. Now the layer should be displayed correctly.

Image for post
Image for post

Preview layer when editing style

We could also edit the style and preview the result as soon as we apply in the style editing page.

Image for post
Image for post

Add additional styles

Edit the layer again and with the ‘WMS Settings’ select additional styles and save. Remember to add the newly added style into it as well otherwise the restful api cannot list this style info under the layer.

Image for post
Image for post

Preview layer with additional styles

Preview the layer again and we could switch the style to any available one and see the result.

Image for post
Image for post

Enable CORS for GeoServer

Clone repository

Clone the github repository docker-geoserver.

Create web.xml

The contents of resources/overlays will be copied to the image file system during the build. For example, to include a static web xml with CORS support web.xml, create the file at resources/overlays/usr/local/tomcat/conf/web.xml.

Enable CORS

Add CORS enabled content into the web.xml as bellow. The full content of the web.xml can be found here.

<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Docker hub modification

Modify the build.sh script to own hub repository.

Image for post
Image for post

Build and push

Build the docker image and push to own docker hub. Now the CORS enabled GeoServer docker image is ready to use.

./build.sh
docker pull hustakin/geoserver

Tomcat error log

Sometimes the GeoServer container will met 404 issue. That’s because the tomcat failed to start because of your modification. We could attach to the GeoServer container and inspect the tomcat error log to find the reason.

Image for post
Image for post

Client http

Please be noted the client HTTP should not use the credentials for CORS requests. For example, here I get feature information for raster data in angular6 client by clicking on the layer.

Image for post
Image for post

Renderer the raster layer in the web

Leaflet layer using WMS

let wmsLayer = L.tileLayer.wms('http://localhost:9999/geoserver/raster/wms?', {
layers: 'raster:demo',
version: '1.1.1',
styles: '', //Use the default style, we can also specify additional styles
format: 'image/png',
transparent: true,
maxZoom: 25,
tiled: true
});
let map = L.map('map', {
zoom: 0,
maxZoom: 25,
maxNativeZoom: 18,
layers: [wmsLayer],
});
Image for post
Image for post

Leaflet layer using WMTS

Please be noted that we should use EPSG:900913 other than EPSG:4326 here which for historical reasons is what GeoServer calls Web Mercator.

let wmtsLayer = new L.TileLayer.WMTS('http://localhost:9999/geoserver/gwc/service/wmts', {
layer: 'raster:demo',
style: "",
tilematrixSet: "EPSG:900913", //Important!! It should be EPSG:900913 other than EPSG:4326
format: "image/png",
maxZoom: 25,
attribution: "<a href='https://github.com/mylen/leaflet.TileLayer.WMTS'>GitHub</a>&copy; <a href='http://www.ign.fr'>IGN</a>"
});
let map = L.map('map', {
zoom: 0,
maxZoom: 25,
maxNativeZoom: 18,
layers: [wmtsLayer],
});
Image for post
Image for post

OpenLayers layer using WMTS

let gridNames = ['EPSG:4326:0', 'EPSG:4326:1', 'EPSG:4326:2', 'EPSG:4326:3', 'EPSG:4326:4', 'EPSG:4326:5', 'EPSG:4326:6', 'EPSG:4326:7', 'EPSG:4326:8', 'EPSG:4326:9', 'EPSG:4326:10', 'EPSG:4326:11', 'EPSG:4326:12', 'EPSG:4326:13', 'EPSG:4326:14', 'EPSG:4326:15', 'EPSG:4326:16', 'EPSG:4326:17', 'EPSG:4326:18', 'EPSG:4326:19', 'EPSG:4326:20', 'EPSG:4326:21'];
let baseParams = ['VERSION', 'LAYER', 'STYLE', 'TILEMATRIX', 'TILEMATRIXSET', 'SERVICE', 'FORMAT'];
let params = {
VERSION: '1.0.0',
LAYER: 'raster:demo',
STYLE: '', //Use the default style, we can also specify additional styles
TILEMATRIX: gridNames,
TILEMATRIXSET: 'EPSG:4326',
SERVICE: 'WMTS',
FORMAT: 'image/png'
};
let projection = new Projection({
code: 'EPSG:4326',
units: 'degrees',
axisOrientation: 'neu'
});,
let resolutions = [0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625, 0.010986328125, 0.0054931640625, 0.00274658203125, 0.001373291015625, 6.866455078125E-4, 3.4332275390625E-4, 1.71661376953125E-4, 8.58306884765625E-5, 4.291534423828125E-5, 2.1457672119140625E-5, 1.0728836059570312E-5, 5.364418029785156E-6, 2.682209014892578E-6, 1.341104507446289E-6, 6.705522537231445E-7, 3.3527612686157227E-7];
let url = 'http://localhost:9999/geoserver/gwc/service/wmts?';
for (const param in params) {
if (baseParams.indexOf(param.toUpperCase()) < 0) {
url = url + param + '=' + params[param] + '&';
}
}
url = url.slice(0, -1);

const source = new WMTS({
url,
layer: params.LAYER,
matrixSet: params.TILEMATRIXSET,
format: params.FORMAT,
projection: projection,
tileGrid: new WMTSTileGrid({
tileSize: [256, 256],
extent: [-180.0, -90.0, 180.0, 90.0],
origin: [-180.0, 90.0],
resolutions: resolutions,
matrixIds: params.TILEMATRIX
}),
style: params.STYLE,
wrapX: true
});
let wmsLayer = new TileLayer({
source: source
});
let view = new View({
center: [0, 0],
zoom: 2,
projection: projection;,
extent: [-180.0, -90.0, 180.0, 90.0]
});
let map = new Map({
controls: [
new MousePosition(),
new Zoom(),
],
layers: [wmsLayer],
target: 'map',
view: wmsVioew
});

//Get layer feature information by clicking on the layer
map.on('singleclick', evt => {
document.getElementById('info').innerHTML = '';

const source = source;
const resolution = view.getResolution();
const tilegrid = source.getTileGrid();
const tileResolutions = tilegrid.getResolutions();
let zoomIdx, diff = Infinity;

for (let i = 0; i < tileResolutions.length; i++) {
const tileResolution = tileResolutions[i];
const diffP = Math.abs(resolution - tileResolution);
if (diffP < diff) {
diff = diffP;
zoomIdx = i;
}
if (tileResolution < resolution) {
break;
}
}
const tileSize = tilegrid.getTileSize(zoomIdx);
const tileOrigin = tilegrid.getOrigin(zoomIdx);

const fx = (evt.coordinate[0] - tileOrigin[0]) / (resolution * tileSize[0]);
const fy = (tileOrigin[1] - evt.coordinate[1]) / (resolution * tileSize[1]);
const tileCol = Math.floor(fx);
const tileRow = Math.floor(fy);
const tileI = Math.floor((fx - tileCol) * tileSize[0]);
const tileJ = Math.floor((fy - tileRow) * tileSize[1]);
const matrixIds = tilegrid.getMatrixIds()[zoomIdx];

let url = url;
for (const param in params) {
if (param.toUpperCase() === 'TILEMATRIX') {
url = url + 'TILEMATRIX=' + matrixIds + '&';
} else {
url = url + param + '=' + params[param] + '&';
}
}

url = url
+ 'SERVICE=WMTS&REQUEST=GetFeatureInfo'
+ '&INFOFORMAT=' + 'text/html'
+ '&TileCol=' + tileCol
+ '&TileRow=' + tileRow
+ '&I=' + tileI
+ '&J=' + tileJ;

if (url) {
document.getElementById('info').innerHTML = 'Loading... please wait...';

this.http.get<any>(url, {
// withCredentials: true,
responseType: 'text' as 'json',
headers: new HttpHeaders({
'Accept': '*/*',
'Content-Type': 'text/html'
}),
})
.subscribe((res) => {
document.getElementById('info').innerHTML = res;
}, () => {
document.getElementById('info').innerHTML = '';
});
}
});
Image for post
Image for post

Full exception stack trace from GeoServer console

09 Sep 17:11:56 INFO [geoserver.wms] -
Request: getServiceInfo
Sep 09, 2019 5:11:56 PM org.geoserver.GeoserverInitStartupListener$1 errorOccurred
INFO: Problem occurs when computing a tile by the owner.
java.lang.RuntimeException: javax.imageio.IIOException: Illegal value for Predictor in TIFF file
at com.sun.media.jai.imageioimpl.ImageReadOpImage.computeTile(ImageReadOpImage.java:706)
at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:904)
at javax.media.jai.OpImage.getTile(OpImage.java:1129)
at javax.media.jai.PlanarImage.getData(PlanarImage.java:2085)
at javax.media.jai.PlanarImage.getExtendedData(PlanarImage.java:2440)
at javax.media.jai.ScaleOpImage.computeTile(ScaleOpImage.java:1255)
at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:904)
at javax.media.jai.OpImage.getTile(OpImage.java:1129)
at javax.media.jai.PlanarImage.getData(PlanarImage.java:2085)
at javax.media.jai.StatisticsOpImage.getProperty(StatisticsOpImage.java:292)
at com.sun.media.jai.opimage.ExtremaOpImage.getProperty(ExtremaOpImage.java:100)
at javax.media.jai.RenderedOp$1.getProperty(RenderedOp.java:1808)
at javax.media.jai.PropertyEnvironment.getProperty(PropertyEnvironment.java:197)
at javax.media.jai.PropertySourceImpl.getProperty(PropertySourceImpl.java:277)
at javax.media.jai.WritablePropertySourceImpl.getProperty(WritablePropertySourceImpl.java:130)
at javax.media.jai.RenderedOp.getProperty(RenderedOp.java:1982)
at org.geotools.image.ImageWorker.getComputedProperty(ImageWorker.java:1033)
at org.geotools.image.ImageWorker.getExtremas(ImageWorker.java:1089)
at org.geotools.image.ImageWorker.rescaleToBytes(ImageWorker.java:1400)
at org.geotools.renderer.lite.gridcoverage2d.RasterSymbolizerHelper.execute(RasterSymbolizerHelper.java:139)
at org.geotools.renderer.lite.gridcoverage2d.RasterSymbolizerHelper.execute(RasterSymbolizerHelper.java:53)
at org.geotools.renderer.lite.gridcoverage2d.StyleVisitorCoverageProcessingNodeAdapter$1.execute(StyleVisitorCoverageProcessingNodeAdapter.java:97)
at org.geotools.renderer.lite.gridcoverage2d.BaseCoverageProcessingNode.checkExecuted(BaseCoverageProcessingNode.java:234)
at org.geotools.renderer.lite.gridcoverage2d.BaseCoverageProcessingNode.getOutput(BaseCoverageProcessingNode.java:332)
at org.geotools.renderer.lite.gridcoverage2d.BaseCoverageProcessingNode.getOutput(BaseCoverageProcessingNode.java:52)
at org.geotools.renderer.lite.gridcoverage2d.StyleVisitorCoverageProcessingNodeAdapter.getOutput(StyleVisitorCoverageProcessingNodeAdapter.java:130)
at org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer.symbolize(GridCoverageRenderer.java:484)
at org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer.renderImage(GridCoverageRenderer.java:1021)
at org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer.renderImage(GridCoverageRenderer.java:831)
at org.geoserver.wms.map.RenderedImageMapOutputFormat.directRasterRender(RenderedImageMapOutputFormat.java:1036)
at org.geoserver.wms.map.RenderedImageMapOutputFormat.produceMap(RenderedImageMapOutputFormat.java:349)
at org.geoserver.wms.map.RenderedImageMapOutputFormat.produceMap(RenderedImageMapOutputFormat.java:265)
at org.geoserver.wms.map.RenderedImageMapOutputFormat.produceMap(RenderedImageMapOutputFormat.java:132)
at org.geoserver.wms.GetMap.executeInternal(GetMap.java:720)
at org.geoserver.wms.GetMap.run(GetMap.java:300)
at org.geoserver.wms.GetMap.run(GetMap.java:123)
at org.geoserver.wms.DefaultWebMapService.getMap(DefaultWebMapService.java:251)
at sun.reflect.GeneratedMethodAccessor296.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.geoserver.kml.WebMapServiceKmlInterceptor.invoke(WebMapServiceKmlInterceptor.java:38)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.geoserver.gwc.wms.CacheSeedingWebMapService.invoke(CacheSeedingWebMapService.java:59)
at org.geoserver.gwc.wms.CacheSeedingWebMapService.invoke(CacheSeedingWebMapService.java:33)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.geoserver.gwc.wms.CachingWebMapService.invoke(CachingWebMapService.java:72)
at org.geoserver.gwc.wms.CachingWebMapService.invoke(CachingWebMapService.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.geoserver.ows.util.RequestObjectLogger.invoke(RequestObjectLogger.java:50)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy96.getMap(Unknown Source)
at sun.reflect.GeneratedMethodAccessor254.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.geoserver.ows.Dispatcher.execute(Dispatcher.java:877)
at org.geoserver.ows.Dispatcher.handleRequestInternal(Dispatcher.java:264)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:174)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:50)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.geoserver.filters.ThreadLocalsCleanupFilter.doFilter(ThreadLocalsCleanupFilter.java:26)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.filters.SpringDelegatingFilter$Chain.doFilter(SpringDelegatingFilter.java:69)
at org.geoserver.wms.animate.AnimatorFilter.doFilter(AnimatorFilter.java:73)
at org.geoserver.filters.SpringDelegatingFilter$Chain.doFilter(SpringDelegatingFilter.java:66)
at org.geoserver.filters.SpringDelegatingFilter.doFilter(SpringDelegatingFilter.java:41)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.platform.AdvancedDispatchFilter.doFilter(AdvancedDispatchFilter.java:37)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.geoserver.security.filter.GeoServerAnonymousAuthenticationFilter.doFilter(GeoServerAnonymousAuthenticationFilter.java:51)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.geoserver.security.filter.GeoServerBasicAuthenticationFilter.doFilter(GeoServerBasicAuthenticationFilter.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.geoserver.security.filter.GeoServerSecurityContextPersistenceFilter$1.doFilter(GeoServerSecurityContextPersistenceFilter.java:52)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.geoserver.security.GeoServerSecurityFilterChainProxy.doFilter(GeoServerSecurityFilterChainProxy.java:141)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.filters.LoggingFilter.doFilter(LoggingFilter.java:90)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.filters.XFrameOptionsFilter.doFilter(XFrameOptionsFilter.java:79)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.filters.GZIPFilter.doFilter(GZIPFilter.java:42)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.filters.SessionDebugFilter.doFilter(SessionDebugFilter.java:46)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.geoserver.filters.FlushSafeFilter.doFilter(FlushSafeFilter.java:42)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:256)
at org.eclipse.jetty.servlets.CrossOriginFilter.doFilter(CrossOriginFilter.java:219)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.imageio.IIOException: Illegal value for Predictor in TIFF file
at it.geosolutions.imageioimpl.plugins.tiff.TIFFLZWDecompressor.<init>(TIFFLZWDecompressor.java:118)
at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.read(TIFFImageReader.java:1856)
at com.sun.media.jai.imageioimpl.ImageReadOpImage.computeTile(ImageReadOpImage.java:697)
... 147 more

Written by

Researcher | Architect | Full-Stack | @hustakin

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store