TileCutter.js
3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
* @Date: 2025-01-22 11:45:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-01-23 16:38:00
* @FilePath: /map-demo/src/utils/TileCutter.js
* @Description: 文件描述
*/
const tileSize = 512;
export function TileCutter(imageURL, bounds, zoomLevel) {
const img = new Image();
img.crossOrigin = "Anonymous"; // 避免跨域问题
img.src = imageURL;
img.onload = () => {
sliceImageToTiles(img, bounds, zoomLevel);
};
}
function sliceImageToTiles(image, bounds, zoomLevel) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const imgWidth = image.width;
const imgHeight = image.height;
const southWest = bounds.getSouthWest();
const northEast = bounds.getNorthEast();
const lonStart = southWest.lng;
const latStart = southWest.lat;
const lonEnd = northEast.lng;
const latEnd = northEast.lat;
let tileStartX = lonToTileX(lonStart, zoomLevel);
let tileEndX = lonToTileX(lonEnd, zoomLevel);
let tileStartY = latToTileY(latEnd, zoomLevel); // 取 latEnd 作为起点
let tileEndY = latToTileY(latStart, zoomLevel); // 取 latStart 作为终点
// 确保 tileStartX <= tileEndX,tileStartY <= tileEndY
tileStartX = Math.min(tileStartX, tileEndX);
tileEndX = Math.max(tileStartX, tileEndX);
tileStartY = Math.min(tileStartY, tileEndY);
tileEndY = Math.max(tileStartY, tileEndY);
// console.warn(`瓦片编号: X(${tileStartX} -> ${tileEndX}), Y(${tileStartY} -> ${tileEndY})`);
const cols = tileEndX - tileStartX + 1;
const rows = tileEndY - tileStartY + 1;
const tileWidth = imgWidth / cols;
const tileHeight = imgHeight / rows;
const scaleFactor = 2; // 调高分辨率倍率
canvas.width = tileSize * scaleFactor;
canvas.height = tileSize * scaleFactor;
ctx.scale(scaleFactor, scaleFactor);
for (let x = 0; x < cols; x++) {
for (let y = 0; y < rows; y++) {
ctx.clearRect(0, 0, tileSize, tileSize);
ctx.drawImage(
image,
x * tileWidth, y * tileHeight, tileWidth, tileHeight, // 源图像区域
0, 0, tileSize, tileSize // 目标画布区域
);
canvas.toBlob((blob) => {
if (!blob) {
console.error("瓦片转换失败!");
return;
}
const tileX = tileStartX + x;
const tileY = tileStartY + y;
// console.warn(`保存瓦片: ${tileX}_${tileY}_${zoomLevel}.png`);
saveTile(blob, `${tileX}_${tileY}_${zoomLevel}.png`);
}, "image/png", 1.0);
}
}
}
// 经纬度转换为瓦片坐标
function lonToTileX(lon, zoom) {
return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom));
}
function latToTileY(lat, zoom) {
return Math.floor(
((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2) * Math.pow(2, zoom)
);
}
function saveTile(blob, filename) {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}