Watermark technology
Watermark can provide strong evidence of the ownership of products receiving copyright information, and can monitor the spread of protected data, authenticate and control illegal copies, etc. It is also needed in today’s popular online maps Watermark technology protects map data. This article will introduce how to add watermarks to tile maps, including raster tiles and vector tiles.
During the exploration process, we referred to “Front-end Watermark Generation Scheme (Web Page Watermark + Image Watermark)” and “Openlayer Slice Layer Adding Watermark”
Implementation plan
Option 1: Pure front-end implementation
By setting a watermark to the HTML tag, add canvas at the front of the current view. The code is as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>map demo</title> <link href="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.css" rel="stylesheet"> </head> <style> html, body, #map {<!-- --> padding: 0; margin: 0; width: 100%; height: 100%; overflow: hidden; } </style> <body> <div id="map"></div> <script src="//i2.wp.com/cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.js"></script> <script> (function () {<!-- --> // canvas implements watermark function __canvasWM({<!-- --> // Use ES6's function default value method to set the default value of the parameter // For details, see https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Default_parameters container = document.body, width = '256px', height = '256px', textAlign = 'center', textBaseline = 'middle', font = "20px microsoft yahei", fillStyle = 'rgba(184, 184, 184, 0.8)', content = 'for reference only', rotate = '30', zIndex = 1000 } = {<!-- -->}) {<!-- --> var args = arguments[0]; var canvas = document.createElement('canvas'); canvas.setAttribute('width', width); canvas.setAttribute('height', height); var ctx = canvas.getContext("2d"); ctx.textAlign = textAlign; ctx.textBaseline = textBaseline; ctx.font = font; ctx.fillStyle = fillStyle; ctx.rotate(Math.PI / 180 * rotate); ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2); var base64Url = canvas.toDataURL(); console.log(base64Url); const watermarkDiv = document.createElement("div"); watermarkDiv.setAttribute('style', ` position:absolute; top:0; left:0; width:100%; height:100%; z-index:${<!-- -->zIndex}; pointer-events:none; background-repeat:repeat; background-image:url('${<!-- -->base64Url}')`); container.style.position = 'relative'; container.insertBefore(watermarkDiv, container.firstChild); }; window.__canvasWM = __canvasWM; })(); //Call watermark __canvasWM({<!-- --> content: 'watermark' }) </script> <script> var map = new ol.Map({<!-- --> target: 'map', layers: [ new ol.layer.Tile({<!-- --> source: new ol.source.OSM() }) ], view: new ol.View({<!-- --> zoom: 4, center: ol.proj.transform([110, 39], "EPSG:4326", "EPSG:3857") }) }); </script> </body> </html>
The effect is as follows:
Option 2: Send slices back to the front end for secondary processing (applicable to both raster tiles and vector tiles)
This solution is to use tile slicing to create a separate watermark, and use the callback function of the tile URL to return the base64 watermark image. The watermark image can be made in advance and converted to base64 or Canvas can be used to dynamically brake the watermark. Things to note The width and height of the watermark image need to be 512X512. The watermark layer addition of Openlayer and Mapbox is implemented here.
Openlayer implements watermark layer
The function used by Openlayer is tileUrlFunction
, the corresponding official document explains
code show as below:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Openlayer map watermark</title> <link href="https://cdn.bootcdn.net/ajax/libs/openlayers/7.5.2/ol.min.css" rel="stylesheet"> </head> <style> html, body, #map {<!-- --> padding: 0; margin: 0; width: 100%; height: 100%; overflow: hidden; } </style> <body> <div id="map"> </div> <script src="//i2.wp.com/cdn.bootcdn.net/ajax/libs/openlayers/7.5.2/dist/ol.min.js"></script> <script> //Create Canvas function createCanvasContext2D(opt_width, opt_height) {<!-- --> const canvas = (document.createElement('canvas')); if (opt_width) {<!-- --> canvas.width = opt_width; } if (opt_height) {<!-- --> canvas.height = opt_height; } return (canvas.getContext('2d')); } //Watermark tile layer var tiles = new ol.layer.Tile({<!-- --> source: new ol.source.XYZ({<!-- --> tileUrlFunction: function (t) {<!-- --> var zoom = t[0]; var tile = {<!-- --> x: t[1], y: -(t[2] + 1) } var tileSize = [512, 512]; const half = tileSize[0] / 2; const lineheight = 48; var tileSize = [512, 512]; //Create Canvas const context = createCanvasContext2D(tileSize[0], tileSize[0]); //Fill style context.fillStyle = 'rgba(184, 184, 184, 0.8)'; //Text position context.textAlign = 'center'; context.textBaseline = 'middle'; //Text font size context.font = '48px microsoft yahei'; //slope context.rotate(Math.PI / 180 * 30); //Text content context.fillText(`for reference only`, half, half); //return base64 return context.canvas.toDataURL(); }, extent: ol.proj.transformExtent([-180, -85, 180, 85], "EPSG:4326", "EPSG:3857") }) }); var map = new ol.Map({<!-- --> target: 'map', layers: [ new ol.layer.Tile({<!-- --> source: new ol.source.OSM() }), //Add watermark layer tiles ], view: new ol.View({<!-- --> zoom: 4, center: ol.proj.transform([110, 39], "EPSG:4326", "EPSG:3857")//ol.proj.fromLonLat([110, 39]) }) }); </script> </body> </html>
final effect:
MapBox implements watermark layer
The function used by Mapbox is transformRequest
, and the corresponding official document explains
code show as below:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>MapBox map watermark</title> <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /> <script src="//i2.wp.com/api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.js"></script> <link href="https://api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.css" rel="stylesheet" /> <style> body {<!-- --> margin: 0; padding: 0; } #map {<!-- --> position: absolute; top: 0; bottom: 0; width: 100%; } </style> </head> <body> <div id="map"></div> <script> mapboxgl.accessToken = 'your key'; const map = new mapboxgl.Map({<!-- --> container: 'map', style: 'mapbox://styles/mapbox/streets-v11', //Callback transformRequest: function transformRequest(url, resourceType) {<!-- --> if (resourceType === 'Tile' & amp; & amp; url.startsWith('http://ip:watermark')) {<!-- --> //When the data source type is Tile and the tile address is http://ip:watermark, modify the tile URL return {<!-- --> //TODO: base64 or URL watermark image //TODO: The image size can be adjusted to include 256X256, 512X512 and other square images. url: '' }; } } }); //TODO: Map loading success event map.on('load', () => {<!-- --> //TODO: Add watermark data source map.addSource('watermark', {<!-- --> type: 'raster', //It doesn't matter whether a tile address can be loaded or not. tiles: ['http://ip:watermark/{x}/{y}/{z}.png'], //TODO: Set the tile size 256 512 optional, you can adjust the density tileSize: 512, minzoom: 0, maxzoom: 24 }); //TODO: Add watermark layer map.addLayer({<!-- --> id: "watermark", type: "raster", source: "watermark", //TODO: Set the minimum display level minzoom: 0, //TODO: Set the maximum display level maxzoom: 24, //TODO: Set transparency paint: {<!-- --> "raster-opacity": 0.5 }, //TODO: Set the vertical index value of the layer to always stay on top zIndex: 999999 }); }); map.addControl(new mapboxgl.NavigationControl()); </script> </body> </html>
final effect:
Other instructions:
1. MapBox can also be implemented through json style files,
The watermark image needs to be made into a script sprite. You can refer to this article to generate a Mapbox sprite, and then create a transparent background setting icon. The size of the same watermark image is 512X512. The style.json example is as follows :
{<!-- --> "version": 8, "name": "Watermark Style", "metadata": {<!-- -->"maputnik:renderer": "mbgljs"}, "sources": {<!-- -->}, "sprite": "", "glyphs": " ", "layers": [ //Other layers ... //watermark layer {<!-- --> "id": "watermark", "type": "background", "paint": {<!-- --> "background-color": "rgba(255, 255, 255, 1)", "background-pattern": "watermark", "background-opacity": 0.5 } } ], "id": "Watermark" }
The effect is as follows:
2. Watermark density control
Watermark image size: Because the map tile size is 512X512, images of different sizes will have an impact. We recommend 512X512, but you can also try watermark images of other sizes such as 256X256 or 1024X1024.
Watermark proportion: The proportion of the text or logo in the middle of the watermark image to the entire image will also affect the watermark density.
Map zoom level: Since the watermark is loaded on tiles, the smaller the map level, the denser the tiles, resulting in a denser watermark display. The watermark density can be adjusted by controlling the maximum zoom ratio of the watermark layer.
Option 3: Data layer implementation (mainly for grid tiles)
When generating raster slices, adding watermarks to the raster slices is actually a superimposition process of pictures and watermark pictures. You can write a batch program after the slicing is completed to perform watermark superposition processing on all slice pictures. This has not been implemented yet. .