go wails 合图工具 plist

535 阅读1分钟

go wails 合图工具

今天把前面 go-walk 做的合图工具用 wails 写下,合并图片的主要逻辑不变,主要是界面上的。

主要的三个功能

1,合成图片自选

2,合成结果预览,自定义缩放查看

3,合成图片导出

创建项目

wails 命令直接创建一个wails vue 的项目

前端展示的界面如下

image-20230824184622281.png

左侧,打开文件,导出文件的按钮,一个控制缩放的拉条

右侧是展示合成的预览

合成预览的逻辑

1.用户选择图片,然后Go程序拿到选择的文件,进行图片合成,并且计算出每个图片相对左上角的坐标

2.把选择并计算的结果,返回给界面,界面拿到图片链接,图片位置坐标,展示合成的效果

3.可拖动slider 进行缩放,查看效果

4.用户可以点击导出,弹出选择导出的目录,点击确定导出,自动打开导出目录

合成的结果

image-20230824185444088.png

Go选择文件,计算位置并返回结果
func (a *MergeRes) OpenFileDlg() (position []entity.Plist) {
	opts := runtime.OpenDialogOptions{}
	filePath, err := runtime.OpenMultipleFilesDialog(a.ctx, opts)
	if err != nil {
		log.Println(err.Error())
		return nil
	}

	plist := imageMarge.MargeResAny(filePath, "")

	for k := range plist {
		plist[k].Path = filePath[k]
	}
	return plist
}
Go导出文件,并打开导出目录
func (a *MergeRes) ExportImg(plistInfo []entity.Plist) {
	opts := runtime.OpenDialogOptions{}
	dirPath, err := runtime.OpenDirectoryDialog(a.ctx, opts)
	if err != nil {
		log.Println(err.Error())
		return
	}
	files := make([]string, 0)
	for _, v := range plistInfo {
		files = append(files, v.Path)
	}

	randomFileName := time.Now().Format("20060102150405.png")
	_ = imageMarge.MargeResAny(files, dirPath+"\\"+randomFileName)
	openDir(dirPath)
}

func openDir(dirPath string) {
	cmd := exec.Command("cmd.exe", "/c", "start "+dirPath)
	err := cmd.Start() //如果用start则直接向后运行
	if err != nil {
		log.Fatal(err)
	}
}
预览合成结果,calcStyle 是动态缩放的样式
    <div class="right">
       <div class="imgview" :style="calcStyle">
				<div v-for="(item, index) in imgList"  :key="index" class="img-item-div" :style='{width:item.Width+"px",height:item.Height+"px",top:item.Y+"px",left:item.X+"px"}' >
					<Image :src="item.Url" fit="contain" />
				</div>
			 </div>
    </div>
// 定义
calcStyle:{
	transform:'scale(1)'
},
// 更新
onScaleChange(){
    this.calcStyle={
    	transform:`scale(${this.imgViewScale/100})`
    }
},
go完整代码

合成图片的代码参考 juejin.cn/post/726778…

type MergeRes struct {
	ctx context.Context
}

func NewMergeRes() *MergeRes {
	return &MergeRes{}
}

func (a *MergeRes) SetContext(ctx context.Context) {
	a.ctx = ctx
}

func (a *MergeRes) CloseApp() {
	// 解绑所有事件
	runtime.EventsOffAll(a.ctx)
	// 退出系统
	os.Exit(0)
}

func (a *MergeRes) OpenFileDlg() (position []entity.Plist) {
	opts := runtime.OpenDialogOptions{}
	filePath, err := runtime.OpenMultipleFilesDialog(a.ctx, opts)
	if err != nil {
		log.Println(err.Error())
		return nil
	}

	plist := imageMarge.MargeResAny(filePath, "")

	for k := range plist {
		plist[k].Path = filePath[k]
	}
	return plist
}

func (a *MergeRes) GetPosition(files []string) []entity.Plist {

	plist := imageMarge.MargeResAny(files, "")
	return plist
}

func (a *MergeRes) ExportImg(plistInfo []entity.Plist) {
	opts := runtime.OpenDialogOptions{}
	dirPath, err := runtime.OpenDirectoryDialog(a.ctx, opts)
	if err != nil {
		log.Println(err.Error())
		return
	}
	files := make([]string, 0)
	for _, v := range plistInfo {
		files = append(files, v.Path)
	}

	randomFileName := time.Now().Format("20060102150405.png")
	_ = imageMarge.MargeResAny(files, dirPath+"\\"+randomFileName)
	openDir(dirPath)
}

func openDir(dirPath string) {
	cmd := exec.Command("cmd.exe", "/c", "start "+dirPath)
	err := cmd.Start() //如果用start则直接向后运行
	if err != nil {
		log.Fatal(err)
	}
}

界面文件如下
<template>
<div class="imgMergeApp">
  <div class="top">
    <div class="tool-bar" style="--wails-draggable: drag">
			<div class="title">
				<img :src="iconUrl" style="width: 16px; height: 16px" />
				{{ name }}
			</div>
			<div class="tool-btn">
				<div style="cursor: pointer" @click="fullScreen">
					<Icon type="md-expand" />
				</div>
				<div style="cursor: pointer" @click="closeApp">
					<Icon type="md-power" />
				</div>
			</div>
		</div>
  </div>
  <div class="bottom" >
    <div class="left">
				<div>
					<Space>
						<Button size="small" type="default" @click="openFile" >打开</Button>
						<Button size="small" type="default" @click="exportImg" >导出</Button>
					</Space>
				</div>
        <div>
					<Input v-model="fileDir" size="small" />
				</div>
				<div>
					<Slider v-model="imgViewScale" @on-input="onScaleChange"></Slider>
				</div>
    </div>
    <div class="right">
       <div class="imgview" :style="calcStyle">
				<div v-for="(item, index) in imgList"  :key="index" class="img-item-div" :style='{width:item.Width+"px",height:item.Height+"px",top:item.Y+"px",left:item.X+"px"}' >
					<Image :src="item.Url" fit="contain" />
					<!-- <p>{{ item }}</p> -->
				</div>
			 </div>
    </div>
  </div>
</div>

</template>
<script lang="js">
import { WindowSetSize, WindowToggleMaximise } from "../../wailsjs/runtime/runtime";
import iconUrl from "../assets/images/logo-universal.png";
import { CloseApp, OpenFileDlg,ExportImg} from "../../wailsjs/go/api/MergeRes";
  export default {
    name:"",
    data(){
      return {
        name: "图片合成Plist",
        iconUrl: iconUrl,
				winsSize: {
					w: 800,
					h: 630,
				},
				fileDir:"",
				imgList:[],
				calcStyle:{
					transform:'scale(1)'
				},
				imgViewScale:100,
      }
    },
		mounted() {
			WindowSetSize(this.winsSize.w, this.winsSize.h);
		},
    methods:{
			fullScreen() {
				WindowToggleMaximise();
			},
			closeApp() {
				CloseApp();
			},
			onScaleChange(){
				this.calcStyle={
					transform:`scale(${this.imgViewScale/100})`
				}
			},
			openFile() {
				this.imgList=[]
				OpenFileDlg().then((res) => {
					res.forEach((ele) => {
						let imgFile = ele.Path
						imgFile = imgFile.replace(":", "");
						imgFile = "/" + imgFile.split("\\").join("/");
						ele.Url = imgFile
						this.imgList.push(ele);
					});
				});
			},
			exportImg(){
				ExportImg(this.imgList)
			}
    }
  }
</script>
<style scoped>
	#imgMergeApp {
		height: 100%;
		width: 100%;
		background: none;
	}
  .top{
    height: 30px;
  }

	.tool-bar {
		font-size: 12px;
		color: #000;
		font-weight: 500;
		padding: 0px 9px;
		display: flex;
		background: #fff;
		justify-content: space-between;
		align-items: center;
		height: 30px;
	}
	.tool-btn {
		display: flex;
	}
	.tool-btn div {
		margin-left: 5px;
		font-size: 18px;
	}
	.title {
		display: flex;
		justify-content: space-between;
		justify-items: center;
	}

  .bottom{
    height: calc( 100vh - 30px );
    width: 100%;
    display: flex;
  }
  .bottom .left{
    width: 200px;
    height: 100%;
		padding: 0 10px;
		padding-top: 20px;
		text-align: left;
		border-right: 1px #fff solid;

  }
	.bottom .left>div{
		margin-top: 5px;
	}
  .right{
    flex: 1;
    height: 100%;
		overflow: auto;
  }
	.imgview{
		position: relative;
		transform-origin: left top;
	}
	.img-item-div{
		position: absolute;
	}
</style>