TileCutter.js 3.1 KB
/*
 * @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);
}