|
1 | | -# Web Coverage Services |
| 1 | +# Web Coverage Services (WCS) |
2 | 2 |
|
3 | | -TODO |
| 3 | +## Overview |
4 | 4 |
|
5 | | -https://mapserver.org/ogc/wcs_server.html |
| 5 | +This tutorial demonstrates the [WCS Server](https://mapserver.org/ogc/wcs_server.html) capabilities of MapServer. |
| 6 | +We'll be using [WCS 2.0](https://mapserver.org/ogc/wcs_server.html#wcs-2-0) for this tutorial, and will serve a |
| 7 | +Cloud-Optimized GeoTIFF (COG) from the Estonian Land Board as the source dataset. The dataset is a Digital Terrain Model (DTM) with a 1 m resolution. |
6 | 8 |
|
7 | | -https://mapserver.org/ogc/wcs_format.html |
| 9 | +<div class="map"> |
| 10 | + <iframe src="https://mapserver.github.io/getting-started-with-mapserver-demo/wcs.html"></iframe> |
| 11 | +</div> |
8 | 12 |
|
9 | | -We'll be using [WCS 2.0](https://mapserver.org/ogc/wcs_server.html#wcs-2-0) for this tutorial. |
| 13 | +## WCS Requests |
10 | 14 |
|
11 | | -# GetCapabilities |
12 | | -http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&REQUEST=GetCapabilities |
| 15 | +Some sample MapServer requests for testing the WCS service are listed below. You can test these in your browser. |
13 | 16 |
|
14 | | -# DescribeCoverage 2.0 |
15 | | -http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=DescribeCoverage&COVERAGEID=dtm |
| 17 | +- [GetCapabilities](http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&REQUEST=GetCapabilities&VERSION=2.0.1) |
| 18 | +- [DescribeCoverage 2.0](http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=DescribeCoverage&COVERAGEID=dtm) |
| 19 | +- [GetCoverage 2.0 image/tiff full](http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=dtm&FORMAT=image/tiff) |
16 | 20 |
|
17 | | -# GetCoverage 2.0 image/tiff full |
18 | | -http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=dtm&FORMAT=image/tiff |
| 21 | +You can also connect to the MapServer Docker container and use `mapserv` to test the requests from the command line. |
19 | 22 |
|
20 | 23 | ```bash |
21 | | -gdalinfo /etc/mapserver/data/raster/54752_dtm_1m.tif |
| 24 | +docker exec -it mapserver bash |
| 25 | +mapserv -nh "QUERY_STRING=map=/etc/mapserver/wcs.map&SERVICE=WCS&REQUEST=GetCapabilities&VERSION=2.0.1" |
22 | 26 | ``` |
23 | 27 |
|
24 | | -NoData Value=-9999 |
25 | | -Size is 5002, 5002 |
| 28 | +## Source Dataset |
26 | 29 |
|
27 | | -curl "http://localhost:7000/?map=/etc/mapserver/wcs.map&SERVICE=WCS&REQUEST=GetCapabilities" |
| 30 | +Let's get some information about the source dataset using the GDAL CLI command[gdal raster info](https://gdal.org/en/latest/programs/gdal_raster_info.html) |
| 31 | +(the modern equivalent of `gdalinfo`). |
28 | 32 |
|
29 | | -!!! tip |
| 33 | +```bash |
| 34 | +gdal raster info /etc/mapserver/data/raster/54752_dtm_1m.tif |
| 35 | +``` |
30 | 36 |
|
31 | | - The `COVERAGEID` will be the `LAYER` `NAME` |
| 37 | +The truncated output is shown below. |
32 | 38 |
|
| 39 | +``` |
| 40 | +Driver: GTiff/GeoTIFF |
| 41 | +Files: /etc/mapserver/data/raster/54752_dtm_1m.tif |
| 42 | + /etc/mapserver/data/raster/54752_dtm_1m.tif.aux.xml |
| 43 | +Size is 5000, 5000 |
| 44 | +Coordinate System is: |
| 45 | +PROJCRS["Estonian Coordinate System of 1997", |
| 46 | +... |
| 47 | + ID["EPSG",3301]] |
| 48 | +Origin = (655000.000000000000000,6475000.000000000000000) |
| 49 | +Pixel Size = (1.000000000000000,-1.000000000000000) |
| 50 | +... |
| 51 | +Image Structure Metadata: |
| 52 | + LAYOUT=COG |
| 53 | +... |
| 54 | +Center ( 657500.000, 6472500.000) ( 26d41'30.35"E, 58d21'52.44"N) |
| 55 | +Band 1 Block=512x512 Type=Float32, ColorInterp=Gray |
| 56 | + Min=30.680 Max=83.205 |
| 57 | + Minimum=30.680, Maximum=83.205, Mean=60.461, StdDev=9.347 |
| 58 | + NoData Value=-9999 |
| 59 | + Overviews: 2500x2500, 1250x1250, 625x625, 312x312 |
| 60 | + Metadata: |
| 61 | + STATISTICS_MAXIMUM=83.205001831055 |
| 62 | +... |
| 63 | +``` |
33 | 64 |
|
| 65 | +From the output we can see that the dataset is in the [EPSG:3301](https://spatialreference.org/ref/epsg/3301/) coordinate reference system, with an origin at (655000, 6475000) |
| 66 | +and a pixel size of 1 × 1 (with a negative Y resolution, as is typical for north-up rasters). The `LAYOUT=COG` indicates that the file is structured as a Cloud-Optimized GeoTIFF (COG). |
| 67 | + |
| 68 | +## Configuring a Mapfile for WCS |
| 69 | + |
| 70 | +The Mapfile for the WCS service is similar to a WMS Mapfile, but with some differences. The `LAYER` type is set to `RASTER`, and the `METADATA` section contains |
| 71 | +keywords prefixed with `wcs_` to specify the WCS parameters. |
| 72 | + |
| 73 | +```scala |
| 74 | +WEB |
| 75 | + METADATA |
| 76 | + "wcs_enable_request" "*" |
| 77 | + "wcs_srs" "EPSG:4326 EPSG:3857" |
| 78 | + "wcs_title" "Example WCS Mapfile" |
| 79 | + "wcs_description" "Test description" |
| 80 | + "wcs_onlineresource" "http://localhost:7000/" |
| 81 | + END |
| 82 | +END |
34 | 83 | ``` |
35 | | -msWCSGetCoverage20(): WCS server error. Raster size out of range, width and height of resulting coverage must be no more than MAXSIZE=4096. |
| 84 | + |
| 85 | +If the Mapfile is used for multiple services such as WMS and WCS, a single metadata item can be specified using the `ows_` prefix, for example `ows_title`. |
| 86 | + |
| 87 | +[LAYER METADATA](https://mapserver.org/ogc/wcs_server.html#layer-object-metadata) can also be used to specify additional information about the coverage, |
| 88 | +but is not required for this tutorial. |
| 89 | + |
| 90 | +The [OUTPUTFORMAT](https://mapserver.org/mapfile/outputformat.html) defines the properties of the output format. |
| 91 | +In this case we are defining a custom output format for GeoTIFFs with a `FLOAT32` data type to match the source raster |
| 92 | +and ensure that the full precision of the source raster is preserved in WCS responses. |
| 93 | + |
| 94 | +```scala |
| 95 | +OUTPUTFORMAT |
| 96 | + NAME "GEOTIFF" |
| 97 | + DRIVER "GDAL/GTiff" |
| 98 | + MIMETYPE "image/tiff" |
| 99 | + IMAGEMODE FLOAT32 |
| 100 | + EXTENSION "tif" |
| 101 | +END |
36 | 102 | ``` |
37 | 103 |
|
38 | | -Set the [MAXSIZE](https://mapserver.org/mapfile/map.html#mapfile-map-maxsize) directive on the `MAP` to a larger value. By default this is set to 4096. |
| 104 | +We can use the full power of GDAL to define custom output formats. For example, we could define a COG output format |
| 105 | +by switching to the [COG Driver](https://gdal.org/en/latest/drivers/raster/cog.htm), and add statistics to the output file by adding the `STATISTICS=YES` format option: |
| 106 | + |
| 107 | +```scala |
| 108 | +OUTPUTFORMAT |
| 109 | + NAME "GEOTIFF_COG" |
| 110 | + DRIVER "GDAL/COG" |
| 111 | + MIMETYPE "image/tiff" |
| 112 | + IMAGEMODE FLOAT32 |
| 113 | + EXTENSION "tif" |
| 114 | + FORMATOPTION "STATISTICS=YES" |
| 115 | +END |
| 116 | +``` |
| 117 | + |
| 118 | +## Requesting a WCS in OpenLayers |
39 | 119 |
|
40 | | -[WCS and NULL Values](https://github.com/geographika/wcs-test) |
| 120 | +Typically WCS requests are made from client applications such as QGIS, ArcGIS Pro, or custom JS code in web applications to download the raw raster data, |
| 121 | +rather than to display it as a map image. However, for the purposes of this tutorial we will be using OpenLayers to make requests to the WCS and display the results. |
| 122 | +WCS is not natively supported in OpenLayers, but we can use the [ImageWMS](https://openlayers.org/en/latest/apidoc/module-ol_source_ImageWMS.html) source as a workaround |
| 123 | +by overriding the request parameters to call WCS, and display the results as an image layer on the map. |
| 124 | + |
| 125 | +!!! tip |
41 | 126 |
|
| 127 | + The `COVERAGEID` corresponds to the MapServer `LAYER` `NAME` |
42 | 128 |
|
| 129 | +## Code |
| 130 | + |
| 131 | +??? JavaScript "wcs.js" |
| 132 | + |
| 133 | + ```js |
| 134 | + --8<-- "wcs.js" |
| 135 | + ``` |
| 136 | + |
| 137 | +??? Mapfile "wcs.map" |
| 138 | + |
| 139 | + ``` scala title="wcs.map" |
| 140 | + --8<-- "wcs.map" |
| 141 | + ``` |
| 142 | + |
| 143 | +## Exercises |
| 144 | + |
| 145 | +1. From the command line, test the WCS 2.0.1 protocol by making a `GetCoverage` request and saving the output as a GeoTIFF using the configured `OUTPUTFORMAT` (MapServer format name, not a MIME type). |
| 146 | + Then use `gdal raster info` to check the output file. |
| 147 | + |
| 148 | +``` |
| 149 | +mapserv -nh "QUERY_STRING=map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=dtm&FORMAT=GEOTIFF&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326&SUBSET=x(26.6507,26.7362)&SUBSET=y(58.3414,58.3879)&SCALESIZE=x(400),y(400)" \ |
| 150 | +> output.tif |
| 151 | +gdal raster info output.tif |
43 | 152 | ``` |
44 | | -mapserv -nh "QUERY_STRING=map=test.map&SERVICE=WCS&VERSION=2.0.0&REQUEST=GetCoverage&CoverageId=test&FORMAT=GEOTIFF_INT16&BBOX=-69.955,3.420,-69.701,3.5896&CRS=EPSG:4326&WIDTH=500&HEIGHT=500" > output2.tif |
45 | | -gdalinfo output.tif |
| 153 | + |
| 154 | +2. Add the COG output format to the Mapfile and make a `GetCoverage` request to download a COG-formatted output. Check the output file with `gdal raster info` to see the difference in metadata. |
| 155 | + |
| 156 | +3. Update the JavaScript code to test the WCS 1.0.0 protocol. This requires different parameters to be passed in the requests, |
| 157 | + for example `COVERAGEID` becomes `COVERAGE`, and the CRS parameters are different. You can also remove the entire `imageLoadFunction` as WCS 1.0.0 |
| 158 | + more closely matches the WMS protocol, using `BBOX`,`WIDTH`, and `HEIGHT` parameters to specify the area and size of the output image. |
| 159 | + |
| 160 | +```js |
| 161 | +params: { |
| 162 | + SERVICE: 'WCS', |
| 163 | + VERSION: '1.0.0', |
| 164 | + REQUEST: 'GetCoverage', |
| 165 | + FORMAT: 'image/png', |
| 166 | + COVERAGE: 'dtm', |
| 167 | + CRS: 'EPSG:3857', |
| 168 | + RESPONSE_CRS: 'EPSG:3857', |
| 169 | +}, |
| 170 | +``` |
| 171 | + |
| 172 | +## Possible Errors |
| 173 | + |
46 | 174 | ``` |
| 175 | +msWCSGetCoverage20(): WCS server error. Raster size out of range, width and height of resulting coverage must be no more than MAXSIZE=4096. |
| 176 | +``` |
| 177 | + |
| 178 | +Set the [MAXSIZE](https://mapserver.org/mapfile/map.html#mapfile-map-maxsize) directive in the `MAP` to a larger value. By default, this is set to 4096. |
| 179 | + |
| 180 | +## Further Reading |
47 | 181 |
|
48 | | -<!-- |
49 | | -https://openlayers.org/workshop/en/cog/ |
50 | | ---> |
| 182 | +- [MapServer WCS Use Cases](https://mapserver.org/ogc/wcs_format.html) |
| 183 | +- [WCS and NULL Values](https://github.com/geographika/wcs-test) |
0 commit comments