---
title: 「JavaScript」将 Dynmap 网页上的地图图片合成为一张图
date: 2025-03-16T16:24:15Z
lastmod: 2025-03-16T16:26:41Z
tags: [Minecraft,JavaScript,Dynmap,Web 前端,代码片段]
---

# 「JavaScript」将 Dynmap 网页上的地图图片合成为一张图

游戏版本：Minecraft Java Edition 1.12.2

已测试 Dynmap 版本：3.0

---

## 简介

根据我的 Minecraft 服务器的一位玩家的需求写的 JavaScript，可自动将 Dynmap 网页上分块的地图图片合成为一张图。建议使用 `Chrome` 浏览器或 `Chromium` 内核的浏览器进行操作。

因为是在 `前端` 进行合成，需要在操作前浏览一次要导出的地图区域。不建议合成过大的区域，否则可能会导致浏览器崩溃。

结果会在新窗口中显示（若不能弹出新窗口，请将 `弹出新窗口` 设置为 `允许`）。

本代码可能并不是最优的方案，欢迎各位在评论区提出建议。

若您是服务器的管理人员，可尝试使用下列插件：

- [Leaflet.print](https://github.com/aratcliffe/Leaflet.print)
- [Leaflet-image](https://github.com/mapbox/leaflet-image)
- [Leaflet-easyPrint](https://github.com/rowanwins/leaflet-easyPrint)
- [leaflet.browser.print](https://github.com/Igor-Vladyka/leaflet.browser.print)
- [Leaflet.BigImage](https://github.com/pasichnykvasyl/Leaflet.BigImage)

## 代码

> 更新：2020-12-23

```javascript
function dataURLtoBlob(dataURL) {
    var arr = dataURL.split(',');
    var mime = arr[0].match(/(:)(.*?)(;)/)[2]; // MIME
    var bStr = atob(arr[1]);                   // 解码
    var bLength = bStr.length;
    var u8Arr = new Uint8Array(bLength);

    while (bLength--) {
        u8Arr[bLength] = bStr.charCodeAt(bLength);
    }

    return new Blob([u8Arr], { type: mime });
}

function exportMap() {
    var base64Data = '';
    var images = document.querySelectorAll('#mcmap .map .leaflet-map-pane .leaflet-tile-pane .leaflet-layer img');
    var imagesCount = images.length;                                 // 图片数量
    var resultWindow = window.open('', '', 'width=800, height=480'); // 新窗口：显示结果

    // 提取 translate3d X Y Z 的值（文本）并转换为数字
    function getTransInfo(elem) {
        var reg = new RegExp(/(translate3d\(|px|\))/, 'g');
        var transInfo = elem.style.transform.replace(reg, '').split(', ').map(Number);

        // X, Y
        return [transInfo[0], transInfo[1]];
    }

    // 获取 Transform 最值信息
    function getTransMax() {
        console.log('获取 Transform 最值信息');

        var image_trans;
        var min_x = 0, min_y = 0, max_x = 0, max_y = 0;

        for (let i = 0; i < imagesCount; i++) {
            image_trans = getTransInfo(images[i]);
            if (image_trans[0] < min_x) {
                min_x = image_trans[0];
                // console.log("min_x 元素：" + i);
            }
            if (image_trans[1] < min_y) {
                min_y = image_trans[1];
                // console.log("min_y 元素：" + i);
            }
            if (image_trans[0] > max_x) {
                max_x = image_trans[0];
                // console.log("max_x 元素：" + i);
            }
            if (image_trans[1] > max_y) {
                max_y = image_trans[1];
                // console.log("max_y 元素：" + i);
            }
        }

        // max 加上图片大小
        max_x += images[0].width;
        max_y += images[0].height;

        return [min_x, min_y, max_x, max_y];
    }

    // 绘制
    function draw(fn) {
        // fn：绘制结束时的回调函数

        console.log("开始绘制");

        var trans_info = getTransMax();
        var canvasElem = document.createElement('canvas');
        var ctx = canvasElem.getContext('2d');

        canvasElem.width = trans_info[2] - trans_info[0];  // 画布元素宽度
        canvasElem.height = trans_info[3] - trans_info[1]; // 画布元素高度

        // 填充画布
        // ctx.rect(0, 0, canvasElem.width, canvasElem.height);
        // ctx.fillStyle = '#FFF';
        // ctx.fill();

        function drawing(n) {
            // n：绘制次数

            if (n < imagesCount) {
                // 自动计算坐标
                var image_trans = getTransInfo(images[n]);
                var pos_x = image_trans[0] + Math.abs(trans_info[0]);
                var pos_y = image_trans[1] + Math.abs(trans_info[1]);

                // console.log('绘制中：' + n + ' / ' + imagesCount);
                // console.log('坐标：' + pos_x + ', ' + pos_y);
                ctx.drawImage(images[n], pos_x, pos_y);

                // 递归
                arguments.callee(n + 1);
            } else {
                console.log('已合成，等待显示图片');

                // base64Data = canvasElem.toDataURL('image/jpeg', 0.8); // JPEG
                base64Data = canvasElem.toDataURL('image/png');          // PNG

                fn();
            }
        }

        drawing(0);
    }

    // 开始
    (function () {
        console.log('开始合成图片');

        draw(function () {
            // 回调函数：显示图片
            console.log('显示图片');
            var blobData = dataURLtoBlob(base64Data);
            var url = URL.createObjectURL(blobData);
            resultWindow.document.write('<img src="' + url + '" />');
            resultWindow.focus();
            console.log('结束');
        });
    })();
}

exportMap();
```

## 使用方式（二选一）

#### 常规方式

1. 在浏览器打开 Dynmap 的页面。
2. 根据需要调整地图的缩放比例（不建议太大）。
3. 打开浏览器的 `开发人员工具`（可使用快捷键 `Ctrl + Shift + I`）。  
    ​![](assets/network-asset-01-20250316162508-3w1fppe.png)  
    **建议将** **​`开发人员工具`​** **设置为独立窗口显示模式，以让网页有更大的显示区域：**

    右上角的三个点 -\> Dock side -\> Unlock info separate window
4. 拖动地图，直至需要导出的地图范围都完成加载。
5. 切换到 `Console`（控制台）标签页，并将上方的 `代码` 粘贴至输入区。  
    ​![](assets/network-asset-02-20250316162508-nz6ede0.png)
6. 按下 `Enter`（回车），等待即可。

#### 对于管理员

- 若您是服务器的管理人员，且对 HTML、CSS、JavaScript 有了解，可将本代码写入到 Dynmap 的网页中（例如：作为点击事件绑定到特定的按钮上）。

‍
