hookehuyr

✨ feat: 最后切出来的图片,按照实际图片在瓦片的位置,而不是填充满瓦片的长宽

...@@ -47,14 +47,6 @@ function sliceImageToTiles(image, bounds, zoomLevel) { ...@@ -47,14 +47,6 @@ function sliceImageToTiles(image, bounds, zoomLevel) {
47 tileStartY = Math.min(tileStartY, tileEndY); 47 tileStartY = Math.min(tileStartY, tileEndY);
48 tileEndY = Math.max(tileStartY, tileEndY); 48 tileEndY = Math.max(tileStartY, tileEndY);
49 49
50 - // console.warn(`瓦片编号: X(${tileStartX} -> ${tileEndX}), Y(${tileStartY} -> ${tileEndY})`);
51 -
52 - const cols = tileEndX - tileStartX + 1;
53 - const rows = tileEndY - tileStartY + 1;
54 -
55 - const tileWidth = imgWidth / cols;
56 - const tileHeight = imgHeight / rows;
57 -
58 const scaleFactor = 2; // 调高分辨率倍率 50 const scaleFactor = 2; // 调高分辨率倍率
59 51
60 canvas.width = tileSize * scaleFactor; 52 canvas.width = tileSize * scaleFactor;
...@@ -66,39 +58,50 @@ function sliceImageToTiles(image, bounds, zoomLevel) { ...@@ -66,39 +58,50 @@ function sliceImageToTiles(image, bounds, zoomLevel) {
66 58
67 let tileIndex = 0; // 瓦片索引,用来给每个瓦片命名 59 let tileIndex = 0; // 瓦片索引,用来给每个瓦片命名
68 60
69 - for (let x = 0; x < cols; x++) { 61 + // 计算每个瓦片的经纬度范围
70 - for (let y = 0; y < rows; y++) { 62 + for (let tileX = tileStartX; tileX <= tileEndX; tileX++) {
71 - ctx.clearRect(0, 0, tileSize, tileSize); 63 + for (let tileY = tileStartY; tileY <= tileEndY; tileY++) {
72 - 64 + // 计算当前瓦片的经纬度范围
73 - ctx.drawImage( 65 + const tileLonStart = tileX * 360 / Math.pow(2, zoomLevel) - 180;
74 - image, 66 + const tileLonEnd = (tileX + 1) * 360 / Math.pow(2, zoomLevel) - 180;
75 - x * tileWidth, y * tileHeight, tileWidth, tileHeight, // 源图像区域 67 + const tileLatStart = Math.atan(Math.sinh(Math.PI * (1 - 2 * (tileY + 1) / Math.pow(2, zoomLevel)))) * 180 / Math.PI;
76 - 0, 0, tileSize, tileSize // 目标画布区域 68 + const tileLatEnd = Math.atan(Math.sinh(Math.PI * (1 - 2 * tileY / Math.pow(2, zoomLevel)))) * 180 / Math.PI;
77 - ); 69 +
78 - 70 + // 计算图片在当前瓦片中的位置和尺寸
79 - canvas.toBlob((blob) => { 71 + const tileImgX = (lonStart - tileLonStart) / (tileLonEnd - tileLonStart) * tileSize;
80 - if (!blob) { 72 + const tileImgY = (tileLatEnd - latEnd) / (tileLatEnd - tileLatStart) * tileSize;
81 - console.error("瓦片转换失败!"); 73 + const tileImgWidth = (lonEnd - lonStart) / (tileLonEnd - tileLonStart) * tileSize;
82 - return; 74 + const tileImgHeight = (latEnd - latStart) / (tileLatEnd - tileLatStart) * tileSize;
83 - } 75 +
84 - const tileX = tileStartX + x; 76 + ctx.clearRect(0, 0, tileSize * scaleFactor, tileSize * scaleFactor);
85 - const tileY = tileStartY + y; 77 +
86 - // console.warn(`保存瓦片: ${tileX}_${tileY}_${zoomLevel}.png`); 78 + // 根据图片在瓦片中的实际位置和尺寸绘制
87 - // saveTile(blob, `${tileX}_${tileY}_${zoomLevel}.png`); 79 + ctx.drawImage(
88 - 80 + image,
89 - // 获取当前北京时间(UTC+8) 81 + 0, 0, imgWidth, imgHeight, // 源图像区域(使用完整图片)
90 - const beijingTime = dayjs().add(8, "hour").toDate(); 82 + tileImgX, tileImgY, tileImgWidth, tileImgHeight // 目标画布区域(保持实际位置和比例)
91 - 83 + );
92 - // 使用 JSZip 将每个瓦片添加到压缩包中 84 +
93 - zip.file(`${tileX}_${tileY}_${zoomLevel}.png`, blob, { date: beijingTime }); 85 + canvas.toBlob((blob) => {
94 - tileIndex++; 86 + if (!blob) {
95 - 87 + console.error("瓦片转换失败!");
96 - // 如果所有瓦片都处理完,生成并下载压缩包 88 + return;
97 - if (tileIndex === cols * rows) { 89 + }
98 - generateAndDownloadZip(zip, zoomLevel); 90 +
99 - } 91 + // 获取当前北京时间(UTC+8)
100 - }, "image/png", 1.0); 92 + const beijingTime = dayjs().add(8, "hour").toDate();
101 - } 93 +
94 + // 使用 JSZip 将每个瓦片添加到压缩包中
95 + zip.file(`${tileX}_${tileY}_${zoomLevel}.png`, blob, { date: beijingTime });
96 + tileIndex++;
97 +
98 + // 如果所有瓦片都处理完,生成并下载压缩包
99 + const totalTiles = (tileEndX - tileStartX + 1) * (tileEndY - tileStartY + 1);
100 + if (tileIndex === totalTiles) {
101 + generateAndDownloadZip(zip, zoomLevel);
102 + }
103 + }, "image/png", 1.0);
104 + }
102 } 105 }
103 } 106 }
104 // 经纬度转换为瓦片坐标 107 // 经纬度转换为瓦片坐标
......