blog.itcode.devblog.itcode.dev

A Guide for Developers Traveling Through OpenLayers - 16. Displaying Images on the Map Using WMS GetImage

This chapter covers how to display images on the map via WFS. While WFS in the previous chapter received spatial data as GeoJSON and displayed it directly as objects, WMS receives an image that GeoServer has rendered from objects and displays that. In other words, you can think of it as receiving a Tile Map directly from GeoServer and rendering it.

A Guide for Developers Traveling Through OpenLayers - 16. Displaying Images on the Map Using WMS GetImage

This chapter covers how to display images on the map via WFS. While WFS in the previous chapter received spatial data as GeoJSON and displayed it directly as objects, WMS receives an image that GeoServer has rendered from objects and displays that. In other words, you can think of it as receiving a Tile Map directly from GeoServer and rendering it.
RWB0104
@RWBwritten at 2022-05-15 17:13:10
A Guide for Developers Traveling Through OpenLayers

시리즈 모아보기

A Guide for Developers Traveling Through OpenLayers

16 / 23

This chapter covers how to display images on the map via WFS.

While WFS in the previous chapter received spatial data as GeoJSON and displayed it directly as objects, WMS receives an image that GeoServer has rendered from objects and displays that.

In other words, you can think of it as receiving a Tile Map directly from GeoServer and rendering it.




To display WMS, a total of 4 objects are needed. Since WMS receives and displays images, we need ImageWMS to hold the image, and ImageLayer to render it onto the map using that image. The remaining View and Map objects are also required.

We'll explain how to implement each of these 4 elements in order, ultimately creating a map that uses WMS.



We call the WMS image via the data we built through GeoServer.

Among the WMS operations, we use GetImage, which provides attribute information. The request method for GetImage is as follows.

TXT

GET https://example.com/geoserver/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&layers=test:building&exceptions=application%2Fjson&WIDTH=256&HEIGHT=256&CRS=EPSG%3A3857&STYLES=&BBOX=14168061.814827133%2C4367306.048101831%2C14168367.562940273%2C4367611.796214972
ParameterExampleRequireDescription
serviceWMS (fixed)YService name
version1.3.0 (fixed), 1.1.1, 1.1.0, 1.0.0YVersion
requestGetMap (fixed)YRequest name
layersrepo_name:layer_nameYLayer name (separate multiple with commas)
stylesstyle1Style name to apply (if empty, applies the default style set in GeoServer; multiple separated by commas)
srs(or crs)EPSG:4326Reference coordinate system (if empty, uses the layer's default CRS)
bboxxmin,ymin,xmax,ymaxx_{min},y_{min},x_{max},y_{max}YImage extent coordinates
width256YImage width
height256YImage height
formatimage/pngYRequest name
transparentfalse (default)Whether the background is transparent
bgcolorFFFFFF (default)Background color in RRGGBB format
exceptionsapplication/vnd.ogc.se_xml (default)Exception response format
time2022-03-14T22:30.27.520+09:00Time for time-series data (yyyy-MM-ddThh:mm:ss.SSSZ)
sldhttps://example.com/sld.xmlPath to the XML file
sld_bodySLD XML

However, compared to WFS, the WMS URL requires more parameters, making it somewhat more complex. In WFS, we entered the URL directly into VectorSource, but with WMS's source object, ImageWMS, if you provide a few required values, it will build and call the URL automatically.

For now, just understand that WMS is called directly in this manner, and move on.



OpenLayers' ImageWMS object generates and calls a WMS URL from the given values.

TYPESCRIPT

import { ImageWMS } from 'ol/source';

const source = new ImageWMS({
	url: 'https://example.com/geoserver/wms',
	params: {
		layers: 'test:building',
		exceptions: 'application/json'
	},
	serverType: 'geoserver'
});

The complete information for ImageWMS can be found in the official documentation.

The details of the configuration are as follows.

NameTypeDefaultDescription
attributionsol/source/Source-AttributionLike | undefinedAttribution text (bottom right of the map)
crossOriginnull | string | undefinedThe image's CORS attribute (reference)
hidpibooleantrueWhen requesting WMS from a remote server, uses the Map object's pixelRatio value
serverTypeol/source/WMSServerType | string | undefinedType of the WMS server (mapserver, geoserver, qgis, etc.)
Only needed when hidpi is true
imageLoadFunctionol/Image-LoadFunction | undefinedtrueMethod to load the WMS URL image
Used when overriding the WMS call method
imageSmoothingbooleantrueA deprecated property; using interpolate is recommended
interpolatebooleantrueWhether to use interpolated values during resampling
paramsobjectWMS request parameters. At least one LAYERS must be provided
STYLES defaults to an empty value ''
VERSION defaults to 1.3.0
WIDTH, HEIGHT, BOX, CRS(SRS) are set dynamically
projectionol/proj-ProjectionLike | undefinedProjection object. Defaults to the projection declared on the Map's View object
rationumber1.5Size of the viewport used when requesting images. 1 is the same as the map viewport, and 2 means twice the map viewport's width and height
Must be 1 or greater
resolutionsArray<number> | undefinedResolutions. If specific resolutions are set, calls only occur at those resolutions
urlstringWMS URL

url and params.layers must both be provided to perform a valid WMS call. If you provide just these two values, ImageWMS will calculate and fill in the remaining parameters needed for WMS on its own.



OpenLayers' TileLayer object renders the map using the image called via ImageWMS. This map consists of an image, similar to a basemap.

TYPESCRIPT

import ImageLayer from 'ol/layer/Image';

const layer = new TileLayer({
	source: source,
	minZoom: 15,
	properties: { name: 'wms' },
	zIndex: 5
});
NameTypeDefaultDescription
classNamestringol-layerClass name
opacitynumber1Opacity (0 ~ 1)
visiblebooleantrueWhether visible
extentol/extent-Extent | undefinedThe layer's rendering extent. Data outside this extent isn't shown
zIndexnumber | undefinedPriority (higher shows on top)
minResolutionnumber | undefinedMinimum display resolution
maxResolutionnumber | undefinedMaximum display resolution
minZoomnumber | undefinedMinimum display zoom level
maxZoomnumber | undefinedMaximum display zoom level
mapol/PluggableMap-PluggableMap | undefinedUses the corresponding layer as an overlay in the specified Map object
source(ol/source/Image-ImageSource | ol/source/VectorTile-VectorTile) | undefinedThe layer's source
propertiesobject | undefinedArbitrary properties. Can be manipulated with get(), set()

The complete information for ImageLayer can be found at ol/layer/Image-ImageLayer.



We create a View object to declare the map's viewing information.

TYPESCRIPT

import View from 'ol/View';
import proj4 from 'proj4';

const view = new View({
	projection: 'EPSG:3857',
	center: proj4('EPSG:4326', 'EPSG:3857', [ 127.28923267492068, 36.48024986578043 ]),
	zoom: 17
});
NameTypeDefaultDescription
centerol/coordinate-Coordinate | undefinedCenter of the map
constrainRotationboolean | numbertrueWhether to constrain rotation. If a number, indicates the number of allowed rotation steps (0 means 90, 180, 270, 360)
enableRotationbooleantrueWhether rotation is enabled
extentol/extent-Extent | undefinedThe map's viewing extent. Cannot go beyond the specified extent
constrainOnlyCenterbooleanfalseIf true, the extent constraint is applied only to the View's center, not the entire extent
smoothExtentConstraintbooleantrueWhether the View may slightly go outside the extent range
maxResolutionnumber | undefinedMaximum viewing resolution. Cannot zoom in beyond the specified resolution.
minResolutionnumber | undefinedMinimum viewing resolution. Cannot zoom out beyond the specified resolution.
maxZoomnumber28Maximum viewing zoom level. Cannot zoom in beyond the specified zoom level.
minZoomnumber0Minimum viewing zoom level. Cannot zoom out beyond the specified zoom level.
multiWorldbooleanfalseWhether to allow multiple worlds
constrainResolutionbooleanfalseWhether to allow only integer zoom levels
smoothResolutionConstraintbooleantrueWhether to use loose zoom-in/zoom-out rules
showFullExtentbooleanfalseWhether to show the full configured extent
projectionol/proj-ProjectionLikeEPSG:3857Coordinate system
resolutionnumber | undefinedInitial resolution
resolutionsArray<number> | undefinedList of available resolutions (descending order). Ignores the max/minResolution, max/minZoom, zoomFactor options
rotationnumber0Default rotation value
zoomnumber | undefinedDefault zoom level
zoomFactornumber2Zoom factor
paddingArray<number>[ 0, 0, 0, 0 ]Padding


WMS can also style the elements drawn in the image.

While WFS could describe style objects directly in the code, WMS is fundamentally handled on the backend side, like GeoServer, so the server itself describes the style directly.

It's usually described in XML form, which is called SLD.


For GeoServer, you can manage this in the [Styles] menu. If you haven't made any changes, several ready-to-use SLDs are loaded by default.

When adding a layer, you can configure the style during the [Publish] step, and what you set there is the SLD used for WMS.

You can also register multiple styles, in which case you can call the desired style by the name specified in STYLES. The default value of STYLES is an empty '', and in that case the specified default style is used to render the image.

XML

<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0" 
 xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" 
 xmlns="http://www.opengis.net/sld" 
 xmlns:ogc="http://www.opengis.net/ogc" 
 xmlns:xlink="http://www.w3.org/1999/xlink" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <!-- a Named Layer is the basic building block of an SLD document -->
  <NamedLayer>
    <Name>default_polygon</Name>
    <UserStyle>
    <!-- Styles can have names, titles and abstracts -->
      <Title>Default Polygon</Title>
      <Abstract>A sample style that draws a polygon</Abstract>
      <!-- FeatureTypeStyles describe how to render different features -->
      <!-- A FeatureTypeStyle for rendering polygons -->
      <FeatureTypeStyle>
        <Rule>
          <Name>rule1</Name>
          <Title>Gray Polygon with Black Outline</Title>
          <Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract>
          <PolygonSymbolizer>
            <Fill>
              <CssParameter name="fill">#ED143D</CssParameter>
              <CssParameter name="opacity">0.6</CssParameter>
            </Fill>
            <Stroke>
              <CssParameter name="stroke">#ED143d</CssParameter>
              <CssParameter name="stroke-width">2</CssParameter>
            </Stroke>
          </PolygonSymbolizer>
          <TextSymbolizer>
            	  <Geometry>
	    <ogc:Function name="centroid">
	      <ogc:PropertyName>SHAPE</ogc:PropertyName>
	    </ogc:Function>
	  </Geometry>
            <Label>
              <ogc:PropertyName>buld_nm</ogc:PropertyName>
            </Label>
            <Font>
              <CssParameter name="font-family">sans-serif</CssParameter>
              <CssParameter name="font-size">16</CssParameter>
            </Font>
            <LabelPlacement>
              <PointPlacement>
                <AnchorPoint>
                  <AnchorPointX>0.5</AnchorPointX>
                  <AnchorPointY>0.5</AnchorPointY>
                </AnchorPoint>
                <Displacement>
                  <DisplacementX>0</DisplacementX>
                  <DisplacementY>0</DisplacementY>
                </Displacement>
              </PointPlacement>
            </LabelPlacement>
            <Halo>
              <Radius>
                <ogc:Literal>2</ogc:Literal>
              </Radius>
              <Fill>
                <CssParameter name="fill">#000000</CssParameter>
              </Fill>
            </Halo>
            <Fill>
              <CssParameter name="fill">#FFFFFF</CssParameter>
            </Fill>
          </TextSymbolizer>
        </Rule>
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>

The SLD above is actually the SLD used in the project's WMS request. If you've read the section on style description in WFS, this will be easier to understand. Due to the nature of XML it looks complex, but once you break it down, there isn't much to it.

Likewise, the way it's described differs slightly by data type, such as Point and Polygon.


There's also a way to use the design you want without necessarily describing the SLD in GeoServer, which is possible by using the sld_body WMS request parameter.

If you enter the SLD directly into sld_body, that SLD is applied with priority. The parameter's content is the SLD itself.



We create a Map object that combines all the information to build the map.

TYPESCRIPT

import Map from 'ol/Map';
import { ImageWMS } from 'ol/source';
import ImageLayer from 'ol/layer/Image';
import View from 'ol/View';
import proj4 from 'proj4';

// WMS source object
const source = new ImageWMS({
	url: 'https://example.com/geoserver/wms',
	params: {
		layers: 'test:building',
		exceptions: 'application/json'
	},
	serverType: 'geoserver'
});

// WMS layer object
const layer = new ImageLayer({
	source: source,
	minZoom: 15,
	properties: { name: 'wms' },
	zIndex: 5
});

// View object
const view = new View({
	projection: 'EPSG:3857',
	center: proj4('EPSG:4326', 'EPSG:3857', [ 127.28923267492068, 36.48024986578043 ]),
	zoom: 17
});

// Map object
const map = new Map({
	layers: [ vworldBaseLayer, vworldHybridLayer, wfsLayer ],
	target: 'map',
	view: view
});
NameTypeDefaultDescription
controlsol/Collection-Collection<ol/control/Control-Control> | Array<ol/control/Control-Control> | undefinedol/control/defaultsMap control object
pixelRationumberwindow.devicePixelRatioDevice pixel ratio
interactionsol/Collection-Collection<ol/interaction/Interaction-Interaction> | Array<ol/interaction/Interaction-Interaction> | undefined
keyboardEventTargetHTMLElement | Document | string | undefinedTarget element for keyboard events
layersArray<ol/layer/Base-BaseLayer> | ol/Collection-Collection<ol/layer/Base-BaseLayer> | ol/layer/Group-LayerGroup | undefinedList of layers. Later entries in the array have higher priority
maxTilesLoadingnumber16Maximum number of tiles that can load simultaneously
moveTolerancenumber1Minimum pixels the mouse must move to be recognized as a map move event
overlaysol/Collection-Collection<ol/Overlay-Overlay> | Array<ol/Overlay-Overlay> | undefinedMap overlay object
targetHTMLElement | string | undefinedDOM or DOM ID where the map will be displayed
viewol/View-View | Promise<ol/View-View> | undefinedThe map's view object

We assign the objects declared so far to the Map object. The declared map is displayed in the DOM specified by target.

target: map means displaying the map in the DOM with the ID map. You can also assign an HTMLElement directly, not just an ID.

You can confirm that the image called via WMS is displayed on the map.



OpenLayers provides two ways to call WMS: the Image method, which fetches the entire image of the current extent, and the Tile method, which splits it into multiple grids and fetches those.

This chapter describes the Image method, which calls the entire image of the current extent.

If you'd like to call WMS in a tiled form, you can use TileWMS and TileLayer. The usage is the same. Based on the code described in this chapter, simply changing ImageWMS to TileWMS works without any issues. The same goes for TileLayer.


The difference between the two methods is illustrated in the diagram above. The basemap also uses the TileWMS method.

  • Image method

    • Since the WMS call happens only once, the number of requests can be reduced.
    • The size of a single response is relatively large, and it is slower.
  • Tile method

    • There are far more WMS call requests compared to the Image method.
    • Since it calls multiple smaller images, it is relatively faster.

Check the differences and adopt whichever method is more suitable for your service.

The basemap is also essentially a kind of TileWMS.




You can check an example implementing this at OpenLayers6 Sandbox - WMS.


You can confirm that OpenLayers renders the map by calling spatial data through GeoServer.

# GIS# GeoServer# OpenLayers# OGC# WMS
ship
blog.itcode.dev

Notes from the π-th Alpaca

7.0.1
Developed by RWB since 2021.057th upgraded at 2026.08