tiler icon indicating copy to clipboard operation
tiler copied to clipboard

下载后切片镶嵌是否有相关工具呀

Open githublask opened this issue 1 year ago • 3 comments

下载后切片镶嵌是否有相关工具呀,或者您是怎么后续处理镶嵌的

githublask avatar Jul 15 '24 01:07 githublask

木有,后续可以考虑搞个小工具

atlasdatatech avatar Aug 23 '24 06:08 atlasdatatech

是拼图吗?我用go写了一个,但是和你的机理稍微有点区别,我发给你看看能否改改支持你的拼接?

3xxx avatar Jul 30 '25 09:07 3xxx

我用Trae AI编辑器很快就写好了几个拼图的程序。

package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	_ "image/gif"
	_ "image/jpeg" // 坑:这里一定要引入这个才能解析jpeg格式的图片!!!即使不需要,也要这样引入_ "image/jpeg"
	"image/png"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

// Tile 表示单个瓦片
type Tile struct {
	Z, X, Y int
	Img     image.Image
}

func main() {
	// 命令行参数
	currentDir, err := os.Getwd()
	if err != nil {
		return
	}
	baseDir := flag.String("dir", currentDir, "瓦片存储根目录")
	outputFile := flag.String("combineinpath", "combininpath.png", "输出文件名")
	zoom := flag.Int("zoom", -1, "指定缩放层级,默认为-1(自动检测所有层级)")
	flag.Parse()

	// 验证输入
	if _, err := os.Stat(*baseDir); os.IsNotExist(err) {
		fmt.Printf("错误: 目录 %s 不存在\n", *baseDir)
		os.Exit(1)
	}

	// 读取瓦片

	tiles, err := readTiles(*baseDir, *zoom)
	// fmt.Print(tiles)
	if err != nil {
		fmt.Printf("读取瓦片失败: %v\n", err)
		os.Exit(1)
	}

	if len(tiles) == 0 {
		fmt.Println("没有找到瓦片")
		os.Exit(1)
	}

	// 确定缩放层级
	currentZoom := tiles[0].Z
	for _, tile := range tiles {
		if tile.Z != currentZoom {
			fmt.Println("错误: 发现多个缩放层级的瓦片,请使用-zoom参数指定一个层级")
			os.Exit(1)
		}
	}

	// 拼接瓦片resultImg
	resultImg, err := stitchTiles(tiles)
	if err != nil {
		fmt.Printf("拼接瓦片失败: %v\n", err)
		os.Exit(1)
	}

	// 保存结果
	if err := saveImage(resultImg, *outputFile); err != nil {
		fmt.Printf("保存图像失败: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("成功拼接瓦片并保存到 %s\n", *outputFile)
}

// readTiles 读取指定目录下的所有瓦片
func readTiles(baseDir string, targetZoom int) (tiles []Tile, err error) {
	// var tiles []Tile

	// 遍历目录
	err = filepath.Walk(baseDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// fmt.Printf(path)

		// 跳过目录
		if info.IsDir() {
			return nil
		}

		// 检查文件是否为PNG
		if !strings.HasSuffix(strings.ToLower(path), ".png") {
			// fmt.Printf(path)
			return nil
		}

		// 解析路径获取z, x, y
		relPath, err := filepath.Rel(baseDir, path)
		if err != nil {
			return err
		}

		parts := strings.Split(relPath, string(filepath.Separator))
		if len(parts) < 3 {
			return nil // 路径不符合z/x/y.png格式
		}
		// fmt.Printf(parts[1])
		// 解析z, x, y
		z, err := strconv.Atoi(parts[0])
		if err != nil {
			return nil
		}

		// 如果指定了缩放层级,则只处理该层级
		if targetZoom != -1 && z != targetZoom {
			return nil
		}

		x, err := strconv.Atoi(parts[1])
		if err != nil {
			return nil
		}

		// 去除文件扩展名
		yStr := strings.TrimSuffix(parts[2], ".png")
		y, err := strconv.Atoi(yStr)
		if err != nil {
			fmt.Print(tiles)
			return nil
		}

		// 读取图像
		img, err := loadImage(path)
		if err != nil {
			fmt.Printf("警告: 无法读取图像 %s: %v\n", path, err)
			return nil
		}

		// 添加到瓦片列表
		tiles = append(tiles, Tile{
			Z:   z,
			X:   x,
			Y:   y,
			Img: img,
		})
		// fmt.Print(tiles)
		return nil
	})
	// fmt.Print(tiles)
	return tiles, err
}

// loadImage 加载图像文件
func loadImage(path string) (image.Image, error) {
	file, err := os.Open(path)
	if err != nil {
		// fmt.Print(err)
		return nil, err
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	// fmt.Print(err)
	return img, err
}

// stitchTiles 拼接瓦片
func stitchTiles(tiles []Tile) (image.Image, error) {
	if len(tiles) == 0 {
		return nil, fmt.Errorf("瓦片列表为空")
	}

	// 确定瓦片尺寸(假设所有瓦片大小相同)
	tileWidth := tiles[0].Img.Bounds().Dx()
	tileHeight := tiles[0].Img.Bounds().Dy()

	// 找出X和Y的最小和最大值
	minX, maxX := tiles[0].X, tiles[0].X
	minY, maxY := tiles[0].Y, tiles[0].Y

	for _, tile := range tiles {
		if tile.X < minX {
			minX = tile.X
		}
		if tile.X > maxX {
			maxX = tile.X
		}
		if tile.Y < minY {
			minY = tile.Y
		}
		if tile.Y > maxY {
			maxY = tile.Y
		}
	}

	// 计算输出图像的尺寸
	width := (maxX - minX + 1) * tileWidth
	height := (maxY - minY + 1) * tileHeight

	// 创建输出图像
	resultImg := image.NewRGBA(image.Rect(0, 0, width, height))
	bgColor := color.White
	draw.Draw(resultImg, resultImg.Bounds(), &image.Uniform{bgColor}, image.Point{}, draw.Src)

	// 绘制每个瓦片到正确的位置
	for _, tile := range tiles {
		xOffset := (tile.X - minX) * tileWidth
		yOffset := (tile.Y - minY) * tileHeight

		draw.Draw(resultImg,
			image.Rect(xOffset, yOffset, xOffset+tileWidth, yOffset+tileHeight),
			tile.Img,
			image.Point{},
			draw.Over)
	}

	return resultImg, nil
}

// saveImage 保存图像到文件
func saveImage(img image.Image, filePath string) error {
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	return png.Encode(file, img)
}

3xxx avatar Aug 03 '25 14:08 3xxx