WebGIS瓦片地图添加水印(矢量瓦片、栅格瓦片)

news2025/1/16 16:14:10

水印技术

  水印能为收到版权信息产品归属提供有力的证据, 并能够监视被保护数据的传播, 真伪鉴别以及非法拷贝控制等.在现今流行的线上地图同样需要水印技术, 保护地图数据.本文将介绍如何实现瓦片地图水印添加, 包括栅格瓦片、矢量瓦片.

  在探索过程中, 参考了《前端水印生成方案(网页水印+图片水印)》、《Openlayer 切片图层添加水印》

在这里插入图片描述

实现方案

方案一: 纯前端实现

  通过给HTML的标签设置水印, 在当前视图最前添加canvas, 代码如下:

<!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="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.js"></script>
  <script>
    (function () {
      // canvas 实现 watermark
      function __canvasWM({
        // 使用 ES6 的函数默认值方式设置参数的默认取值
        // 具体参见 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 = '仅供参考',
        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;
    })();
    //调用水印
    __canvasWM({
      content: '水印'
    })
  </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>

效果如下:
在这里插入图片描述

方案二: 切片传回前端进行二次处理(栅格瓦片、矢量瓦片均适用)

  此方案是使用 tile 切片的方式, 单独创建一个水印, 运用瓦片URL的回调函数返回base64的水印图片实现, 其中水印图片可以提前制作好转为base64或者使用Canvas动态制动水印, 需要注意的是水印图片宽高需要为512X512.这里实现了Openlayer和Mapbox的水印图层添加.

Openlayer实现水印图层

  Openlayer使用的函数是tileUrlFunction, 相应的官方文档说明
在这里插入图片描述

代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Openlayer地图水印</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="https://cdn.bootcdn.net/ajax/libs/openlayers/7.5.2/dist/ol.min.js"></script>
    <script>
        //创建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'));
        }

        //水印瓦片图层
        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];
                    //创建Canvas
                    const context = createCanvasContext2D(tileSize[0], tileSize[0]);
                    //填充样式
                    context.fillStyle = 'rgba(184, 184, 184, 0.8)';
                    //文字位置
                    context.textAlign = 'center';
                    context.textBaseline = 'middle';
                    //文字字体大小
                    context.font = '48px microsoft yahei';
                    //倾斜角度
                    context.rotate(Math.PI / 180 * 30);
                    //文字内容
                    context.fillText(`仅供参考`, half, half);
                    //返回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()
                }),
                //添加水印图层
                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>

最终效果:
在这里插入图片描述

MapBox实现水印图层

  Mapbox使用的函数是transformRequest, 相应的官方文档说明
在这里插入图片描述

代码如下:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>MapBox地图加水印</title>
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <script src="https://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 = '你的key';
    const map = new mapboxgl.Map({
      container: 'map',
      style: 'mapbox://styles/mapbox/streets-v11',
      //回调函数
      transformRequest: function transformRequest(url, resourceType) {
        if (resourceType === 'Tile' && url.startsWith('http://ip:watermark')) {
          //数据源类型为 Tile 且瓦片地址为 http://ip:watermark 时 对瓦片url进行修改
          return {
            //TODO: base64 或 URL的水印图片 
            //TODO: 图片大小可以调节疏密程度 256X256、512X512等其他正方形图片 
            url: ''
          };
        }
      }
    });
    //TODO: 地图加载成功事件
    map.on('load', () => {
      //TODO: 添加水印数据源
      map.addSource('watermark', {
        type: 'raster',
        //随便给一个瓦片地址能不能加载都无所谓
        tiles: ['http://ip:watermark/{x}/{y}/{z}.png'],
        //TODO:  设置瓦片大小 256 512可选 可以调节疏密程度
        tileSize: 512,
        minzoom: 0,
        maxzoom: 24
      });
      //TODO: 添加水印图层
      map.addLayer({
        id: "watermark",
        type: "raster",
        source: "watermark",
        //TODO: 设置最小显示层级
        minzoom: 0,
        //TODO: 设置最大显示层级
        maxzoom: 24,
        //TODO: 设置透明度
        paint: { "raster-opacity": 0.5 },
        //TODO: 设置图层垂直索引值 永远保持最上面
        zIndex: 999999
      });
    });
    map.addControl(new mapboxgl.NavigationControl());
  </script>
</body>

</html>

最终效果:
在这里插入图片描述

其他说明:

1. MapBox还可通过json样式文件实现,

需要将水印图片制作到script精灵图里, Mapbox精灵图的生成可以参考这篇, 再创建一个透明的背景设置图标, 同样的水印图片大小为512X512, style.json实例如下:

{
  "version": 8,
  "name": "Watermark Style",
  "metadata": {"maputnik:renderer": "mbgljs"},
  "sources": {},
  "sprite": "",
  "glyphs": " ",
  "layers": [
    //其他图层
    ...
    //水印图层
    {
      "id": "watermark",
      "type": "background",
      "paint": {
        "background-color": "rgba(255, 255, 255, 1)",
        "background-pattern": "watermark",
        "background-opacity": 0.5
      }
    }
  ],
  "id": "Watermark"
}

效果如下:
在这里插入图片描述

2. 水印密集程度控制

水印图片大小: 因为地图瓦片大小为512X512,不同大小的图片会有影响, 推荐512X512, 也可以尝试256X256或者1024X1024等其他大小的水印图片
在这里插入图片描述

水印占比: 水印图片中间文字或logo在整图中的占比情况也会对水印密度有影响
在这里插入图片描述

地图缩放级别: 由于水印加载是在瓦片上进行的, 地图等级越小, 瓦片越密集, 导致水印显示更密集, 可以通过控制水印图层的最大缩放比例调节水印密度

方案三: 数据层实现(主要针对栅格瓦片)

在生成栅格切片时, 对栅格切片加上水印, 实际上就是对图片和水印图片的叠加处理, 可以切片完成后写个批处理程序, 对所有切片图片进行水印叠加处理, 目前尚未具体实施.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1145910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NTRU 加密方案

参考文献&#xff1a; [Rivest97] Rivest R L. All-or-nothing encryption and the package transform[C]//Fast Software Encryption: 4th International Workshop, FSE’97 Haifa, Israel, January 20–22 1997 Proceedings 4. Springer Berlin Heidelberg, 1997: 210-218.[…

云安全-云原生技术架构(Docker逃逸技术-特权与危险挂载)

0x00 云原生技术-docker docker容器和虚拟机的对比&#xff1a;前者是将运行环境打包&#xff0c;封装一个环境。后者是将整个系统打包&#xff0c;封装一个系统。在操作使用上来说各有利弊。 0x01 docker容器的三种逃逸类型 特权模式启动&#xff08;不安全的启动方式&…

Qt5.15:MinGW64位编译Oracle 19c数据库驱动及代码测试 - 安装时没有选Sources处理办法

文章目录 0 代码仓库1 环境以及条件说明2 准备一&#xff1a;下载Oracle 19c驱动&#xff0c;需要下载两个包&#xff0c;注意分x86和x642.1 32位2.2 64位2.3 新建目录并解压缩2.4 记录路径2.4.1 x86需要的路径2.4.2 x64需要的路径 3 准备二&#xff1a;下载Sources源代码的两种…

毅速丨金属3D打印能替代传统制造吗?

金属3D打印技术已经逐渐被很多行业认可和应用&#xff0c;但是目前&#xff0c;金属3D打印多数被作为传统制造技术的一种补充&#xff0c;暂时还不能完全替代传统制造。 金属3D打印使用的是金属粉末进行选择性激光烧结&#xff0c;打印时在成型缸里铺上金属粉末&#xff0c;打印…

【刷题宝典NO.1】

Nim游戏 https://leetcode.cn/problems/nim-game/description/ 你和你的朋友&#xff0c;两个人一起玩 Nim 游戏&#xff1a; 桌子上有一堆石头。 你们轮流进行自己的回合&#xff0c; 你作为先手 。 每一回合&#xff0c;轮到的人拿掉 1 - 3 块石头。 拿掉最后一块石头的人…

替换所有的问号

这篇也是凑数的 哈哈.... 稍后会整合到算法通关第三关白银挑战 . 描述 : 给你一个仅包含小写英文字母和 ? 字符的字符串 s&#xff0c;请你将所有的 ? 转换为若干小写字母&#xff0c;使最终的字符串不包含任何 连续重复 的字符。 注意 : 不能 修改非 ? 字符 . 题目 : …

分类预测 | MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双向门控循环单元数据分类预测

分类预测 | MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双向门控循环单元数据分类预测 目录 分类预测 | MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双向门控循环单元数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双…

【计算机视觉】3D视觉

文章目录 一、基本问题二、三个坐标系 X w \boldsymbol{X}_w Xw​到 X c \boldsymbol{X}_c Xc​的转换 X c \boldsymbol{X}_c Xc​到 x i \boldsymbol{x}_i xi​的转换投影矩阵尺度模糊问题 三、相机标定四、立体视觉 我的《计算机视觉》系列参考UC Berkeley的CS180课程&#x…

JDK21下载和安装

说明 本文介绍 JDK21&#xff08;Oracle版&#xff09;的下载和安装。 下载 Oracle官网JDK21下载页面 根据操作系统的类型&#xff0c;下载相应的版本。本文下载的是Windows64位的安装版。 下载页面示例 安装包示例 安装 双击安装包&#xff0c;开始安装。 把路径改为自定…

【数据结构】数组和字符串(八):稀疏矩阵的链接存储:十字链表的创建、插入元素、遍历打印(按行、按列、打印矩阵)、销毁

文章目录 4.2.1 矩阵的数组表示4.2.2 特殊矩阵的压缩存储a. 对角矩阵的压缩存储b~c. 三角、对称矩阵的压缩存储d. 稀疏矩阵的压缩存储——三元组表4.2.3三元组表的转置、加法、乘法、操作4.2.4十字链表0. 十字链表结构1. 创建2. 销毁3. 插入4. 打印矩阵形式5. 按行打印6.按列打…

京东平台数据分析(京东销量):2023年9月京东吸尘器行业品牌销售排行榜

鲸参谋监测的京东平台9月份吸尘器市场销售数据已出炉&#xff01; 根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;今年9月&#xff0c;京东吸尘器的销量为19万&#xff0c;环比下滑约12%&#xff0c;同比下滑约25%&#xff1b;销售额为1.2亿&#xff0c;环比下滑约11%&…

刀具磨损状态识别(Python代码,MSCNN_LSTM_Attention模型,初期磨损、正常磨损和急剧磨损分类,解压缩直接运行)

1.运行效果&#xff1a;刀具磨损状态识别&#xff08;Python代码&#xff0c;MSCNN_LSTM_Attention模型&#xff0c;初期磨损、正常磨损和急剧磨损&#xff09;_哔哩哔哩_bilibili 环境库&#xff1a; NumPy 版本: 1.19.4 Pandas 版本: 0.23.4 Matplotlib 版本: 2.2.3 Keras …

【Qt之控件QTreeView】设置单元格高度、设置图标尺寸

设置列宽 设置高度 自定义代理 继承QItemDelegate&#xff0c;实现sizeHint ()方法&#xff0c;设置自定义委托。 class itemDelegate : public QItemDelegate {Q_OBJECTpublic:explicit itemDelegate(QObject *parent 0) : QItemDelegate(parent){}~itemDelegate(){}virtua…

策略路由和路由策略

目录 策略路由 路由策略 策略路由和路由策略 策略路由 Step1:配置ACL&#xff0c;匹配流量 acl number 2010 rule 10 permit source 192.168.10.0 0.0.0.255 acl number 2020 rule 10 permit source 192.168.20.0 0.0.0.255 Step2:流分类traffic classifier jiaoxue //匹配…

Navicat for MySQL 视图创建使用方法

创建视图步骤&#xff1a; 点击新建&#xff1b;选择视图&#xff1b;点击视图创建工具&#xff1b;可以在左侧拖拽表到工作区&#xff1b;选择表字段进行连线

二维码智慧门牌管理系统升级,解决地址要素挂接难题!

文章目录 前言一、传统问题和新解决方案二、多样化应用三、实际案例 前言 随着科技的不断发展&#xff0c;智能化管理已经深入到各行各业。在地址要素采集过程中&#xff0c;如何实现要素之间的挂接关系&#xff0c;是智慧门牌管理系统面临的重要挑战。本文将为您揭秘一种升级…

【错误解决方案】ModuleNotFoundError: No module named ‘cPickle‘

1. 错误提示 在python程序中试图导入一个名为cPickle的模块&#xff0c;但Python提示找不到这个模块。 错误提示&#xff1a;ModuleNotFoundError: No module named cPickle 2. 解决方案 实际上&#xff0c;cPickle是Python的pickle模块的一个C语言实现&#xff0c;通常用于…

【ROS入门】机器人导航(仿真)——导航实现

文章结构 建图 SLAM编写gmapping节点相关launch文件执行 地图服务 map_server地图保存节点 map_server地图服务 map_server 定位 amcl编写amcl节点相关的launch文件编写测试launch文件执行 路径规划 move_basemove_base与代价地图碰撞算法 move_base使用launch文件配置文件laun…

Selenium自动测试框架

selenium3 selenium元素的定位css 选择器Xpath 操作测试对象 API添加等待浏览器的操作键盘操作鼠标操作定位一组元素下拉框弹窗上传文件 <dependencies><!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --><dependency><…

phar反序列化学习

PHP反序列化常见的是使用unserilize()进行反序列化&#xff0c;除此之外还有其它的反序列化方法&#xff0c;不需要用到unserilize()。就是用到phar反序列化。 Phar phar文件 Phar是将php文件打包而成的一种压缩文档&#xff0c;类似于Java中的jar包。它有一个特性就是phar文…