go gui 序列帧图片合成

641 阅读1分钟

go gui 序列帧图片合成

合图的工具是早些时候写的,当时是为了做传奇类游戏素材打包用的,把多张图片合成,并输出plist,其实就是做序列帧动画的,今天把这个核心的代码分享下。

工具简介

刚开始做的时候是一个nogui,命令行处理的,把要合成的目录,输出目录填进去就就可以合成,在后来用go-walk做了个gui,大概就是下面这样子,

image-20230816175359103.png

合图思路

外观地址就是要合成的图片的目录,或者可以用拖拽把其中一张素材拖进去,就可以识别目录。

1,定义一个 10000*10000的画布
newImg := image.NewNRGBA(image.Rect(0, 0, 10000, 10000)) //创建一个新RGBA图像
2,根据图片的数量,尽量是布局成类似9宫格那样子,横竖图片数量一样,计算下x,y 方向的最大值
func getMaxCountXY(sum int) (int, int) {
	f := float64(sum)
	ff := math.Sqrt(f)
	x := int(math.Round(ff))
	y := int(ff + 1)
	return x, y
}
3,把图片依次绘制到画布上,记录每一张图片的Plist信息
	for i := 0; i < my; i++ {

		temp_arr := make([]entity.ImgBean, mx)
		if i == my-1 { //最后一行
			temp_arr = img_array[0:]
		} else {
			temp_arr = img_array[0:mx] //每行的图片数量
			img_array = img_array[mx:]
		}
		temp_h := 0
		temp_w := 0
		for k, v := range temp_arr {
			v.X = temp_w * 1          //x便宜
			v.Y = line_max_height * 1 //y 偏移

			//拼图
			draw.Draw(newImg, newImg.Bounds(), v.Img, image.Pt(v.X*-1, v.Y*-1), draw.Over) 
			p := &entity.Plist{v.FileName, v.X, v.Y, v.Img.Bounds().Max.X, v.Img.Bounds().Max.Y, 0, 0}
			ps[i*mx+k] = p

			//计算本行的最大高度
			if v.Img.Bounds().Max.Y > temp_h {
				temp_h = v.Img.Bounds().Max.Y
			}
			temp_w += v.Img.Bounds().Max.X //累计行宽
		}
		if temp_w > max_x { //计算最大宽度
			max_x = temp_w
		}
		line_max_height += temp_h
	}
4,最后输出图片
png.Encode(outFile, newImg.SubImage(image.Rect(0, 0, max_x, line_max_height)))
完整合图代码
func Marge_res_any(p_dir string, p_out string) []*entity.Plist {

	log.Println("out file :" + p_out)
	//读文件列表
	fs, _ := ioutil.ReadDir(p_dir)
	mx, my := getMaxCountXY(len(fs))
	//图的集合
	img_array := make([]entity.ImgBean, 0)

	//判断输出文件是否存在

	outFile, _ := os.Create(p_out)
	defer outFile.Close()

	//填文件,计算目标图片位置

	for i, f := range fs {
		if f.IsDir() {
			continue
		}
		b := entity.ImgBean{}
		b.FileName = f.Name()
		b.Img = getImg(p_dir + "/" + f.Name())
		b.X = i % mx
		b.Y = i / mx
		img_array = append(img_array, b)
		//img_array[i]=b
	}
	ps := make([]*entity.Plist, len(img_array))

	line_max_height := 0
	max_x := 0

	newImg := image.NewNRGBA(image.Rect(0, 0, 10000, 10000)) //创建一个新RGBA图像
	for i := 0; i < my; i++ {

		temp_arr := make([]entity.ImgBean, mx)
		if i == my-1 { //最后一行
			temp_arr = img_array[0:]
		} else {
			temp_arr = img_array[0:mx] //每行的图片数量
			img_array = img_array[mx:]
		}
		temp_h := 0
		temp_w := 0
		for k, v := range temp_arr {
			v.X = temp_w * 1          //x 偏移
			v.Y = line_max_height * 1 //y 偏移

			//拼图
			draw.Draw(newImg, newImg.Bounds(), v.Img, image.Pt(v.X*-1, v.Y*-1), draw.Over)
			p := &entity.Plist{v.FileName, v.X, v.Y, v.Img.Bounds().Max.X, v.Img.Bounds().Max.Y, 0, 0}
			ps[i*mx+k] = p

			//计算本行的最大高度
			if v.Img.Bounds().Max.Y > temp_h {
				temp_h = v.Img.Bounds().Max.Y
			}
			temp_w += v.Img.Bounds().Max.X //累计行宽
		}
		if temp_w > max_x { //计算最大宽度
			max_x = temp_w
		}
		line_max_height += temp_h
	}
	//fmt.Println(max_x,line_max_height)

	png.Encode(outFile, newImg.SubImage(image.Rect(0, 0, max_x, line_max_height)))

	//fmt.Println("OK")
	return ps
}