|
@@ -0,0 +1,3327 @@
|
|
|
+<template>
|
|
|
+ <!-- 1/2/3/5 -->
|
|
|
+ <el-main ref="el-main" style="background-color: #fafafa;">
|
|
|
+ <template>
|
|
|
+ <div class="content-top">
|
|
|
+ <el-button-group>
|
|
|
+ <el-button type="primary" size="mini" icon="el-icon-document"
|
|
|
+ @click="pickFile()">添加文件</el-button>
|
|
|
+ <el-button type="primary" size="mini" icon="el-icon-folder"
|
|
|
+ @click="pickDir()">添加文件夹</el-button>
|
|
|
+ <el-button type="primary" size="mini" icon="el-icon-delete"
|
|
|
+ @click="clearList()">清空图片</el-button>
|
|
|
+ </el-button-group>
|
|
|
+
|
|
|
+ <el-row type="flex" style="align-items: center;">
|
|
|
+ <div class="set-item">
|
|
|
+ <span class="set-title">保存目录:</span>
|
|
|
+ <el-input :title="handleData.newPath" ref="upload-input" size="mini" @focus="pickPath" placeholder="请选择输出目录" v-model="handleData.newPath" readonly style="width:200px;" prefix-icon="el-icon-folder"></el-input>
|
|
|
+ <el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="打开保存目录">
|
|
|
+ <i class="el-icon-folder-opened" slot="reference" style="padding-left: 5px; cursor: pointer; font-size: 22px; vertical-align: middle;" @click="openFolder()"></i>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-button type="danger" @click="exportImg()" :loading="loading">开始转换</el-button>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="imgList.length == 0" class="upload-area">
|
|
|
+ <div class="file-area" @click="pickFile()" id="drag-jimp">
|
|
|
+ <div>
|
|
|
+ <img src="../assets/image/upload.png" style="width: 220px;"/>
|
|
|
+ <p style="font-size: 16px;">将图片文件拖住至此处,或点击此处选择图片</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="img-content" v-else>
|
|
|
+ <!-- 1、格式转换 2、图片压缩 3、修改dpi-->
|
|
|
+ <template v-if="menuIndex == 1 || menuIndex == 2">
|
|
|
+ <div style="height: calc(100% - 78px);">
|
|
|
+ <vxe-table ref="xTable" show-overflow class="img-table" max-height="100%" empty-text="没有更多数据了!" :row-config="{isCurrent: true, isHover: true}"
|
|
|
+ :edit-config="{trigger: 'click', mode: 'cell'}" :data="imgList" :scroll-y="{enabled: true}">
|
|
|
+ <vxe-column field="name" :title="'文件名'+'(' + imgList.length + ')'" min-width="120"></vxe-column>
|
|
|
+ <!-- <vxe-column field="path" title="缩略图" width="70">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-image style="width: 30px; height: 30px" :src="row.path" fit="contain"></el-image>
|
|
|
+ </template>
|
|
|
+ </vxe-column> -->
|
|
|
+ <vxe-column field="size" title="大小" min-width="100" max-width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span v-if="row.width == 0 && row.height == 0">-</span>
|
|
|
+ <span v-else>{{row.size}}</span>
|
|
|
+ </template>
|
|
|
+ </vxe-column>
|
|
|
+
|
|
|
+ <vxe-column field="width" title="尺寸" min-width="110" max-width="130">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span v-if="row.width == 0 && row.height == 0">{{'加载中 '+row.loadPercent+'%'}}</span>
|
|
|
+ <span v-else>{{row.width + '*' + row.height}}</span>
|
|
|
+ </template>
|
|
|
+ </vxe-column>
|
|
|
+ <vxe-column field="progress" title="进度" min-width="110" max-width="160">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-progress :text-inside="true" :stroke-width="20" :percentage="row.percent"></el-progress>
|
|
|
+ </template>
|
|
|
+ </vxe-column>
|
|
|
+ <vxe-column field="action" title="操作" width="80">
|
|
|
+ <template #default="{ row, rowIndex }">
|
|
|
+ <i class="el-icon-delete cur-pointer" @click="delImgFile(rowIndex)"></i>
|
|
|
+ </template>
|
|
|
+ </vxe-column>
|
|
|
+ </vxe-table>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 3、更改尺寸 5、添加水印 -->
|
|
|
+ <template v-else-if="[3,5].indexOf(menuIndex) > -1">
|
|
|
+ <div class="soft-content">
|
|
|
+ <div class="content-left" style="width: calc(100% - 270px)">
|
|
|
+ <div class="merge-flex">
|
|
|
+ <div class="merge-scroll">
|
|
|
+ <vxe-table fit show-overflow :show-header="false" align="center" height="100%" :row-config="{isCurrent: true, isHover: true, height: 100}"
|
|
|
+ :data="imgList" @cell-click="selectTab">
|
|
|
+ <vxe-column field="name" width="123" show-overflow>
|
|
|
+ <template #default="{ row, rowIndex }">
|
|
|
+ <vxe-button type="text" icon="vxe-icon-close" class="vxebtn-del" @click="delImgFile(rowIndex)"></vxe-button>
|
|
|
+ <el-image style="width: 60px; height: 60px" :src="row.path" fit="contain" :title="row.name"></el-image>
|
|
|
+ <div class="img-mid-progress" v-if="row.percent > 0">
|
|
|
+ <el-progress :percentage="row.percent"></el-progress>
|
|
|
+ </div>
|
|
|
+ <div style="padding: 0 5px; overflow: hidden;white-space: nowrap;text-overflow: ellipsis;" :title="row.name">{{row.name}}</div>
|
|
|
+ </template>
|
|
|
+ </vxe-column>
|
|
|
+ </vxe-table>
|
|
|
+ </div>
|
|
|
+ <div class="merge-content">
|
|
|
+ <div style="width: 100%; height: 100%;">
|
|
|
+ <div id="show-img" class="show-img" style="position:relative;overflow: hidden; width: 100%; height: 100%;">
|
|
|
+ <div style="position: absolute;top: 5px; left: 5px;padding: 0 10px 10px 10px; background: #00000060; color: #fff;font-size: 12px;z-index: 2;">
|
|
|
+ <label>放大:</label>
|
|
|
+ <el-slider v-model="viewScale" class="info-input" :min="0.5" :max="5" :step="0.1"></el-slider>
|
|
|
+ {{viewScale.toFixed(1)}}
|
|
|
+ </div>
|
|
|
+ <img draggable="false" class="result-img" :src="imgSrc"
|
|
|
+ :style="{maxWidth: '80%',maxHeight: '500px', transform: 'rotate('+handleData.rotateValue+'deg) rotateY('+ (handleData.hflip ? '180' : '0') +'deg) rotateX('+ (handleData.vflip ? '180' : '0') +'deg) scale('+viewScale+')'}" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ <div class="content-right" style="width: 260px;">
|
|
|
+ <div class="setting-area">
|
|
|
+ <div class="img-handle">
|
|
|
+ <!-- 3更改尺寸 -->
|
|
|
+ <div v-if="menuIndex == 3">
|
|
|
+ <div class="handle-item">
|
|
|
+ <el-radio-group v-model="handleData.sizeType">
|
|
|
+ <el-radio-button label="1">按比例调整</el-radio-button>
|
|
|
+ <el-radio-button label="2">按尺寸调整</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.sizeType == '1'">
|
|
|
+ <label class="handle-label">缩放比例:</label>
|
|
|
+ <el-input-number size="small" v-model="handleData.scaling" :min="1" :max="500"></el-input-number>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.sizeType == '2'">
|
|
|
+ <label class="handle-label">宽度:</label>
|
|
|
+ <el-input-number size="small" v-model="handleData.width" :min="1" @change="scaleWidthChange"></el-input-number> px
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.sizeType == '2'">
|
|
|
+ <label class="handle-label">高度:</label>
|
|
|
+ <el-input-number size="small" v-model="handleData.height" :min="1" @change="scaleHeightChange"></el-input-number> px
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.sizeType == '2'">
|
|
|
+ <label class="handle-label">锁定比例:</label>
|
|
|
+ <el-checkbox size="small" v-model="handleData.lockScale"></el-checkbox>
|
|
|
+ <span style="font-size: 12px; color: #666;">(原始尺寸{{imgInfo.originalWidth}}:{{imgInfo.originalHeight}})</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 5添加水印 -->
|
|
|
+ <div v-if="menuIndex == 5">
|
|
|
+ <div class="handle-item">
|
|
|
+ <el-radio-group v-model="handleData.watermarkType">
|
|
|
+ <el-radio-button label="1">文字水印</el-radio-button>
|
|
|
+ <el-radio-button label="2">图片水印</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.watermarkType == '1'">
|
|
|
+ <label class="handle-label">水印类型:</label>
|
|
|
+ <el-select size="small" v-model="handleData.watermarkStyle" style="width:150px;">
|
|
|
+ <el-option value="1" label="单个水印"></el-option>
|
|
|
+ <el-option value="2" label="多个水印"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div v-if="handleData.watermarkType == '1'">
|
|
|
+ <div class="handle-item">
|
|
|
+ <label class="handle-label">文字内容:</label>
|
|
|
+ <el-input type="text" v-model="handleData.watermarkValue" size="small" placeholder="请输入文字水印内容" style="width:150px;" @change="handleImg"></el-input>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item">
|
|
|
+ <label class="handle-label">文字样式:</label>
|
|
|
+ <el-color-picker style="vertical-align: middle;" v-model="handleData.watermarkColor" show-alpha @change="handleImg"></el-color-picker>
|
|
|
+ <el-input-number size="small" style="width: 105px;" v-model="handleData.watermarkFont" @change="handleImg" :min="0" :max="200"></el-input-number>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item">
|
|
|
+ <label class="handle-label">旋转角度:</label>
|
|
|
+ <el-input-number size="small" style="width: 140px;" v-model="handleData.rotate" @change="handleImg" ></el-input-number> °
|
|
|
+ </div>
|
|
|
+ <div class="handle-item">
|
|
|
+ <label class="handle-label">文字字体:</label>
|
|
|
+ <el-select size="small" v-model="handleData.fonts" style="width:120px;" @change="handleImg">
|
|
|
+ <el-option v-for="(item,key) in fonts" :key="key" :value="item.path" :label="item.name"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <vxe-button type="text" status="info" icon="vxe-icon-info-circle-fill" @click="$message({message:'文字为中文时,请选择中文字体!', type:'warning'})"></vxe-button>
|
|
|
+ </div>
|
|
|
+ <template v-if="handleData.watermarkStyle == 2">
|
|
|
+ <div class="handle-item" style="overflow: hidden;" v-if="handleData.watermarkType != '0'">
|
|
|
+ <label class="handle-label">水印行数:</label>
|
|
|
+ <el-input-number size="small" :min="1" v-model="handleData.watermarkDensityY" @change="handleImg" ></el-input-number>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" style="overflow: hidden;" v-if="handleData.watermarkType != '0'">
|
|
|
+ <label class="handle-label">水印列数:</label>
|
|
|
+ <el-input-number size="small" :min="1" v-model="handleData.watermarkDensityX" @change="handleImg" ></el-input-number>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <!-- 图片水印 -->
|
|
|
+ <div v-if="handleData.watermarkType == '2'">
|
|
|
+ <div class="handle-item">
|
|
|
+ <label class="handle-label">图片水印:</label>
|
|
|
+ <el-upload :style="{display: 'inline-block'}" action="/" :before-upload="getImgPath">
|
|
|
+ <el-input type="text" readonly v-model="handleData.watermarkImgPath" size="small" style="width:125px;" ></el-input>
|
|
|
+ <i class="el-icon-folder-opened open-folder" style="font-size:22px;"></i>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item">
|
|
|
+ <label class="handle-label">比例:</label>
|
|
|
+ <el-input-number size="small" style="margin-right:5px;" :min="1" :max="200" v-model="handleData.watermarkImgSize" @change="handleImg" ></el-input-number>%
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.watermarkType == '2'">
|
|
|
+ <label class="handle-label">不透明度:</label>
|
|
|
+ <el-input-number size="small" style="margin-right:5px;" :min="1" :max="100" v-model="handleData.watermarkImgOpactiy" @change="handleImg" ></el-input-number>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.watermarkType == '2'">
|
|
|
+ <label class="handle-label">旋转角度:</label>
|
|
|
+ <el-input-number size="small" v-model="handleData.watermarkImgRotate" @change="handleImg" ></el-input-number>
|
|
|
+ </div>
|
|
|
+ <div class="handle-item" v-if="handleData.watermarkType != '0'">
|
|
|
+ <label class="handle-label">水印位置:</label>
|
|
|
+ <el-radio-group class="position-radio" v-model="handleData.watermarkPosition" :style="{width: '120px', color: '#fff'}" @change="handleImg">
|
|
|
+ <el-radio :disabled="handleData.watermarkStyle == '2' && handleData.watermarkType == 1" :style="{margin: '2px 2px 2px 0', fontSize: 0}" v-for="key in watermarkPosition" :key="key" :label="key"></el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ <div>
|
|
|
+ <div style="padding-bottom: 3px;">
|
|
|
+ <label class="handle-label">水平边距:</label>
|
|
|
+ <el-input-number size="small" v-model="handleData.watermarkX" @change="handleImg" ></el-input-number>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <label class="handle-label">垂直边距:</label>
|
|
|
+ <el-input-number size="small" v-model="handleData.watermarkY" @change="handleImg" ></el-input-number>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 底部设置区域 -->
|
|
|
+ <div class="img-footer-area">
|
|
|
+ <div class="footer-line-between">
|
|
|
+ <!-- 1格式转化 -->
|
|
|
+ <div class="handle-item" v-if="menuIndex == 1">
|
|
|
+ <label class="handle-label">输出转换:</label>
|
|
|
+ <el-select v-model="handleData.imgFormat" style="width:100px;" size="small">
|
|
|
+ <el-option v-for="(item, key) in imgFormat" :key="key" :value="item" :label="item"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <vxe-button v-if="handleData.imgFormat == 'ICO'" type="text" status="info" icon="vxe-icon-info-circle-fill" @click="$message('图标资源ICO有最大尺寸限制,建议尺寸低于512x512')"></vxe-button>
|
|
|
+ <vxe-button v-if="isGif" type="text" status="info" icon="vxe-icon-info-circle-fill" @click="$message('GIF图片默认输出第一帧,多帧输出到单独文件夹中')"></vxe-button>
|
|
|
+ <el-checkbox v-if="isGif" v-model="gifChecked">GIF图片输出所有帧</el-checkbox>
|
|
|
+ </div>
|
|
|
+ <!-- 2图片压缩 -->
|
|
|
+ <div class="handle-item" v-if="menuIndex == 2">
|
|
|
+ <label class="handle-label">压缩质量:</label>
|
|
|
+ <el-input-number v-model="handleData.quality" :min="1" :max="100" size="small"></el-input-number>
|
|
|
+ <el-tag size="mini" type="danger" style="margin-left: 10px;">质量越低压缩的越小</el-tag>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else> </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </template>
|
|
|
+ </el-main>
|
|
|
+
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import os from 'os'
|
|
|
+import fs from 'fs'
|
|
|
+import pathMod, { resolve } from 'path';
|
|
|
+import electronApi from '@/utils/electronApi';
|
|
|
+import pjson from '/package.json'
|
|
|
+import Vue from 'vue'
|
|
|
+const sizeOf = require('image-size')
|
|
|
+
|
|
|
+let separator = '';
|
|
|
+if (os.platform == 'linux') {
|
|
|
+ separator = '/'
|
|
|
+} else {
|
|
|
+ separator = '\\'
|
|
|
+}
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'landing-page',
|
|
|
+ components: {
|
|
|
+
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ isGif: false, //是否含有gif图片
|
|
|
+ gifChecked: false, // 是否输出所有帧
|
|
|
+ rollFlag: false,
|
|
|
+ viewScale: 1,
|
|
|
+ productName: pjson.softInfo.softName,
|
|
|
+ setModal: false,
|
|
|
+ resetModal: false,
|
|
|
+ renameModal: false,
|
|
|
+ subTitle: '请查看列表文件状态',
|
|
|
+ cropimgShow: false,
|
|
|
+ cropImgIndex: -1,
|
|
|
+ cropInt: false,
|
|
|
+ selectInt: false,
|
|
|
+ cropImgLoading: false,
|
|
|
+ virtualWidth: 0,
|
|
|
+ virtualHeight: 0,
|
|
|
+ cropOptionsImgInfo: {},
|
|
|
+ cropOptions: {
|
|
|
+ img: '',
|
|
|
+ autoCrop: true, // 是否默认生成截图框
|
|
|
+ autoCropWidth: 100,
|
|
|
+ autoCropHeight: 100,
|
|
|
+ cropWidth: 100,
|
|
|
+ cropHeight: 100,
|
|
|
+ original: false,
|
|
|
+ maxImgSize: 20000,
|
|
|
+ canMove: false,
|
|
|
+ centerBox: true, // 截图框是否被限制在图片里面
|
|
|
+ fixed: false, //是否开启截图框宽高固定比例
|
|
|
+ fixedValue: 'free',
|
|
|
+ cropType: '1',
|
|
|
+ cropClassify: '1',
|
|
|
+ fixedNumber: [1, 1],
|
|
|
+ infoTrue: true,
|
|
|
+ previewInfo: '',
|
|
|
+ cropScale: 100,
|
|
|
+ },
|
|
|
+ execLimit: 3,
|
|
|
+ defaultFont:'c:\\windows\\fonts\\simkai.ttf',
|
|
|
+ imgShow:false,
|
|
|
+ pickProgress:false,
|
|
|
+ pickProgressPercent:0,
|
|
|
+ fonts:[],
|
|
|
+ watermarkPosition:['NorthWest','North','NorthEast','West','Center','East','SouthWest','South','SouthEast'],
|
|
|
+ imgUrl: this.$api.imgUrl,
|
|
|
+ imgSrc: '',
|
|
|
+ imgList: [],
|
|
|
+ mergeList: [], // 拼接图片列表
|
|
|
+ cropList: [], // 裁剪图片列表
|
|
|
+ imgInfo: '',
|
|
|
+ imgInfoIndex: 0,
|
|
|
+ menuIndex: 1, // 选中菜单
|
|
|
+ imgFormat: ['PNG','BMP','JPEG','JPG','ICO','WBMP','WEBP','HEIC','GIF','JFIF','TTF','TIF','TIFF','SVG','3FR','3G2','3GP','AAI','AI','ART','ARW','BGR','BGRA','BGRO','BIE','BMP2','BMP3','BRF','CAL','CALS','CANVAS','CAPTION','CIN','CIP','CLIP','CMYK','CMYKA','CR2','CRW','CUR','CUT','DATA','DCM','DCR','DCX','DDS','DFONT','DJVU','DNG','DOT','DPX','DXT1','DXT5','EPDF','EPI','EPS','EPS2','EPS3','EPSF','EPSI','EPT','EPT2','EPT3','ERF','EXR','FAX','FILE','FITS','FRACTAL','FTP','FTS','G3','G4','GIF87','GRADIENT','GRAY','GRAYA','GROUP4','GV','H','HALD','HDR','HISTOGRAM','HRZ','ICB','ICON','IIQ','INFO','INLINE','IPL','ISOBRL','ISOBRL6','J2C','J2K','JBG','JBIG','JNG','JNX','JP2','JPC','JPE','JPM','JPS','JPT','JSON','K25','KDC','LABEL','M2V','M4V','MAC','MAGICK','MAP','MASK','MAT','MATTE','MEF','MIFF','MKV','MNG','MONO','MRW','MSL','MSVG','MVG','NEF','NRW','ORF','OTB','OTF','PAL','PALM','PAM','PANGO','PATTERN','PBM','PCD','PCDS','PCL','PCT','PEF','PES','PFA','PFB','PFM','PGM','PGX','PICON','PICT','PIX','PJPEG','PLASMA','PNG00','PNG24','PNG32','PNG48','PNG64','PNG8','PNM','PPM','PREVIEW','PS','PS2','PS3','PSB','PSD','PTIF','PWP','RADIAL-GRADIENT','RAF','RAS','RAW','RGB','RGBA','RGBO','RGF','RLA','RLE','RMF','RW2','SCR','SCT','SFW','SGI','SHTML','SIX','SIXEL','SPARSE-COLOR','SR2','SRF','STEGANO','SUN','SVGZ','TGA','THUMBNAIL','TIFF64','TILE','UBRL','UBRL6','UIL','UYVY','VDA','VICAR','VID','VIFF','VIPS','VST','WMF','WMV','WMZ','WPG','X','X3F','XBM','XC','XCF','XPM','XPS','XV','XWD','YCbCr','YCbCrA','YUV'], // 图片格式
|
|
|
+ positionList: ['上左', '上中', '上右', '中左', '中间', '中右', '下左', '下中', '下右'],
|
|
|
+
|
|
|
+ downloadDir: '', // 默认下载目录
|
|
|
+ softdownloadDir: '', // 软件下载目录
|
|
|
+ mergeData: {
|
|
|
+ space: 0,
|
|
|
+ border: 0,
|
|
|
+ radius: 0,
|
|
|
+ row: 2,
|
|
|
+ col: 2,
|
|
|
+ width: 1200,
|
|
|
+ height: 1200,
|
|
|
+ contentWidth: 0,
|
|
|
+ contentHeight: 0,
|
|
|
+ outWidth: 1200,
|
|
|
+ outHeight: 1200,
|
|
|
+ backgroundColor: 'rgba(255,255,255,1)',
|
|
|
+ sizeType: '1200*1200px(1:1)',
|
|
|
+ scale: '1:1',
|
|
|
+ zoom: 1,
|
|
|
+ lockScale: true,
|
|
|
+ autoStyle: 'padding-top: 50%;',
|
|
|
+ mergeType: 2,
|
|
|
+ sortType: 2
|
|
|
+ },
|
|
|
+ handleData: {
|
|
|
+ dpi: 300,
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ pathType: '2', // 输出目录类型
|
|
|
+ newPath: os.userInfo().homedir + separator + "Downloads", // 新路径
|
|
|
+ autoRename: false, // 是否自动重命名
|
|
|
+ imgFormat: 'JPG', // 转换类型
|
|
|
+ quality: 92, // 图片品质
|
|
|
+ colorNum:256, // 颜色数量 1 - 256
|
|
|
+ sizeType: '1', // 调整尺寸
|
|
|
+ scaling: 100, // 缩放比例
|
|
|
+ rotateValue: 0, // 旋转角度
|
|
|
+ color: '0', // 图片色彩
|
|
|
+ colorValue: 256,
|
|
|
+ paintValue: 1, //油画数值
|
|
|
+ brightnessValue: 0, // 亮度
|
|
|
+ saturationValue: 0, //饱和度
|
|
|
+ hueValue: 0, // 色调
|
|
|
+ contrastValue: 0, // 对比度
|
|
|
+ opacityValue: 100, // 透明度
|
|
|
+ compressScaling:100,
|
|
|
+ compressOutType:2,
|
|
|
+ watermarkType: '1', // 水印类型 1文字 2图片
|
|
|
+ watermarkStyle: '1', // 1 单个 2平铺
|
|
|
+ watermarkValue: '', // 水印文字内容
|
|
|
+ watermarkColor: '#ff0000',
|
|
|
+ watermarkFont: 16,
|
|
|
+ watermarkX: 0,
|
|
|
+ watermarkY: 0,
|
|
|
+ watermarkDensityX: 3, // 平铺水印密度
|
|
|
+ watermarkDensityY: 3, // 平铺水印密度
|
|
|
+ watermarkImgPath: '', //图片水印路径
|
|
|
+ watermarkImgOpactiy: 100, // 水印不透明度
|
|
|
+ watermarkImgSize: 100, // 水印缩放比例
|
|
|
+ watermarkImgRotate: 0,
|
|
|
+ watermarkPosition: 'Center', // 水印位置
|
|
|
+ lineFlag: false,
|
|
|
+ lineWidth: 3,
|
|
|
+ lineColor: '#ff0000',
|
|
|
+ fonts:'',
|
|
|
+ rotate: 30,
|
|
|
+ circularFlag: false,
|
|
|
+ circularValue: 10,
|
|
|
+ hflip: false,
|
|
|
+ vflip: false,
|
|
|
+ lockScale: true,
|
|
|
+ },
|
|
|
+ handleRename: {
|
|
|
+ fileName: "", // 新文件名
|
|
|
+ fileCase: "1", // 大小写转换
|
|
|
+ startNumber: 0, // 起始编号
|
|
|
+ increment: 1, // 增量
|
|
|
+ digit: 1 // 位数
|
|
|
+ },
|
|
|
+ dowloadModel: false,
|
|
|
+ finishModel: false,
|
|
|
+ version: '0.0.1',
|
|
|
+
|
|
|
+ isStart: false, // 是否开始转换
|
|
|
+ isUpdate: false, // 是否有更新
|
|
|
+
|
|
|
+ loading: false,
|
|
|
+ cancelLoadStatus: false,
|
|
|
+ authority:{}, // 用户权限
|
|
|
+ sysDefaultTmpPath:'', // 系统水印路径
|
|
|
+ previewTmpPath:'', // 预览图片路径
|
|
|
+ imgLoading:false,
|
|
|
+ renameLoading: false,
|
|
|
+ mergeLoading: false,
|
|
|
+ mergeInterval: false,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ let __dirname = os.userInfo().homedir;
|
|
|
+ this.softdownloadDir = __dirname + separator + "Downloads";
|
|
|
+ if(fs.existsSync(__dirname + separator + "Desktop")){
|
|
|
+ this.downloadDir = __dirname + separator + "Desktop"
|
|
|
+ } else{
|
|
|
+ this.downloadDir = __dirname + separator + "Downloads"
|
|
|
+ }
|
|
|
+ this.handleData.newPath = this.downloadDir;
|
|
|
+
|
|
|
+ // 预览图片路径
|
|
|
+ this.previewTmpPath = os.tmpdir()+separator+'preview.png';
|
|
|
+
|
|
|
+ this.fonts = [
|
|
|
+ {
|
|
|
+ name:'宋体',
|
|
|
+ path:'c:\\Windows\\fonts\\simsun.ttc',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'仿宋',
|
|
|
+ path:'c:\\windows\\fonts\\simfang.ttf',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'楷体',
|
|
|
+ path:'c:\\windows\\fonts\\simkai.ttf',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'微软雅黑 常规',
|
|
|
+ path:'C:\\Windows\\Fonts\\msyh.ttc',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'微软雅黑 粗体',
|
|
|
+ path:'c:\\windows\\fonts\\msyhbd.ttc'
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ this.defaultFont = 'c:\\windows\\fonts\\simkai.ttf';
|
|
|
+
|
|
|
+ // 打开浏览器
|
|
|
+ const links = document.querySelectorAll('a[href]');
|
|
|
+ links.forEach(link => {
|
|
|
+ link.addEventListener('click', e => {
|
|
|
+ const url = link.getAttribute('href');
|
|
|
+ e.preventDefault();
|
|
|
+ electronApi.call('openExternal', [url]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.initDrop();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 鼠标滚轮事件
|
|
|
+ initRoll(){
|
|
|
+ let element = document.getElementById('show-img');
|
|
|
+ if(!this.rollFlag){
|
|
|
+ // 添加滚轮事件监听器
|
|
|
+ element.addEventListener('wheel', (event) => {
|
|
|
+ this.rollFlag = true;
|
|
|
+ // event.deltaY 是滚轮滚动的距离,正值表示向下滚动,负值表示向上滚动
|
|
|
+ if (event.deltaY < 0) {
|
|
|
+ if(this.viewScale < 5){
|
|
|
+ this.viewScale += 0.1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if(this.viewScale > 0){
|
|
|
+ this.viewScale -= 0.1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ event.preventDefault();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ // 选择目录
|
|
|
+ pickPath() {
|
|
|
+ this.$refs['upload-input'].blur();
|
|
|
+ electronApi.call('pickDir', []).then((path) => {
|
|
|
+ if (path) {
|
|
|
+ this.handleData.newPath = path;
|
|
|
+ this.downloadDir = path;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 将裁剪设置应用到所有图片
|
|
|
+ setOk(){
|
|
|
+ let cropPosition = this.cropList[this.cropImgIndex].cropPosition;
|
|
|
+ this.cropList.map(item => {
|
|
|
+ item.cropPosition = cropPosition;
|
|
|
+ item.cropOptions = this.cropOptions;
|
|
|
+ });
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.setModal = false;
|
|
|
+ }, 2000);
|
|
|
+ },
|
|
|
+ // 重置所有裁剪设置
|
|
|
+ resetOk(){
|
|
|
+ this.cropList.map(item => {
|
|
|
+ item.cropPosition = undefined;
|
|
|
+ item.cropOptions = {};
|
|
|
+ });
|
|
|
+ this.cropOptions.fixedValue = 'free';
|
|
|
+ this.cropOptions.fixed = false;
|
|
|
+ this.cropOptions.fixedNumber = [this.cropOptionsImgInfo.width, this.cropOptionsImgInfo.height];
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.resetModal = false;
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ // 选择裁剪比例
|
|
|
+ fixedChange(e){
|
|
|
+ this.cropOptions.fixedValue = e;
|
|
|
+ if(e == 'free'){
|
|
|
+ this.cropOptions.fixed = false;
|
|
|
+ }else if(e == 'original'){
|
|
|
+ this.cropOptions.fixed = true;
|
|
|
+ this.cropOptions.fixedNumber = [this.cropOptionsImgInfo.originalWidth, this.cropOptionsImgInfo.originalHeight];
|
|
|
+ }else{
|
|
|
+ this.cropOptions.fixed = true;
|
|
|
+ this.cropOptions.fixedNumber = [e.split(':')[0], e.split(':')[1]];
|
|
|
+ }
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$refs.cropper.goAutoCrop();
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.cropOptions.autoCropWidth = Number(this.$refs.cropper.cropW.toFixed(0));
|
|
|
+ this.cropOptions.autoCropHeight = Number(this.$refs.cropper.cropH.toFixed(0));
|
|
|
+ });
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+ // 加载图片成功回调函数
|
|
|
+ cropImgLoad(result){
|
|
|
+ this.cropImgLoading = result;
|
|
|
+ if(this.cropList[this.cropImgIndex].cropPosition){ // 有位置信息
|
|
|
+ this.$refs.cropper.goAutoCrop();
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let width = this.cropList[this.cropImgIndex].cropPosition.x2 - this.cropList[this.cropImgIndex].cropPosition.x1;
|
|
|
+ let height = this.cropList[this.cropImgIndex].cropPosition.y2 - this.cropList[this.cropImgIndex].cropPosition.y1;
|
|
|
+ this.$refs.cropper.cropOffsertX = this.cropList[this.cropImgIndex].cropPosition.x1;
|
|
|
+ this.$refs.cropper.cropOffsertY = this.cropList[this.cropImgIndex].cropPosition.y1;
|
|
|
+ this.$refs.cropper.cropW = width;
|
|
|
+ this.$refs.cropper.cropH = height;
|
|
|
+ });
|
|
|
+ }else{
|
|
|
+ let imgPosition = this.$refs.cropper.getImgAxis();
|
|
|
+ this.cropOptions.autoCropWidth = imgPosition.x2 - imgPosition.x1;
|
|
|
+ this.cropOptions.autoCropHeight = imgPosition.y2 - imgPosition.y1;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 实时预览
|
|
|
+ realTime(data){
|
|
|
+ clearInterval(this.cropInt);
|
|
|
+ this.cropOptions.previewInfo = data.html;
|
|
|
+ if(this.cropImgLoading){
|
|
|
+ this.getCropInfo(data);
|
|
|
+ }else{
|
|
|
+ this.cropInt = setInterval(()=> {
|
|
|
+ if(this.cropImgLoading){
|
|
|
+ this.getCropInfo(data);
|
|
|
+ clearInterval(this.cropInt);
|
|
|
+ }
|
|
|
+ }, 300);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getCropInfo(data){
|
|
|
+ if(this.cropOptions.cropType == '2' && this.cropOptions.cropClassify != '1'){
|
|
|
+ document.getElementsByClassName('crop-info')[0].style.opacity = 0;
|
|
|
+ }else{
|
|
|
+ document.getElementsByClassName('crop-info')[0].style.opacity = 1;
|
|
|
+ }
|
|
|
+ setTimeout(() => {
|
|
|
+ this.cropOptions.previewInfo = data.html;
|
|
|
+ let w = document.getElementsByClassName('crop-info')[0].innerText.split(' × ')[0];
|
|
|
+ let h = document.getElementsByClassName('crop-info')[0].innerText.split(' × ')[1];
|
|
|
+ let w_px = document.getElementsByClassName('cropper-crop-box')[0].offsetWidth;
|
|
|
+ let h_px = document.getElementsByClassName('cropper-crop-box')[0].offsetHeight;
|
|
|
+
|
|
|
+ let scale = w_px / w * 100;
|
|
|
+ this.cropOptions.cropWidth = Number(w);
|
|
|
+ this.cropOptions.cropHeight = Number(h);
|
|
|
+ this.cropOptions.cropScale = Number(scale);
|
|
|
+
|
|
|
+ let cropPosition = this.$refs.cropper.getCropAxis(); //截图框位置信息
|
|
|
+ let imgPosition = this.$refs.cropper.getImgAxis();
|
|
|
+ let dis_x = cropPosition.x1 < imgPosition.x1 ? 0 : cropPosition.x1 - imgPosition.x1;
|
|
|
+ let dis_y = cropPosition.y1 < imgPosition.y1 ? 0 : cropPosition.y1 - imgPosition.y1;
|
|
|
+
|
|
|
+ let cropX = dis_x / (this.cropOptions.cropScale / 100);
|
|
|
+ let cropY = dis_y / (this.cropOptions.cropScale / 100);
|
|
|
+
|
|
|
+ cropPosition.cropX = cropX; // 裁剪图片真实尺寸
|
|
|
+ cropPosition.cropY = cropY;
|
|
|
+ cropPosition.cropWidth = w;
|
|
|
+ cropPosition.cropHeight = h;
|
|
|
+ this.virtualWidth = Number(w);
|
|
|
+ this.virtualHeight = Number(h);
|
|
|
+
|
|
|
+ this.cropList[this.cropImgIndex].cropPosition = cropPosition;
|
|
|
+ this.cropList[this.cropImgIndex].cropOptions = JSON.parse(JSON.stringify(this.cropOptions));
|
|
|
+ }, 200);
|
|
|
+
|
|
|
+ },
|
|
|
+ selectTabCrop(data){
|
|
|
+ this.selectCropImg(data.rowIndex);
|
|
|
+ },
|
|
|
+ // 选择图片
|
|
|
+ selectCropImg(index){
|
|
|
+ this.cropImgIndex = index;
|
|
|
+ if(this.cropList[index].cropOptions){
|
|
|
+ this.cropOptions = JSON.parse(JSON.stringify(this.cropList[index].cropOptions));
|
|
|
+ }else{
|
|
|
+ this.setDefaultCropData();
|
|
|
+ }
|
|
|
+ this.cropOptions.img = this.cropList[index].path;
|
|
|
+ this.cropOptionsImgInfo = this.cropList[index];
|
|
|
+ this.cropImgLoading = false;
|
|
|
+ this.$forceUpdate();
|
|
|
+ },
|
|
|
+ // 裁剪分类
|
|
|
+ classifyChange(e){
|
|
|
+ if(e == '1'){ // 自定义
|
|
|
+ this.virtualWidth = this.cropOptionsImgInfo.originalWidth;
|
|
|
+ this.virtualHeight = this.cropOptionsImgInfo.originalHeight;
|
|
|
+ this.cropOptions.fixed = false;
|
|
|
+ this.cropOptions.fixedValue = 'free';
|
|
|
+ this.$refs.cropper.goAutoCrop();
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.cropOptions.autoCropWidth = Number(this.virtualWidth);
|
|
|
+ this.cropOptions.autoCropHeight = Number(this.virtualHeight);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ cropWidthChange(e){
|
|
|
+ let scale = Number(this.cropOptionsImgInfo.originalWidth) / Number(this.cropOptionsImgInfo.originalHeight);
|
|
|
+ if(this.cropOptions.fixed){ // 锁定比例
|
|
|
+ this.virtualHeight = Math.round(this.virtualWidth / scale);
|
|
|
+ }
|
|
|
+ let cropPosition = this.$refs.cropper.getCropAxis();
|
|
|
+ let c_w = cropPosition.x2 - cropPosition.x1;
|
|
|
+ let c_h = cropPosition.y2 - cropPosition.y1;
|
|
|
+
|
|
|
+ let w = document.getElementsByClassName('crop-info')[0].innerText.split(' × ')[0];
|
|
|
+ let h = document.getElementsByClassName('crop-info')[0].innerText.split(' × ')[1];
|
|
|
+ let c_scale = w / c_w;
|
|
|
+
|
|
|
+ this.$refs.cropper.goAutoCrop();
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.cropOptions.autoCropWidth = this.virtualWidth / c_scale;
|
|
|
+ this.cropOptions.autoCropHeight = this.virtualHeight / c_scale;
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ cropHeightChange(e){
|
|
|
+ let scale = Number(this.cropOptionsImgInfo.originalWidth) / Number(this.cropOptionsImgInfo.originalHeight);
|
|
|
+ if(this.cropOptions.fixed){ // 锁定比例
|
|
|
+ this.virtualWidth = Math.round(this.virtualHeight * scale);
|
|
|
+ }
|
|
|
+ let cropPosition = this.$refs.cropper.getCropAxis();
|
|
|
+ let c_w = cropPosition.x2 - cropPosition.x1;
|
|
|
+ let c_h = cropPosition.y2 - cropPosition.y1;
|
|
|
+
|
|
|
+ let w = document.getElementsByClassName('crop-info')[0].innerText.split(' × ')[0];
|
|
|
+ let h = document.getElementsByClassName('crop-info')[0].innerText.split(' × ')[1];
|
|
|
+ let c_scale = w / c_w;
|
|
|
+
|
|
|
+ this.$refs.cropper.goAutoCrop();
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.cropOptions.autoCropWidth = this.virtualWidth / c_scale;
|
|
|
+ this.cropOptions.autoCropHeight = this.virtualHeight / c_scale;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ cropChange(e){
|
|
|
+ if(e == 2 && this.cropOptions.fixed){
|
|
|
+ this.cropOptions.fixedValue = 'original';
|
|
|
+ this.fixedChange('original');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 预览
|
|
|
+ previewImg(){
|
|
|
+ this.cropimgShow = true;
|
|
|
+ },
|
|
|
+ // 裁剪图片
|
|
|
+ cropImg(){
|
|
|
+ this.mergeLoading = this.$loading({
|
|
|
+ lock: true,
|
|
|
+ text: '图片处理中,请稍后...',
|
|
|
+ spinner: 'el-icon-loading',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+ for(let index = 0; index < this.cropList.length; index++){
|
|
|
+ let item = this.cropList[index];
|
|
|
+
|
|
|
+ let imgType = item.type;
|
|
|
+ let suffix = item.name.lastIndexOf('.') != -1 ? item.name.substr(item.name.lastIndexOf('.')+1) : imgType.toLowerCase();
|
|
|
+ let newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + item.name.slice(0, item.name.lastIndexOf('.')) + '.' +suffix;
|
|
|
+
|
|
|
+ let str;
|
|
|
+ if(item.cropPosition && item.cropPosition.cropWidth){
|
|
|
+ str = item.cropPosition.cropWidth + 'x' + item.cropPosition.cropHeight + '+' + item.cropPosition.cropX + '+' + item.cropPosition.cropY;
|
|
|
+ }else{
|
|
|
+ str = item.width + 'x' + item.height + '+' + 0 + '+' + 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ let resize = [];
|
|
|
+ if(item.cropOptions && item.cropOptions.cropType == '2' && item.cropOptions.cropClassify != '1'){
|
|
|
+ let oWidth = item.cropOptions.fixedNumber[0];
|
|
|
+ let oHeight = item.cropOptions.fixedNumber[1];
|
|
|
+ resize = ['-resize', `${Number(oWidth)}x${Number(oHeight)}!`,];
|
|
|
+ }
|
|
|
+
|
|
|
+ let params = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-crop',
|
|
|
+ str,
|
|
|
+ ...resize,
|
|
|
+ item.path,
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+ electronApi.spawnExec(params).then(res => {
|
|
|
+ let imgInfo = {};
|
|
|
+ if(item.cropPosition && item.cropPosition.cropWidth){
|
|
|
+ imgInfo.width = item.cropPosition.cropWidth;
|
|
|
+ }else{
|
|
|
+ imgInfo.width = item.width;
|
|
|
+ }
|
|
|
+ this.addWatermark(index, imgInfo, newPath);
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ // errorIndex = index;
|
|
|
+ this.$notify.error({
|
|
|
+ title: '第【'+Number(index+1)+'】张图片出错',
|
|
|
+ message: '请调整后重试!' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(() => { // 延迟打开
|
|
|
+ this.mergeLoading.close();
|
|
|
+ electronApi.call('showItemInfolder',[this.downloadDir + separator + pjson.softInfo.softName + separator +'1.tty'])
|
|
|
+ }, 3000);
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ handleDownload(data, path){
|
|
|
+ var dataBuffer = new Buffer(data.split(',')[1], 'base64');
|
|
|
+ fs.writeFileSync(path, dataBuffer, {'flag':'w'});
|
|
|
+ },
|
|
|
+ // 加载拖拽监听事件
|
|
|
+ initDrop(){
|
|
|
+ const dragWrapper = document.getElementById("drag-jimp");
|
|
|
+ let domArr = [dragWrapper];
|
|
|
+ domArr.map(item => {
|
|
|
+ //添加拖拽事件监听器
|
|
|
+ item.addEventListener("drop", (e) => {
|
|
|
+ //阻止默认行为
|
|
|
+ e.preventDefault();
|
|
|
+ //获取文件列表
|
|
|
+ let files = e.dataTransfer.files;
|
|
|
+ let pathArr = [];
|
|
|
+ for(let i = 0; i < files.length; i++){
|
|
|
+ pathArr.push(files[i].path);
|
|
|
+ }
|
|
|
+ this.pushFileToList(pathArr);
|
|
|
+ })
|
|
|
+ //阻止拖拽结束事件默认行为
|
|
|
+ item.addEventListener("dragover", (e) => {
|
|
|
+ e.preventDefault();
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ cancelLoad(){
|
|
|
+ this.cancelLoadStatus = true;
|
|
|
+ },
|
|
|
+ openVip(){
|
|
|
+ this.$refs.headerRef.openVip();
|
|
|
+ },
|
|
|
+ // 打开自定义下载目录
|
|
|
+ openFolder(){
|
|
|
+ let path = this.downloadDir;
|
|
|
+ if(fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)){
|
|
|
+ path = this.downloadDir + separator + pjson.softInfo.softName;
|
|
|
+ } else {
|
|
|
+ fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
|
|
|
+ path = this.downloadDir + separator + pjson.softInfo.softName;
|
|
|
+ }
|
|
|
+ electronApi.call('showItemInfolder',[path+'\\tty.tty'])
|
|
|
+ },
|
|
|
+ // 清除列表
|
|
|
+ clearList() {
|
|
|
+ if(this.menuIndex != 8 && this.menuIndex != 10){
|
|
|
+ this.imgList = [];
|
|
|
+ this.imgSrc = '';
|
|
|
+ this.setDefaultData();
|
|
|
+ }else if(this.menuIndex == 8){
|
|
|
+ this.mergeList = [];
|
|
|
+ }else{
|
|
|
+ this.cropList = [];
|
|
|
+ this.cropImgIndex = -1;
|
|
|
+ this.setDefaultCropData();
|
|
|
+ this.cropOptionsImgInfo = {};
|
|
|
+ }
|
|
|
+
|
|
|
+ this.rollFlag = false;
|
|
|
+ this.isGif = false;
|
|
|
+ this.gifChecked = false;
|
|
|
+ },
|
|
|
+ setMenuIndex(index){
|
|
|
+ this.menuIndex = index;
|
|
|
+ this.setDefaultData();
|
|
|
+ if(index == 5){
|
|
|
+ this.handleData.fonts = this.defaultFont.toString();
|
|
|
+ }else if(index == 3){
|
|
|
+ this.handleData.width = this.imgInfo.width ? this.imgInfo.width : 0;
|
|
|
+ this.handleData.height = this.imgInfo.height ? this.imgInfo.height : 0;
|
|
|
+ }else if(index == 7){
|
|
|
+ this.setChange();
|
|
|
+ }
|
|
|
+ if(this.imgList.length > 0){
|
|
|
+ this.setDefaultImgInfo(this.imgList[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if([3,4,5,6,9].indexOf(this.menuIndex) == -1){ // 滚动事件
|
|
|
+ this.rollFlag = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ setDefaultCropData(){
|
|
|
+ this.cropOptions = {
|
|
|
+ img: '',
|
|
|
+ autoCrop: true, // 是否默认生成截图框
|
|
|
+ autoCropWidth: 100,
|
|
|
+ autoCropHeight: 100,
|
|
|
+ cropWidth: 100,
|
|
|
+ cropHeight: 100,
|
|
|
+ original: false,
|
|
|
+ maxImgSize: 20000,
|
|
|
+ canMove: false,
|
|
|
+ centerBox: true, // 截图框是否被限制在图片里面
|
|
|
+ fixed: false, //是否开启截图框宽高固定比例
|
|
|
+ fixedValue: 'free',
|
|
|
+ cropType: '1',
|
|
|
+ cropClassify: '1',
|
|
|
+ fixedNumber: [1, 1],
|
|
|
+ infoTrue: true,
|
|
|
+ previewInfo: '',
|
|
|
+ cropScale: 100,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ setDefaultData(){
|
|
|
+ this.handleData = {
|
|
|
+ dpi: 300,
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ pathType: this.handleData.pathType, // 输出目录类型
|
|
|
+ newPath: this.handleData.newPath, // 新路径
|
|
|
+ autoRename: false, // 是否自动重命名
|
|
|
+ imgFormat: 'JPG', // 转换类型
|
|
|
+ quality: 92, // 图片品质
|
|
|
+ colorNum: 256, // 颜色数量
|
|
|
+ color: '0', // 图片色彩
|
|
|
+ sizeType: '1', // 调整尺寸
|
|
|
+ scaling: 100, // 缩放比例
|
|
|
+ colorValue: 256,
|
|
|
+ paintValue: 1, // 油画数值
|
|
|
+ brightnessValue: 0, // 亮度
|
|
|
+ saturationValue: 0, //饱和度
|
|
|
+ hueValue: 0, // 色调
|
|
|
+ contrastValue: 0, // 对比度
|
|
|
+ rotateValue: 0, // 旋转角度
|
|
|
+ opacityValue: 100, // 透明度
|
|
|
+ compressScaling:100,
|
|
|
+ compressOutType:2,
|
|
|
+ watermarkType: '1', // 水印类型 1文字 2图片
|
|
|
+ watermarkStyle: '1', // 1 单个 2平铺
|
|
|
+ watermarkValue: '', // 水印文字内容
|
|
|
+ watermarkColor: '#ff0000',
|
|
|
+ watermarkFont: 16,
|
|
|
+ watermarkX: 0,
|
|
|
+ watermarkY: 0,
|
|
|
+ watermarkDensityX: 3, // 平铺水印密度
|
|
|
+ watermarkDensityY: 3, // 平铺水印密度
|
|
|
+ watermarkImgPath: '', //图片水印路径
|
|
|
+ watermarkImgOpactiy: 100, // 水印不透明度
|
|
|
+ watermarkImgSize: 100, //水印缩放比例
|
|
|
+ watermarkImgRotate:0,
|
|
|
+ watermarkPosition: 'Center',
|
|
|
+ lineFlag: false,
|
|
|
+ lineWidth: 3,
|
|
|
+ lineColor: '#ff0000',
|
|
|
+ fonts: this.defaultFont.toString(),
|
|
|
+ rotate: 30,
|
|
|
+ circularFlag: false,
|
|
|
+ circularValue: 10,
|
|
|
+ hflip: false,
|
|
|
+ vflip: false,
|
|
|
+ lockScale: true,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 选择水印图片
|
|
|
+ getImgPath(e) {
|
|
|
+ if (e) {
|
|
|
+ this.handleData.watermarkImgPath = e.path;
|
|
|
+ this.handleImg();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ pickFile(){
|
|
|
+ electronApi.call('pickFile', [this.imgFormat.join(','),true]).then(async(files) =>{
|
|
|
+ this.pushFileToList(files,0);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ pickDir(){
|
|
|
+ electronApi.call('pickDir', []).then((path) =>{
|
|
|
+ this.dealDir(path);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ dealDir(currentDirPath){
|
|
|
+ let files = fs.readdirSync(currentDirPath)
|
|
|
+
|
|
|
+ for (let i = 0; i < files.length; i++) {
|
|
|
+ let name = files[i];
|
|
|
+ var filePath = pathMod.join(currentDirPath, name);
|
|
|
+ var stat = fs.statSync(filePath);
|
|
|
+
|
|
|
+ if (stat.isFile()) {
|
|
|
+ this.pushFileToList([filePath]);
|
|
|
+ } else if (stat.isDirectory()) {
|
|
|
+ this.dealDir(filePath)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ pushFileToList(files){
|
|
|
+ // 直接渲染
|
|
|
+ files.map(file => {
|
|
|
+ let filename = file.substr(file.lastIndexOf(separator)+1);
|
|
|
+
|
|
|
+ let size = fs.statSync(file).size;
|
|
|
+ let imgInfo = {
|
|
|
+ name: filename,
|
|
|
+ size: this.$utils.handleSize(size),
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ originalWidth: 0,
|
|
|
+ originalHeight: 0,
|
|
|
+ path: file,
|
|
|
+ type: filename.lastIndexOf('.') == -1 ? '' : filename.substr(filename.lastIndexOf('.')+1),
|
|
|
+ loadPercent: 0,
|
|
|
+ percent: 0,
|
|
|
+ top: 0,
|
|
|
+ left: 0
|
|
|
+ };
|
|
|
+
|
|
|
+ if(!imgInfo.type){
|
|
|
+ this.$message({message: '不是有效的图片文件! - '+ file , type: 'warning'});
|
|
|
+ }else{
|
|
|
+ if(this.imgFormat.indexOf(imgInfo.type.toUpperCase()) == -1){
|
|
|
+ this.$message({message: '不是有效的图片文件! - '+ file , type: 'warning'});
|
|
|
+ }else{
|
|
|
+ if(imgInfo.type.toUpperCase() == 'GIF'){
|
|
|
+ this.isGif = true;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ let dimensions = sizeOf(file);
|
|
|
+ imgInfo.width = dimensions.width;
|
|
|
+ imgInfo.height = dimensions.height;
|
|
|
+ imgInfo.originalWidth = dimensions.width;
|
|
|
+ imgInfo.originalHeight = dimensions.height;
|
|
|
+ } catch (error) {
|
|
|
+ }
|
|
|
+
|
|
|
+ // 过滤重复图片
|
|
|
+ let flag = true;
|
|
|
+ if(this.menuIndex != 8 && this.menuIndex != 10) {
|
|
|
+ for(let m = 0; m < this.imgList.length; m++){
|
|
|
+ if(this.imgList[m].name == imgInfo.name && this.imgList[m].path == imgInfo.path){
|
|
|
+ flag = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else if(this.menuIndex == 8){
|
|
|
+ for(let m = 0; m < this.mergeList.length; m++){
|
|
|
+ if(this.mergeList[m].name == imgInfo.name && this.mergeList[m].path == imgInfo.path){
|
|
|
+ flag = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ for(let m = 0; m < this.cropList.length; m++){
|
|
|
+ if(this.cropList[m].name == imgInfo.name && this.cropList[m].path == imgInfo.path){
|
|
|
+ flag = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!flag){
|
|
|
+ this.$message({message: '该图片已经存在队列中 - '+ file , type: 'warning'});
|
|
|
+ }else{
|
|
|
+ if(this.menuIndex != 8 && this.menuIndex != 10){
|
|
|
+ this.imgList.push(imgInfo);
|
|
|
+ }else if(this.menuIndex == 8){
|
|
|
+ if(this.mergeList.length < 100){
|
|
|
+ this.mergeList.push(imgInfo);
|
|
|
+ this.sortChange(this.mergeData.sortType);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ this.cropList.push(imgInfo);
|
|
|
+ if(this.cropList.length == 1){
|
|
|
+ this.selectCropImg(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 设置第一个为默认图片
|
|
|
+ if(this.imgSrc == '' && this.imgList[0]){
|
|
|
+ this.setDefaultImgInfo(this.imgList[0])
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.menuIndex == 7){ // 重命名
|
|
|
+ this.setChange();
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ // 设置默认的图片
|
|
|
+ setDefaultImgInfo(info){
|
|
|
+ this.imgInfo = info;
|
|
|
+ this.handleData.width = this.imgInfo.width;
|
|
|
+ this.handleData.height = this.imgInfo.height;
|
|
|
+ this.imgLoading = true;
|
|
|
+
|
|
|
+ if([1,2,7,11].indexOf(this.menuIndex) == -1){
|
|
|
+ electronApi.fileStream(this.imgInfo.path).then(buffer => {
|
|
|
+ this.imgSrc = "data:image/png;base64,"+buffer.toString('base64');
|
|
|
+ this.imgLoading = false;
|
|
|
+ }).catch(err => {
|
|
|
+ this.imgLoading = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if([3,4,5,6,9].indexOf(this.menuIndex) > -1){ // 绑定滚动事件
|
|
|
+ setTimeout(() => {
|
|
|
+ if(!this.rollFlag){
|
|
|
+ this.initRoll();
|
|
|
+ }
|
|
|
+ }, 600);
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ // 选择新路径
|
|
|
+ getFolder(e) {
|
|
|
+ this.handleData.newPath = e.path;
|
|
|
+ this.downloadDir = e.path;
|
|
|
+ },
|
|
|
+ selectTab(data, index) {
|
|
|
+ let currentRow = data.rowIndex > -1 ? this.imgList[data.rowIndex] : data;
|
|
|
+ index = index ? 0 : data.rowIndex;
|
|
|
+ this.imgInfo = currentRow;
|
|
|
+ this.imgInfoIndex = index;
|
|
|
+
|
|
|
+ if([3,6,7,9].indexOf(this.menuIndex) > -1){
|
|
|
+ this.imgLoading = true;
|
|
|
+ electronApi.fileStream(currentRow.path).then(buffer => {
|
|
|
+ this.imgSrc = "data:image/png;base64,"+buffer.toString('base64');
|
|
|
+ this.imgLoading = false;
|
|
|
+ }).catch(err => {
|
|
|
+ this.imgLoading = false;
|
|
|
+ })
|
|
|
+ this.handleData.width = Number(currentRow.width);
|
|
|
+ this.handleData.height = Number(currentRow.height);
|
|
|
+ }else if([4,5].indexOf(this.menuIndex) > -1){
|
|
|
+ this.handleImg();
|
|
|
+ }else if(this.menuIndex == 1){
|
|
|
+ this.handleData.imgFormat = 'JPG';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 导出
|
|
|
+ async exportImg(flag) {
|
|
|
+ let authority = this.$refs.headerRef.authority;
|
|
|
+ if(!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)){
|
|
|
+ fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
|
|
|
+ }
|
|
|
+ // 图片拼接
|
|
|
+ if(this.menuIndex == 8 && this.mergeList.length > 0){
|
|
|
+ if (!authority.isAuthority && !flag) {
|
|
|
+ this.$refs.headerRef.memberModel = true;
|
|
|
+ this.$refs.headerRef.isClick = true;
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ this.$refs.headerRef.memberModel = false;
|
|
|
+ }
|
|
|
+ this.loading = true;
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.loading = false;
|
|
|
+ }, 1500)
|
|
|
+
|
|
|
+ if(this.mergeData.sortType != 3){
|
|
|
+ this.exportMerge2();
|
|
|
+ }else{
|
|
|
+ this.exportMerge();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 图片裁剪
|
|
|
+ if(this.menuIndex == 10 && this.cropList.length > 0){
|
|
|
+ if (!authority.isAuthority && !flag) {
|
|
|
+ this.$refs.headerRef.memberModel = true;
|
|
|
+ this.$refs.headerRef.isClick = true;
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ this.$refs.headerRef.memberModel = false;
|
|
|
+ }
|
|
|
+ this.loading = true;
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.loading = false;
|
|
|
+ }, 1500)
|
|
|
+
|
|
|
+ this.cropImg();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.imgList.length > 0 && this.menuIndex != 8 && this.menuIndex != 10) {
|
|
|
+ if (!authority.isAuthority && !flag) {
|
|
|
+ this.$refs.headerRef.memberModel = true;
|
|
|
+ this.$refs.headerRef.isClick = true;
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ this.$refs.headerRef.memberModel = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.loading = true;
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.loading = false;
|
|
|
+ }, 1500)
|
|
|
+
|
|
|
+ if(this.menuIndex == 7){ // 重命名
|
|
|
+ this.exportRename();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除水印,防止直接篡改水印图片
|
|
|
+ this.deleteSysWtater();
|
|
|
+
|
|
|
+ // 更改尺寸的时候,宽度和高度不允许为0
|
|
|
+ if(this.menuIndex == 3 && this.handleData.sizeType != 1){
|
|
|
+ if(this.handleData.width <= 0 || this.handleData.height <=0){
|
|
|
+ this.$message({message: '请设置缩放的宽度和高度' , type: 'warning'});
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //percent
|
|
|
+ let taskArr = [];
|
|
|
+ let newPath = '';
|
|
|
+ for(let i=0; i<this.imgList.length; i++){
|
|
|
+ let item = this.imgList[i];
|
|
|
+ let lastIndex = item.path.lastIndexOf('.');
|
|
|
+ let imgType = item.type;
|
|
|
+ let suffix = '';
|
|
|
+ if(this.menuIndex == 1){
|
|
|
+ suffix = this.handleData.imgFormat.toLowerCase();
|
|
|
+ }else{
|
|
|
+ suffix = item.name.lastIndexOf('.') != -1 ? item.name.substr(item.name.lastIndexOf('.')+1) : imgType.toLowerCase();
|
|
|
+ }
|
|
|
+ // 图片压缩,输出格式为jpg
|
|
|
+ if(this.menuIndex == 2 && this.handleData.compressOutType == 1){
|
|
|
+ suffix = 'jpg';
|
|
|
+ }
|
|
|
+ newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + item.name.slice(0, item.name.lastIndexOf('.')) + '.' +suffix;
|
|
|
+
|
|
|
+ // 处理图像
|
|
|
+ let task = this.dealImg(i, item, newPath);
|
|
|
+ if(task){
|
|
|
+ taskArr.push(task);
|
|
|
+ }
|
|
|
+
|
|
|
+ if((i+1) % this.execLimit == 0){
|
|
|
+ await Promise.all(taskArr).then(result => {
|
|
|
+ taskArr = [];
|
|
|
+ }).catch(err => {
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(taskArr.length > 0){
|
|
|
+ await Promise.all(taskArr).then(result => {
|
|
|
+ taskArr = [];
|
|
|
+ }).catch(err => {
|
|
|
+ // 错误文件添加到服务中
|
|
|
+ console.log('err',err);
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 打开文件夹
|
|
|
+ if(this.imgList.length > 0){
|
|
|
+ this.$message({message: '恭喜你,任务已完成!', type: 'success'});
|
|
|
+ electronApi.call('showItemInfolder',[newPath])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 操作
|
|
|
+ handleImg() {
|
|
|
+ if (this.imgInfo.path) {
|
|
|
+ this.imgLoading = true;
|
|
|
+ this.dealImg(this.imgInfoIndex);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 处理图片
|
|
|
+ dealImg(index, img, path){
|
|
|
+ let reduceFlag = img ? false : true;
|
|
|
+ let imgInfo = img ? img : this.imgInfo;
|
|
|
+ let newPath = img ? path : this.previewTmpPath;
|
|
|
+ let task = '';
|
|
|
+
|
|
|
+ switch (this.menuIndex) {
|
|
|
+ case 11: // 修改dpi
|
|
|
+ task = new Promise((resolve,reject) => {
|
|
|
+ let imgPath = imgInfo.path;
|
|
|
+ let cmd = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ imgPath,
|
|
|
+ '-density',
|
|
|
+ this.handleData.dpi,
|
|
|
+ '-units',
|
|
|
+ 'PixelsPerInch',
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(cmd,{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Load.*?,(.*?)%/;
|
|
|
+ const regexDuration2 = /Save.*?,(.*?)%/;
|
|
|
+
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList.indexOf(index)){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList.indexOf(index)){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,imgInfo,newPath);
|
|
|
+ resolve({type:this.menuIndex,index, img});
|
|
|
+ }).catch(err => {
|
|
|
+ // console.log(err.stderr.toString());
|
|
|
+ reject({type:this.menuIndex,index,err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ break;
|
|
|
+ case 1: // 格式转换
|
|
|
+ task = new Promise((resolve,reject) => {
|
|
|
+
|
|
|
+ let imgPath = imgInfo.path;
|
|
|
+ let gifParams = [];
|
|
|
+ if(imgInfo.type.toLowerCase() == 'psd'){
|
|
|
+ imgPath = imgInfo.path + '[0]';
|
|
|
+ }
|
|
|
+ if(imgInfo.type.toLowerCase() == 'gif'){
|
|
|
+ if(this.gifChecked){
|
|
|
+ gifParams = ['-coalesce'];
|
|
|
+ let name = imgInfo.name.slice(0, imgInfo.name.lastIndexOf('.'));
|
|
|
+ let gifPath = this.downloadDir + separator + pjson.softInfo.softName + separator + name;
|
|
|
+ if(!fs.existsSync(gifPath)){
|
|
|
+ fs.mkdirSync(gifPath);
|
|
|
+ }
|
|
|
+ newPath = gifPath + separator + name + '.' + this.handleData.imgFormat.toLowerCase();
|
|
|
+ }else{
|
|
|
+ imgPath = imgInfo.path + '[0]';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let cmd = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ ...gifParams,
|
|
|
+ imgPath,
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(cmd,{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Load.*?,(.*?)%/;
|
|
|
+ let regexDuration2 = /Save.*?,(.*?)%/;
|
|
|
+ if(imgInfo.type.toLowerCase() == 'gif'){
|
|
|
+ regexDuration2 = /Write.*?,(.*?)%/;
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList.indexOf(index)){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList.indexOf(index)){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,imgInfo,newPath);
|
|
|
+ resolve({type:this.menuIndex,index, img});
|
|
|
+ }).catch(err => {
|
|
|
+ // console.log(err.stderr.toString());
|
|
|
+ reject({type:this.menuIndex,index,err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: // 图片压缩
|
|
|
+ task = new Promise(async (resolve,reject) => {
|
|
|
+ let extraParams = [];
|
|
|
+ if(this.handleData.compressOutType == 1 || imgInfo.type.toLowerCase() != 'png'){
|
|
|
+ if(this.handleData.compressOutType == 1 || imgInfo.type.toLowerCase() == 'jpg' || imgInfo.type.toLowerCase() == 'JPEG'){
|
|
|
+ let sizeOld = fs.statSync(imgInfo.path).size;
|
|
|
+
|
|
|
+ extraParams=['-resize',this.handleData.compressScaling+'%','-define','jpeg:dct-method=fastest','-define','jpeg:extent='+sizeOld,'-sampling-factor','4:2:0','-strip','-interlace','Plane','-background','white','-flatten','-alpha','off','-quality',this.handleData.quality+'%']
|
|
|
+ }else{
|
|
|
+ extraParams=['+dither','-strip','-colors',256*(this.handleData.quality/90),'-depth',8]
|
|
|
+ }
|
|
|
+
|
|
|
+ electronApi.spawnExec(['convert.exe','-monitor',...extraParams,imgInfo.path, newPath],{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Load.*?,(.*?)%/;
|
|
|
+ const regexDuration2 = /Save.*?,(.*?)%/;
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,imgInfo,newPath);
|
|
|
+ resolve({type:this.menuIndex,index, imgInfo});
|
|
|
+ }).catch(err => {
|
|
|
+ err.stdout = err.stdout.toString();
|
|
|
+ err.stderr = err.stderr.toString();
|
|
|
+
|
|
|
+ reject({type:this.menuIndex,index,err});
|
|
|
+ });
|
|
|
+ }else{
|
|
|
+ // 复制文件到缓存目录 生成结束后输出到目标文件夹
|
|
|
+ let tmpPath = os.tmpdir()+separator+'YSI_'+Math.random();
|
|
|
+ let tmpPath2 = os.tmpdir()+separator+'YSO_'+Math.random() + '.png';
|
|
|
+
|
|
|
+ fs.copyFileSync(imgInfo.path,tmpPath);
|
|
|
+
|
|
|
+ // 添加系统水印
|
|
|
+ await this.addWatermark(index,imgInfo,tmpPath);
|
|
|
+
|
|
|
+ electronApi.spawnExec(['pngquant.exe',tmpPath,'-f','-v','--strip','--quality',this.handleData.quality,'-o',tmpPath2],{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /selecting colors...(.*?)%/;
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ if(res && res[1]){
|
|
|
+ imgInfo.percent = Math.round(parseInt(res[1])-2);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then((res) => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ // 复制
|
|
|
+ fs.copyFileSync(tmpPath2,newPath);
|
|
|
+
|
|
|
+ resolve({type:this.menuIndex,index, imgInfo});
|
|
|
+ }).catch(err => {
|
|
|
+ err.stdout = err.stdout.toString();
|
|
|
+ err.stderr = err.stderr.toString();
|
|
|
+
|
|
|
+ // 如果失败,重新使用推荐的最小值来转换
|
|
|
+ // const regexQ = /\(Q=(.*?)\)/g;
|
|
|
+ // const res2 = regexQ.exec(err.stderr);
|
|
|
+ // const quality = res2[1];
|
|
|
+ this.pngFailedExec(index,tmpPath,tmpPath2,imgInfo,newPath).then(rr => {
|
|
|
+ resolve({type:this.menuIndex,index, imgInfo});
|
|
|
+ }).catch(err2 => {
|
|
|
+ reject({type:this.menuIndex,index,err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: // 更改尺寸
|
|
|
+ case 9: // 批量旋转
|
|
|
+ task = new Promise((resolve,reject) => {
|
|
|
+ let params = [];
|
|
|
+ let extraParams = [];
|
|
|
+
|
|
|
+ if(this.handleData.rotateValue != 0){
|
|
|
+ extraParams = ['-rotate',this.handleData.rotateValue];
|
|
|
+ }
|
|
|
+
|
|
|
+ let vflipParams = [];
|
|
|
+ let hflipParams = [];
|
|
|
+ if(this.handleData.vflip){
|
|
|
+ vflipParams = ['-flip'];
|
|
|
+ }
|
|
|
+ if(this.handleData.hflip){
|
|
|
+ hflipParams = ['-flop'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.handleData.sizeType == 1) { // 按照比列缩放
|
|
|
+ params = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ '-resize',
|
|
|
+ this.handleData.scaling+'%',
|
|
|
+ ...extraParams,
|
|
|
+ ...vflipParams,
|
|
|
+ ...hflipParams,
|
|
|
+ imgInfo.path,
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+ } else { // 按照尺寸缩放
|
|
|
+ params = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ '-resize',
|
|
|
+ `${Number(this.handleData.width)}x${Number(this.handleData.height)}!`,
|
|
|
+ ...extraParams,
|
|
|
+ ...vflipParams,
|
|
|
+ ...hflipParams,
|
|
|
+ imgInfo.path,
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ electronApi.spawnExec(params,{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Load.*?,(.*?)%/;
|
|
|
+ const regexDuration2 = /Save.*?,(.*?)%/;
|
|
|
+
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,imgInfo,newPath);
|
|
|
+
|
|
|
+ resolve({type:this.menuIndex,index, img});
|
|
|
+ }).catch(err => {
|
|
|
+ reject({type:this.menuIndex,index,err});
|
|
|
+ });
|
|
|
+ })
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: // 美化图片
|
|
|
+ task = new Promise((resolve,reject) => {
|
|
|
+ let extraParams2 = [];
|
|
|
+ let extraParams3 = [];
|
|
|
+ let reduceParams = [];
|
|
|
+ switch (this.handleData.color){
|
|
|
+ case '1': // 黑白
|
|
|
+ extraParams2 = ['-type', 'bilevel'];
|
|
|
+ break;
|
|
|
+ case '2': // 灰色
|
|
|
+ extraParams2 = ['-type','grayscale'];
|
|
|
+ break;
|
|
|
+ case '3': // 反转
|
|
|
+ extraParams2 = ['-channel', 'RGB', '-negate'];
|
|
|
+ break;
|
|
|
+ case '4': // 油画
|
|
|
+ extraParams2 = ['-paint', Number(this.handleData.paintValue)-1];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.handleData.lineFlag){
|
|
|
+ extraParams3 = ['-bordercolor',this.handleData.lineColor,'-border',this.handleData.lineWidth];
|
|
|
+ }
|
|
|
+
|
|
|
+ if(reduceFlag){ // 缩小尺寸实现快速渲染???
|
|
|
+ //reduceParams = ['-resize','10%'];
|
|
|
+ }
|
|
|
+
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ imgInfo.path,
|
|
|
+ '-monitor',
|
|
|
+ ...reduceParams,
|
|
|
+ '-colors',
|
|
|
+ this.handleData.colorValue,
|
|
|
+ '-brightness-contrast',
|
|
|
+ `${Number(this.handleData.brightnessValue)}/${Number(this.handleData.contrastValue)}`,
|
|
|
+ '-modulate',
|
|
|
+ '100,'+ Number(this.handleData.saturationValue+100) + ',' + Number(this.handleData.hueValue+100),
|
|
|
+ '-alpha', 'set', '-channel', 'A', '-evaluate', 'Multiply', this.handleData.opacityValue/100, '+channel',
|
|
|
+ ...extraParams2,
|
|
|
+ ...extraParams3,
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params2,{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Function.*?,(.*?)%/;
|
|
|
+ const regexDuration2 = /save.*?,(.*?)%/;
|
|
|
+
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ if(!img){ // 预览状态
|
|
|
+ electronApi.fileStream(newPath).then(buffer => {
|
|
|
+ this.imgSrc = "data:image/png;base64,"+buffer.toString('base64');
|
|
|
+ this.imgLoading = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,imgInfo,newPath);
|
|
|
+ resolve({type:this.menuIndex, index, img});
|
|
|
+ }).catch(err => {
|
|
|
+ reject({type:this.menuIndex, index,err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: // 添加水印
|
|
|
+ if (this.handleData.watermarkType == '1') { // 文字水印
|
|
|
+ if(this.handleData.fonts == ''){
|
|
|
+ this.$message({message: '请选择字体', type: 'warning'});
|
|
|
+ this.imgLoading = false;
|
|
|
+ break;
|
|
|
+ }else{
|
|
|
+ task = this.textWatermark(index, imgInfo, newPath,!img);
|
|
|
+ }
|
|
|
+ } else if (this.handleData.watermarkType == '2') { // 图片水印
|
|
|
+ // 平铺功能去掉
|
|
|
+ this.handleData.watermarkStyle = 1;
|
|
|
+
|
|
|
+ if(!this.handleData.watermarkImgPath){
|
|
|
+ this.$message({message: '请上传图片水印', type: 'warning'});
|
|
|
+ this.imgLoading = false;
|
|
|
+ break;
|
|
|
+ }else{
|
|
|
+ task = this.imgWatermark(index, imgInfo, newPath,!img);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 6: // 圆角设置
|
|
|
+ task = new Promise((resolve,reject) => {
|
|
|
+ let cirPath = newPath;
|
|
|
+ if(this.handleData.circularValue > 0){
|
|
|
+ cirPath = newPath.substr(0, newPath.lastIndexOf('.')+1) + 'png';
|
|
|
+ }
|
|
|
+ let extraParams = ['-draw', 'roundrectangle 0,0,'+imgInfo.width+','+imgInfo.height+','+imgInfo.width*this.handleData.circularValue/100+','+imgInfo.width*this.handleData.circularValue/100]
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-size',
|
|
|
+ imgInfo.width+'x'+imgInfo.height,
|
|
|
+ 'xc:none',
|
|
|
+ '-fill',
|
|
|
+ imgInfo.path,
|
|
|
+ '-monitor',
|
|
|
+ ...extraParams,
|
|
|
+ cirPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params2,{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Function.*?,(.*?)%/;
|
|
|
+ const regexDuration2 = /save.*?,(.*?)%/;
|
|
|
+
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ if(!img){ // 预览状态
|
|
|
+ electronApi.fileStream(cirPath).then(buffer => {
|
|
|
+ this.imgSrc = "data:image/png;base64,"+buffer.toString('base64');
|
|
|
+ this.imgLoading = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,imgInfo,cirPath);
|
|
|
+ resolve({type:this.menuIndex, index, img});
|
|
|
+ }).catch(err => {
|
|
|
+ reject({type:this.menuIndex, index,err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return task;
|
|
|
+ },
|
|
|
+ //如果转换失败,则使用推荐的Quaity转换图片
|
|
|
+ pngFailedExec(index,tmpPath,tmpPath2,imgInfo,newPath){
|
|
|
+ return new Promise((resolve,reject) => {
|
|
|
+ electronApi.spawnExec(['pngquant.exe',tmpPath,'-f','-v','--strip','-o',tmpPath2],{
|
|
|
+ stderr:(data) => {
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /selecting colors...(.*?)%/;
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ if(res && res[1]){
|
|
|
+ imgInfo.percent = Math.round(parseInt(res[1])-2);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).then((res) => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ // 复制
|
|
|
+ fs.copyFileSync(tmpPath2,newPath);
|
|
|
+
|
|
|
+ resolve({type:this.menuIndex,index, imgInfo});
|
|
|
+ }).catch(err => {
|
|
|
+ err.stdout = err.stdout && err.stdout.toString();
|
|
|
+ err.stderr = err.stderr && err.stderr.toString();
|
|
|
+
|
|
|
+ reject({type:this.menuIndex,index,err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // scaleWidthChange
|
|
|
+ scaleWidthChange(e){
|
|
|
+ let scale = Number(this.imgInfo.originalWidth) / Number(this.imgInfo.originalHeight);
|
|
|
+ if(this.handleData.lockScale){ // 锁定比例
|
|
|
+ this.handleData.height = Math.round(this.handleData.width / scale);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // scaleHeightChange
|
|
|
+ scaleHeightChange(e){
|
|
|
+ let scale = Number(this.imgInfo.originalWidth) / Number(this.imgInfo.originalHeight);
|
|
|
+ if(this.handleData.lockScale){ // 锁定比例
|
|
|
+ this.handleData.width = Math.round(this.handleData.height * scale);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 文字水印
|
|
|
+ async textWatermark(index, imgInfo, newPath,isPreview=false) {
|
|
|
+ let m = this.handleData.watermarkDensityX <= 0 ? 3 : this.handleData.watermarkDensityX;
|
|
|
+ let n = this.handleData.watermarkDensityY <= 0 ? 3 : this.handleData.watermarkDensityY;
|
|
|
+
|
|
|
+ return new Promise((resolve,reject) => {
|
|
|
+ let tmpPath = os.tmpdir()+separator+'water_font_'+Math.random()+'.png';
|
|
|
+ let params = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ '-background',
|
|
|
+ 'none',
|
|
|
+ '-fill',
|
|
|
+ this.handleData.watermarkColor,
|
|
|
+ '-font',
|
|
|
+ this.handleData.fonts.toString(),
|
|
|
+ '-pointsize',
|
|
|
+ this.handleData.watermarkFont,
|
|
|
+ '-alpha', 'set', '-channel', 'A', '-evaluate', 'Multiply', this.handleData.watermarkImgOpactiy/100, '+channel', // 透明度
|
|
|
+ '-rotate',
|
|
|
+ this.handleData.rotate,
|
|
|
+ 'label:' + (this.handleData.watermarkValue ? this.handleData.watermarkValue : pjson.softInfo.softName),
|
|
|
+ '-gravity',
|
|
|
+ 'center',
|
|
|
+ '-extent',
|
|
|
+ this.handleData.watermarkStyle == 2 ? (imgInfo.width/m)+'x'+(imgInfo.height/n) : '100%',
|
|
|
+ tmpPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params,{stderr:(data) => { imgInfo.percent = 30;this.imgList.splice(index,1,imgInfo);}}).then(async (res) => {
|
|
|
+ // 生成平铺水印图片
|
|
|
+ if(this.handleData.watermarkStyle == 2){ // 平铺
|
|
|
+ let tmpPath2 = os.tmpdir()+separator+'water_pu_'+Math.random()+'.png';
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ tmpPath,
|
|
|
+ '-write',
|
|
|
+ 'mpr:tiler',
|
|
|
+ '+delete',
|
|
|
+ '-size',
|
|
|
+ imgInfo.width+'x'+imgInfo.height,
|
|
|
+ 'tile:mpr:tiler',
|
|
|
+ tmpPath2
|
|
|
+ ];
|
|
|
+ await electronApi.spawnExec(params2,{stderr:(data) => { imgInfo.percent=60;this.imgList.splice(index,1,imgInfo);}}).then(async (res2) => {
|
|
|
+ await this.waterComposite(index, imgInfo, newPath, tmpPath2);
|
|
|
+ if(fs.existsSync(tmpPath)){
|
|
|
+ fs.unlinkSync(tmpPath);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ await this.waterComposite(index, imgInfo, newPath, tmpPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(isPreview){ // 预览状态
|
|
|
+ electronApi.fileStream(newPath).then(buffer => {
|
|
|
+ this.imgSrc = "data:image/png;base64,"+buffer.toString('base64');
|
|
|
+ this.imgLoading = false;
|
|
|
+ }).catch(err => {
|
|
|
+ this.imgLoading = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ resolve({type:this.menuIndex, index:index, info:imgInfo});
|
|
|
+ }).catch(err => {
|
|
|
+ reject({type:this.menuIndex, index:index, err: err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 图片水印
|
|
|
+ async imgWatermark(index, imgInfo, newPath,isPreview=false) {
|
|
|
+ let m = this.handleData.watermarkDensityX <= 0 ? 3 : this.handleData.watermarkDensityX;
|
|
|
+ let n = this.handleData.watermarkDensityY <= 0 ? 3 : this.handleData.watermarkDensityY;
|
|
|
+
|
|
|
+ return new Promise((resolve,reject) => {
|
|
|
+ let tmpPath = os.tmpdir()+separator+'water_img_'+Math.random()+'.png';
|
|
|
+
|
|
|
+ let params = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ '-background',
|
|
|
+ 'none',
|
|
|
+ '-resize',
|
|
|
+ `${Number(this.handleData.watermarkImgSize)}%`,
|
|
|
+ '-alpha', 'set', '-channel', 'A', '-evaluate', 'Multiply', this.handleData.watermarkImgOpactiy/100, '+channel', // 透明度
|
|
|
+ '-rotate',
|
|
|
+ this.handleData.watermarkImgRotate,
|
|
|
+ '-gravity',
|
|
|
+ 'center',
|
|
|
+ '-extent',
|
|
|
+ this.handleData.watermarkStyle == 2 ? (imgInfo.width/m)+'x'+(imgInfo.height/n) : '100%',
|
|
|
+ this.handleData.watermarkImgPath,
|
|
|
+ tmpPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params).then(async (res) => {
|
|
|
+ // 生成平铺水印图片
|
|
|
+ if(this.handleData.watermarkStyle == 2){ // 平铺
|
|
|
+ let tmpPath2 = os.tmpdir()+separator+'water_pu_'+Math.random()+'.png';
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ tmpPath,
|
|
|
+ '-write',
|
|
|
+ 'mpr:tiler',
|
|
|
+ '+delete',
|
|
|
+ '-size',
|
|
|
+ imgInfo.width+'x'+imgInfo.height,
|
|
|
+ 'tile:mpr:tiler',
|
|
|
+ tmpPath2
|
|
|
+ ];
|
|
|
+ await electronApi.spawnExec(params2,{stderr:(data) => { imgInfo.percent=60;this.imgList.splice(index,1,imgInfo);}}).then(async (res2) => {
|
|
|
+ await this.waterComposite(index, imgInfo, newPath, tmpPath2);
|
|
|
+ if(fs.existsSync(tmpPath)){
|
|
|
+ fs.unlinkSync(tmpPath);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ await this.waterComposite(index, imgInfo, newPath, tmpPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(isPreview){ // 预览状态
|
|
|
+ electronApi.fileStream(newPath).then(buffer => {
|
|
|
+ this.imgSrc = "data:image/png;base64,"+buffer.toString('base64');
|
|
|
+ this.imgLoading = false;
|
|
|
+ }).catch(err => {
|
|
|
+ this.imgLoading = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ resolve({type:this.menuIndex, index:index, info:imgInfo});
|
|
|
+ }).catch(err => {
|
|
|
+ reject({type:this.menuIndex, index:index, err: err});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async waterComposite(index, imgInfo, newPath,waterImg){
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ imgInfo.path,
|
|
|
+ waterImg,
|
|
|
+ '-gravity',
|
|
|
+ this.handleData.watermarkStyle == 2 ? 'Center' : this.handleData.watermarkPosition,
|
|
|
+ '-geometry',
|
|
|
+ '+'+this.handleData.watermarkX+'+'+this.handleData.watermarkY,
|
|
|
+ '-composite',
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ await electronApi.spawnExec(params2,{
|
|
|
+ stderr:(data) => {
|
|
|
+ let percent = 0;
|
|
|
+ let str = data.toString();
|
|
|
+ const regexDuration = /Load.*?,(.*?)%/;
|
|
|
+ const regexDuration2 = /Resize.*?,(.*?)%/;
|
|
|
+
|
|
|
+ const res = regexDuration.exec(str);
|
|
|
+ const res2 = regexDuration2.exec(str);
|
|
|
+
|
|
|
+ let p1 = 0;
|
|
|
+ let p2 = 0;
|
|
|
+ if(res && res[1]){
|
|
|
+ p1 = parseInt(res[1]);
|
|
|
+ if(p1 > 0){
|
|
|
+ imgInfo.percent = Math.round(p1/2);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(res2 && res2[1]){
|
|
|
+ p2 = parseInt(res2[1]);
|
|
|
+ }
|
|
|
+ if(p2 > 0){
|
|
|
+ imgInfo.percent = Math.round(50+(p2/2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.handleData.watermarkStyle == 2){ // 平铺
|
|
|
+ imgInfo.percent = 60 + Math.round(percent*0.4);
|
|
|
+ }else{
|
|
|
+ imgInfo.percent = percent;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.imgList[index]){
|
|
|
+ this.imgList.splice(index,1,imgInfo);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ }).then(res2 => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(this.imgList[index]){
|
|
|
+ imgInfo.percent = 100;
|
|
|
+ this.imgList.splice(index, 1, imgInfo);
|
|
|
+ if(fs.existsSync(waterImg)){
|
|
|
+ fs.unlinkSync(waterImg);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ reject({type:this.menuIndex,index,err:'用户强制终止!'});
|
|
|
+ }
|
|
|
+ }, 150)
|
|
|
+
|
|
|
+ //未购买 添加系统水印
|
|
|
+ this.addWatermark(index,{...imgInfo,path:newPath},newPath);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 初始化系统水印图片
|
|
|
+ async initSysWater(imgInfo){
|
|
|
+ return new Promise((resolve,reject) => {
|
|
|
+ let fontSize = 40;
|
|
|
+ let width = imgInfo.width;
|
|
|
+ if(this.menuIndex == 3){
|
|
|
+ width = width * (this.handleData.scaling / 100);
|
|
|
+ }
|
|
|
+ if (width < 500) {
|
|
|
+ fontSize = 16;
|
|
|
+ } else if (width < 1000) {
|
|
|
+ fontSize = 28
|
|
|
+ }else if(width < 2000){
|
|
|
+ fontSize = 40;
|
|
|
+ }else if(width < 3000){
|
|
|
+ fontSize = 100;
|
|
|
+ }else{
|
|
|
+ fontSize = 220;
|
|
|
+ }
|
|
|
+
|
|
|
+ let sysDefaultTmpPath = os.tmpdir()+separator+'water_xy_'+fontSize+'.png';
|
|
|
+
|
|
|
+ let params = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ '-background',
|
|
|
+ 'none',
|
|
|
+ '-fill',
|
|
|
+ 'rgba(0,0,0,0.8)',
|
|
|
+ '-font',
|
|
|
+ this.defaultFont,
|
|
|
+ '-pointsize',
|
|
|
+ fontSize,
|
|
|
+ 'label:https://www.xingyousoft.com',
|
|
|
+ sysDefaultTmpPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ if(fs.existsSync(sysDefaultTmpPath)){
|
|
|
+ resolve(sysDefaultTmpPath)
|
|
|
+ }else{
|
|
|
+ electronApi.spawnExec(params).then((res) => {
|
|
|
+ resolve(sysDefaultTmpPath)
|
|
|
+ }).catch(err => {
|
|
|
+ reject(err)
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 添加默认水印
|
|
|
+ async addWatermark(index,imgInfo,newPath) {
|
|
|
+ return new Promise((resolve,reject) => {
|
|
|
+ let authority = this.$refs.headerRef.authority;
|
|
|
+
|
|
|
+ if (authority.isAuthority) {
|
|
|
+ // 有权限,则不做任何操作
|
|
|
+ resolve(true)
|
|
|
+ } else {
|
|
|
+ this.initSysWater(imgInfo).then(re => {
|
|
|
+ let sysDefaultTmpPath = re;
|
|
|
+ // 合并系统水印
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-monitor',
|
|
|
+ newPath,
|
|
|
+ sysDefaultTmpPath,
|
|
|
+ '-gravity',
|
|
|
+ 'center',
|
|
|
+ '-composite',
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params2).then(result => {
|
|
|
+ resolve(result)
|
|
|
+ }).catch(err => {
|
|
|
+ reject(err)
|
|
|
+ });
|
|
|
+ }).catch(err2 =>{
|
|
|
+ reject({err2})
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ deleteSysWtater(){
|
|
|
+ let w1 = os.tmpdir()+separator+'water_xy_16.png';
|
|
|
+ let w2 = os.tmpdir()+separator+'water_xy_28.png';
|
|
|
+ let w3 = os.tmpdir()+separator+'water_xy_40.png';
|
|
|
+ let w4 = os.tmpdir()+separator+'water_xy_100.png';
|
|
|
+
|
|
|
+ if(fs.existsSync(w1)){
|
|
|
+ fs.unlinkSync(w1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(fs.existsSync(w2)){
|
|
|
+ fs.unlinkSync(w2);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(fs.existsSync(w3)){
|
|
|
+ fs.unlinkSync(w3);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(fs.existsSync(w4)){
|
|
|
+ fs.unlinkSync(w4);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 翻转模式
|
|
|
+ flipChange(str){
|
|
|
+ if(this.handleData[str]){
|
|
|
+ this.handleData[str] = false;
|
|
|
+ }else{
|
|
|
+ this.handleData[str] = str;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 旋转角度
|
|
|
+ rotateChange(type){
|
|
|
+ let current = this.handleData.rotateValue;
|
|
|
+ if(type == 1){ // 逆时针旋转90°
|
|
|
+ current -= 90;
|
|
|
+ if(current < -360){
|
|
|
+ this.handleData.rotateValue = current + 360;
|
|
|
+ }else{
|
|
|
+ this.handleData.rotateValue = current;
|
|
|
+ }
|
|
|
+ }else{ // 顺时针旋转90°
|
|
|
+ current += 90;
|
|
|
+ if(current > 360){
|
|
|
+ this.handleData.rotateValue = current - 360;
|
|
|
+ }else{
|
|
|
+ this.handleData.rotateValue = current;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除重命名文件
|
|
|
+ delImgFile(rowIndex){
|
|
|
+ this.$confirm('确认删除这张图片吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.imgList.splice(rowIndex, 1);
|
|
|
+ if (this.imgList.length == 0) {
|
|
|
+ this.clearList();
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 重命名操作
|
|
|
+ setChange() {
|
|
|
+ let list = JSON.parse(JSON.stringify(this.imgList));
|
|
|
+ list.map((item, key) => {
|
|
|
+ let lastIndex = item.name.lastIndexOf('.');
|
|
|
+ let fileName = item.name.substring(0, lastIndex);
|
|
|
+ let fileExtend = item.name.substr(lastIndex+1);
|
|
|
+
|
|
|
+ // ------------------文件名---------------------
|
|
|
+ let newFilename = '', newExtendname = '';
|
|
|
+ let fileNo = (this.handleRename.increment * key) + this.handleRename.startNumber;
|
|
|
+ if(fileNo.toString().length < this.handleRename.digit){
|
|
|
+ let size = this.handleRename.digit - fileNo.toString().length;
|
|
|
+ let digitStr = "";
|
|
|
+ for(let i = 0; i < size; i++){
|
|
|
+ digitStr += "0";
|
|
|
+ }
|
|
|
+ fileNo = digitStr + fileNo;
|
|
|
+ }
|
|
|
+ newFilename = this.handleRename.fileName ? this.handleRename.fileName + fileNo : fileNo;
|
|
|
+ // 文件名大小写转换
|
|
|
+ newFilename = newFilename.toString();
|
|
|
+ switch(this.handleRename.fileCase){
|
|
|
+ case "2": // 全部大写
|
|
|
+ newFilename = newFilename.toUpperCase();
|
|
|
+ break;
|
|
|
+ case "3": // 全部小写
|
|
|
+ newFilename = newFilename.toLowerCase();
|
|
|
+ break;
|
|
|
+ case "4": // 首字母大写
|
|
|
+ newFilename = newFilename.charAt(0).toUpperCase() + newFilename.slice(1);
|
|
|
+ break;
|
|
|
+ case "5": // 首字母小写
|
|
|
+ newFilename = newFilename.charAt(0).toLowerCase() + newFilename.slice(1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ item.newName = newFilename + '.' + fileExtend;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.imgList = JSON.parse(JSON.stringify(list));
|
|
|
+ },
|
|
|
+ // 重命名
|
|
|
+ exportRename() {
|
|
|
+ let authority = this.$refs.headerRef.authority;
|
|
|
+ let tempList = [];
|
|
|
+ this.renameLoading = this.$loading({
|
|
|
+ lock: true,
|
|
|
+ text: '批量操作中,请稍后...',
|
|
|
+ spinner: 'el-icon-loading',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+ setTimeout(() => {
|
|
|
+ this.renameLoading.close();
|
|
|
+ this.renameModal = true;
|
|
|
+ // this.$alert('重命名成功', '提示', {
|
|
|
+ // confirmButtonText: '确定',
|
|
|
+ // callback: action => {
|
|
|
+ // this.setChange();
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ this.imgList = JSON.parse(JSON.stringify(tempList));
|
|
|
+ }, 3000);
|
|
|
+
|
|
|
+ tempList = JSON.parse(JSON.stringify(this.imgList));
|
|
|
+
|
|
|
+ let size = 999999999;
|
|
|
+ if(!authority.isAuthority){
|
|
|
+ size = 10;
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(()=>{
|
|
|
+ for(let index = 0; index < tempList.length; index++) {
|
|
|
+ let item = tempList[index];
|
|
|
+ item.status = "1";
|
|
|
+ let path = pathMod.dirname(item.path) + "\\";
|
|
|
+ let newPath = path + item.newName;
|
|
|
+ if(index < size) {
|
|
|
+ fs.exists(path+item.name, (exists) => {
|
|
|
+ if (exists) {
|
|
|
+ fs.exists(newPath, (new_exists) => {
|
|
|
+ if(!new_exists) {
|
|
|
+ fs.rename(path+item.name, newPath, (err) => {
|
|
|
+ if(err){
|
|
|
+ item.status = "3"; throw err;
|
|
|
+ }else{
|
|
|
+ item.status = "2"; // 修改成功
|
|
|
+ item.name = item.newName;
|
|
|
+ item.path = newPath;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ item.status = "5"; // 文件已存在
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ item.status = "4"; // 文件被修改
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 拖拽排序
|
|
|
+ dragEnd(event){
|
|
|
+ this.sortChange(this.mergeData.sortType);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除拼接图片
|
|
|
+ deleteMerge(index, tips){
|
|
|
+ this.$confirm('确认删除这张图片吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ if(tips == 'crop'){ // 删除裁剪图片
|
|
|
+ this.cropList.splice(index, 1);
|
|
|
+ if(this.cropList.length > 0){
|
|
|
+ this.cropImgIndex = 0;
|
|
|
+ this.cropOptions.img = this.cropList[0].path;
|
|
|
+ this.cropOptionsImgInfo = this.cropList[0];
|
|
|
+ this.cropImgLoading = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ }else{
|
|
|
+ this.mergeList.splice(index, 1);
|
|
|
+ this.sortChange(this.mergeData.sortType);
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+
|
|
|
+ });
|
|
|
+ event.stopPropagation();
|
|
|
+ },
|
|
|
+ // 移动图片
|
|
|
+ move(id){
|
|
|
+ let that = this;
|
|
|
+ let obj = document.getElementById('merge-imgId-'+id);
|
|
|
+ let currentWidth = obj.offsetWidth; // 当前元素的宽
|
|
|
+ let currentHeight = obj.offsetHeight; // 当前元素的高
|
|
|
+ let parentWidth = obj.parentElement.offsetWidth; // 父元素的宽
|
|
|
+ let parentHeight = obj.parentElement.offsetHeight; // 父元素的高
|
|
|
+ obj.onmousedown = function(e) { //鼠标按下事件
|
|
|
+ e = e || window.event; //事件对象
|
|
|
+ let x_down = e.clientX; //鼠标按下X的坐标
|
|
|
+ let y_down = e.clientY; //鼠标按下Y的坐标
|
|
|
+ let leftDown = this.offsetLeft; //获取盒子的初始left值
|
|
|
+ let topDown = this.offsetTop; //获取盒子的初始top值
|
|
|
+ obj.parentElement.style.border = "2px solid #ed4014";
|
|
|
+ document.onmousemove = function(e) { //鼠标移动事件
|
|
|
+ // console.log(e.fromElement, e.toElement);
|
|
|
+ e = e || window.event;
|
|
|
+ let x_move = e.clientX; //鼠标移动X的坐标
|
|
|
+ let y_move = e.clientY; //鼠标移动Y的坐标
|
|
|
+ //移动的坐标减去按下的坐标 = 移动的距离
|
|
|
+ let x_now = x_move - x_down;
|
|
|
+ let y_now = y_move - y_down;
|
|
|
+ let top = topDown + y_now;
|
|
|
+ let left = leftDown + x_now;
|
|
|
+ //赋值给left和top
|
|
|
+ obj.style.top = top / parentHeight * 100 + '%'; //top + 'px';
|
|
|
+ obj.style.left = left / parentWidth * 100 + '%'; //left + 'px';
|
|
|
+ if(top > 0){
|
|
|
+ top = 0;
|
|
|
+ obj.style.top = 0;
|
|
|
+ }
|
|
|
+ if(left > 0){
|
|
|
+ left = 0;
|
|
|
+ obj.style.left = 0;
|
|
|
+ }
|
|
|
+ if(left < parentWidth - currentWidth ){
|
|
|
+ left = parentWidth - currentWidth;
|
|
|
+ obj.style.left = (parentWidth - currentWidth) / parentWidth * 100 + '%'; //parentWidth - currentWidth + 'px';
|
|
|
+ }
|
|
|
+ if(top < parentHeight - currentHeight){
|
|
|
+ top = parentHeight - currentHeight;
|
|
|
+ obj.style.top = (parentHeight - currentHeight) / parentHeight * 100 + '%'; //parentHeight - currentHeight + 'px';
|
|
|
+ }
|
|
|
+ that.mergeList[id].top = Math.abs(top / parentHeight);
|
|
|
+ that.mergeList[id].left = Math.abs(left / parentWidth);
|
|
|
+ }
|
|
|
+ document.onmouseup = function() { //鼠标抬起事件
|
|
|
+ //清除移动和抬起事件
|
|
|
+ obj.parentElement.style.border = "none";
|
|
|
+ this.onmousemove = this.onmouseup = null;
|
|
|
+ }
|
|
|
+ return false //阻止默认事件
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //
|
|
|
+ outWidthChange(e){
|
|
|
+ let scale = Number(this.mergeData.scale.split(':')[0]) / Number(this.mergeData.scale.split(':')[1]);
|
|
|
+ this.mergeData.outHeight = Math.round(this.mergeData.outWidth / scale);
|
|
|
+ if(this.mergeData.sortType == 3){
|
|
|
+ this.mergeData.height = this.mergeData.outHeight;
|
|
|
+ this.mergeData.width = this.mergeData.outWidth;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ //
|
|
|
+ outHeightChange(e){
|
|
|
+ let scale = Number(this.mergeData.scale.split(':')[0]) / Number(this.mergeData.scale.split(':')[1]);
|
|
|
+ this.mergeData.outWidth = Math.round(this.mergeData.outHeight * scale);
|
|
|
+ if(this.mergeData.sortType == 3){
|
|
|
+ this.mergeData.height = this.mergeData.outHeight;
|
|
|
+ this.mergeData.width = this.mergeData.outWidth;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ //
|
|
|
+ widthChange(e){
|
|
|
+ let scale = Number(this.mergeData.scale.split(':')[0]) / Number(this.mergeData.scale.split(':')[1]);
|
|
|
+ if(this.mergeData.lockScale){ // 锁定比例
|
|
|
+ this.mergeData.height = Math.round(this.mergeData.width / scale);
|
|
|
+ }
|
|
|
+ let percent = this.mergeData.height / this.mergeData.width * 50;
|
|
|
+ this.mergeData.autoStyle = "padding-top: " + percent + "%;";
|
|
|
+ },
|
|
|
+
|
|
|
+ //
|
|
|
+ heightChange(e){
|
|
|
+ let scale = Number(this.mergeData.scale.split(':')[0]) / Number(this.mergeData.scale.split(':')[1]);
|
|
|
+ if(this.mergeData.lockScale){ // 锁定比例
|
|
|
+ this.mergeData.width = Math.round(this.mergeData.height * scale);
|
|
|
+ }
|
|
|
+ let percent = this.mergeData.height / this.mergeData.width * 50;
|
|
|
+ this.mergeData.autoStyle = "padding-top: " + percent + "%;";
|
|
|
+ },
|
|
|
+
|
|
|
+ //
|
|
|
+ sizeChange(e){
|
|
|
+ if(this.mergeData.sortType == 1){ // 1、横图 2、竖图
|
|
|
+ let spaceReal = this.mergeList[0].height * this.mergeData.space / 500;
|
|
|
+ let borderReal = this.mergeList[0].height * this.mergeData.border / 500;
|
|
|
+ this.mergeData.width = Number((this.mergeData.contentWidth + spaceReal * (this.mergeList.length - 1) + borderReal * 2).toFixed(0));
|
|
|
+ this.mergeData.height = Number((this.mergeData.contentHeight + borderReal * 2).toFixed(0));
|
|
|
+ }else if(this.mergeData.sortType == 2){
|
|
|
+ let spaceReal = this.mergeList[0].width * this.mergeData.space / 500;
|
|
|
+ let borderReal = this.mergeList[0].width * this.mergeData.border / 500;
|
|
|
+ this.mergeData.width = Number((this.mergeData.contentWidth + borderReal * 2).toFixed(0));
|
|
|
+ this.mergeData.height = Number((this.mergeData.contentHeight + spaceReal * (this.mergeList.length - 1) + borderReal * 2).toFixed(0));
|
|
|
+ }
|
|
|
+ this.mergeData.scale = this.mergeData.width + ':' + this.mergeData.height;
|
|
|
+ let scale = Number(this.mergeData.scale.split(':')[0]) / Number(this.mergeData.scale.split(':')[1]);
|
|
|
+ if(this.mergeData.sortType == 1){
|
|
|
+ this.mergeData.outWidth = Math.round(this.mergeData.outHeight * scale);
|
|
|
+ }else if(this.mergeData.sortType == 2){
|
|
|
+ this.mergeData.outHeight = Math.round(this.mergeData.outWidth / scale);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 失焦事件
|
|
|
+ numBlur(str){
|
|
|
+ if(!this.mergeData[str]){
|
|
|
+ this.mergeData[str] = 0;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选择排序模式 1、横图 2、竖图 3、自定义
|
|
|
+ sortChange(e){
|
|
|
+ let canvasWidth = 0;
|
|
|
+ let canvasHeight = 0;
|
|
|
+ if(e == 1){
|
|
|
+ canvasWidth = 0;
|
|
|
+ canvasHeight = this.mergeList[0].height;
|
|
|
+ this.mergeList.map(item => {
|
|
|
+ let width = Number(canvasHeight * (item.width / item.height));
|
|
|
+ canvasWidth = canvasWidth + width;
|
|
|
+ })
|
|
|
+ }else if(e == 2){
|
|
|
+ canvasWidth = this.mergeList[0].width;
|
|
|
+ canvasHeight = 0;
|
|
|
+ this.mergeList.map(item => {
|
|
|
+ let height = Number(canvasWidth / (item.width / item.height));
|
|
|
+ canvasHeight = canvasHeight + height;
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ canvasWidth = 1200;
|
|
|
+ canvasHeight = 1200;
|
|
|
+ this.mergeData.autoStyle = 'padding-top: 50%;';
|
|
|
+ }
|
|
|
+ this.mergeData.contentWidth = Number(canvasWidth.toFixed(0));
|
|
|
+ this.mergeData.contentHeight = Number(canvasHeight.toFixed(0));
|
|
|
+ this.mergeData.width = Number(canvasWidth.toFixed(0));
|
|
|
+ this.mergeData.height = Number(canvasHeight.toFixed(0));
|
|
|
+ this.mergeData.scale = this.mergeData.width + ':' + this.mergeData.height;
|
|
|
+ this.mergeData.outWidth = Number(canvasWidth.toFixed(0));
|
|
|
+ this.mergeData.outHeight = Number(canvasHeight.toFixed(0));
|
|
|
+ this.sizeChange();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 缩放
|
|
|
+ zoom(flag){
|
|
|
+ if(flag == 'reduce'){ // 缩小
|
|
|
+ if(this.mergeData.zoom > 0.7){
|
|
|
+ this.mergeData.zoom -= 0.1;
|
|
|
+ }
|
|
|
+ }else{ // 放大
|
|
|
+ if(this.mergeData.zoom < 2){
|
|
|
+ this.mergeData.zoom += 0.1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 修改画布大小
|
|
|
+ canvasChange(e){
|
|
|
+ let regex = /([1-9]*:[1-9]*)/g;
|
|
|
+ let val = e.match(regex)[0];
|
|
|
+ let str = 'padding-top: 50%;';
|
|
|
+ let width = 1200;
|
|
|
+ let height = 1200;
|
|
|
+ switch(val){
|
|
|
+ case '1:1': // 1:1 1200:1200
|
|
|
+ str = 'padding-top: 50%;';
|
|
|
+ width = 1200;
|
|
|
+ height = 1200;
|
|
|
+ break;
|
|
|
+ case '2:3': // 2:3 1200:1800
|
|
|
+ str = 'padding-top: 75%;';
|
|
|
+ width = 1200;
|
|
|
+ height = 1800;
|
|
|
+ break;
|
|
|
+ case '3:2': // 3:2 1800:1200
|
|
|
+ str = 'padding-top: 33.333%;';
|
|
|
+ width = 1800;
|
|
|
+ height = 1200;
|
|
|
+ break;
|
|
|
+ case '3:4': // 3:4 1200:1600
|
|
|
+ str = 'padding-top: 66.666%;';
|
|
|
+ width = 1200;
|
|
|
+ height = 1600;
|
|
|
+ break;
|
|
|
+ case '4:3': // 4:3 1600:1200
|
|
|
+ str = 'padding-top: 37.5%;';
|
|
|
+ width = 1600;
|
|
|
+ height = 1200;
|
|
|
+ break;
|
|
|
+ case '16:9': // 16:9 1920:1080
|
|
|
+ str = 'padding-top: 28.125%;';
|
|
|
+ width = 1920;
|
|
|
+ height = 1080;
|
|
|
+ break;
|
|
|
+ case '9:16': // 9:16 1080:1920
|
|
|
+ str = 'padding-top: 88.888%;';
|
|
|
+ width = 1080;
|
|
|
+ height = 1920;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ this.mergeData.autoStyle = str;
|
|
|
+ this.mergeData.width = width;
|
|
|
+ this.mergeData.height = height;
|
|
|
+ this.mergeData.outWidth= width;
|
|
|
+ this.mergeData.outHeight = height;
|
|
|
+ this.mergeData.scale = val;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 自定义块样式
|
|
|
+ blockStyle(flag){
|
|
|
+ let str = '';
|
|
|
+ let spacePix = this.mergeData.width * (this.mergeData.space / 10 / 100); //间距的宽度 -> 间距的百分比以宽为基数
|
|
|
+ let heightSpace = spacePix / this.mergeData.height * 100;
|
|
|
+
|
|
|
+ if(flag == 'height'){
|
|
|
+ str = 'height: ' + (100 / this.mergeData.row - (heightSpace * (this.mergeData.row - 1) / this.mergeData.row)) + '%;'
|
|
|
+ }else{
|
|
|
+ str = 'width:' + (100 / this.mergeData.col - (this.mergeData.space / 10 * (this.mergeData.col - 1) / this.mergeData.col)) + '%;border-radius:'+ this.mergeData.radius / 2 +'%;'
|
|
|
+ }
|
|
|
+ return str;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 行数列数发生变化 图片位置初始化0
|
|
|
+ rowColChange(){
|
|
|
+ let num = this.mergeData.row * this.mergeData.col;
|
|
|
+ this.mergeList.map((item, index) => {
|
|
|
+ item.top = 0;
|
|
|
+ item.left = 0;
|
|
|
+ if(index < num && document.getElementById('merge-imgId-'+index)){
|
|
|
+ document.getElementById('merge-imgId-'+index).style.top = 0;
|
|
|
+ document.getElementById('merge-imgId-'+index).style.left = 0;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 图片自适应宽高
|
|
|
+ picStyle(index){
|
|
|
+ let imgWidth = this.mergeList[index].width; // 图高
|
|
|
+ let imgHeight = this.mergeList[index].height; // 图高
|
|
|
+ let blockWidth = this.mergeData.width / this.mergeData.col; // 块宽
|
|
|
+ let blockHeight = this.mergeData.height / this.mergeData.row; // 块高
|
|
|
+ let str = "width: 100%;";
|
|
|
+ let fillType = "width";
|
|
|
+
|
|
|
+ if(imgWidth > imgHeight){
|
|
|
+ if(blockWidth <= blockHeight){
|
|
|
+ str = "height: 100%";
|
|
|
+ fillType = "height";
|
|
|
+ }else{
|
|
|
+ str = (blockWidth / blockHeight) >= (imgWidth / imgHeight) ? "width:100%;" : "height:100%;";
|
|
|
+ fillType = (blockWidth / blockHeight) >= (imgWidth / imgHeight) ? "width" : "height";
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(blockWidth >= blockHeight){
|
|
|
+ str = "width: 100%;";
|
|
|
+ fillType = "width";
|
|
|
+ }else{
|
|
|
+ if(imgWidth == imgHeight){
|
|
|
+ str = "height:100%;";
|
|
|
+ fillType = "height";
|
|
|
+ }else{
|
|
|
+ str = blockWidth / blockHeight >= imgWidth / imgHeight ? "width:100%;" : "height:100%;";
|
|
|
+ fillType = blockWidth / blockHeight >= imgWidth / imgHeight ? "width" : "height";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.mergeList[index].fillType = fillType;
|
|
|
+ return str;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 图片拼接-自定义
|
|
|
+ exportMerge(){ // 先按照移动比列裁剪 在拼接图片
|
|
|
+ //convert src.jpg -resize 500x500 -crop 100x80+50+30 dest.jpg
|
|
|
+ clearInterval(this.mergeInterval);
|
|
|
+ this.mergeLoading = this.$loading({
|
|
|
+ lock: true,
|
|
|
+ text: '图片处理中,请稍后...',
|
|
|
+ spinner: 'el-icon-loading',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+ setTimeout(()=>{ // 3分钟后加载层消失防止进程出错
|
|
|
+ this.mergeLoading.close();
|
|
|
+ }, 1000 * 60 * 3);
|
|
|
+ let borderWidth = this.mergeData.width * (this.mergeData.border / 10 / 100); // 边框的宽度
|
|
|
+ let spaceWidth = this.mergeData.width * (this.mergeData.space / 10 / 100);; // 间距的宽度
|
|
|
+ let blockWidth = (this.mergeData.width - borderWidth * 2 - spaceWidth * (this.mergeData.col - 1)) / this.mergeData.col; // 块宽
|
|
|
+ let blockHeight = (this.mergeData.height - borderWidth * 2 - spaceWidth * (this.mergeData.row - 1)) / this.mergeData.row; // 块高
|
|
|
+ let radiusWidth = this.mergeData.radius / 2 / 100 * blockWidth || 0;
|
|
|
+
|
|
|
+ let newFolderPath = this.handleData.newPath;
|
|
|
+ let newTime = new Date().getTime();
|
|
|
+ fs.mkdirSync(os.tmpdir() + separator + pjson.softInfo.softMid+newTime);
|
|
|
+ newFolderPath = os.tmpdir() + separator + pjson.softInfo.softMid+newTime;
|
|
|
+ let dealNum = 0;
|
|
|
+ let errorIndex = -1;
|
|
|
+ let imgParamsArr = []; // 所有图片的位置参数
|
|
|
+
|
|
|
+ // 生成圆角MASK遮盖层 convert -size "$W"x"$H" xc:none -draw "roundrectangle 0,0,$W,$H,$R,$R" $MASK
|
|
|
+ let maskPath = os.tmpdir()+separator+'radius.png';
|
|
|
+ let radiusStr = 'roundrectangle 0,0,'+blockWidth+','+blockHeight+','+radiusWidth+','+radiusWidth;
|
|
|
+ if(this.mergeData.radius == 0){
|
|
|
+ radiusStr = 'rectangle 0,0,'+blockWidth+','+blockHeight;
|
|
|
+ }
|
|
|
+ let paramsRadius = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-size',
|
|
|
+ blockWidth+'x'+blockHeight,
|
|
|
+ 'xc:none',
|
|
|
+ '-draw',
|
|
|
+ radiusStr,
|
|
|
+ maskPath
|
|
|
+ ];
|
|
|
+ electronApi.spawnExec(paramsRadius).then(res => {
|
|
|
+ setTimeout(() => { // 延迟执行
|
|
|
+ for(let index = 0; index < this.mergeList.length; index++){
|
|
|
+ let item = this.mergeList[index];
|
|
|
+ if(index < this.mergeData.row * this.mergeData.col){ // 自定义排序
|
|
|
+ let imgRealWidth = 0;
|
|
|
+ let imgRealHeight = 0;
|
|
|
+ let top = 0;
|
|
|
+ let left = 0;
|
|
|
+ let cropParams = [];
|
|
|
+
|
|
|
+ if(this.mergeData.mergeType == 1){ // 自适应模式
|
|
|
+ if(item.fillType == 'width'){
|
|
|
+ imgRealHeight = blockHeight;
|
|
|
+ imgRealWidth = imgRealHeight * (item.width / item.height);
|
|
|
+ }else{
|
|
|
+ imgRealWidth = blockWidth;
|
|
|
+ imgRealHeight = imgRealWidth / (item.width / item.height);
|
|
|
+ }
|
|
|
+ top = (blockHeight - imgRealHeight) / 2;
|
|
|
+ left = (blockWidth - imgRealWidth) / 2;
|
|
|
+ }else{ // 自定义裁剪模式
|
|
|
+ if(item.fillType == 'width'){
|
|
|
+ imgRealWidth = blockWidth;
|
|
|
+ imgRealHeight = imgRealWidth / (item.width / item.height);
|
|
|
+ }else{
|
|
|
+ imgRealHeight = blockHeight;
|
|
|
+ imgRealWidth = imgRealHeight * (item.width / item.height);
|
|
|
+ }
|
|
|
+ top = item.top * blockHeight;
|
|
|
+ left = item.left * blockWidth;
|
|
|
+ cropParams = ['-crop',blockWidth+'x'+blockHeight+'+'+left+'+'+top];
|
|
|
+ }
|
|
|
+
|
|
|
+ let newTime2 = new Date().getTime();
|
|
|
+ let newPath = newFolderPath + separator + item.name.slice(0, item.name.lastIndexOf('.')) +newTime2+Math.random()+ '.png';
|
|
|
+ // convert $SRC -matte $MASK -compose DstIn -composite $TMP_PNG
|
|
|
+ let params = [
|
|
|
+ 'convert.exe',
|
|
|
+ item.path,
|
|
|
+ '-resize',
|
|
|
+ imgRealWidth+'x'+imgRealHeight,
|
|
|
+ ...cropParams,
|
|
|
+ '-matte',
|
|
|
+ maskPath,
|
|
|
+ '-compose',
|
|
|
+ 'DstIn',
|
|
|
+ '-composite',
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ let currentRow = Math.floor(index / this.mergeData.col) + 1;
|
|
|
+ let currentCol = index % this.mergeData.col + 1;
|
|
|
+
|
|
|
+ let imgPositionX = borderWidth + blockWidth * (currentCol - 1) + spaceWidth * (currentCol - 1);
|
|
|
+ let imgPositionY = borderWidth + blockHeight * (currentRow - 1) + spaceWidth * (currentRow - 1);
|
|
|
+ if(this.mergeData.mergeType == 1){ // 自适应
|
|
|
+ imgPositionX = imgPositionX + left;
|
|
|
+ imgPositionY = imgPositionY + top;
|
|
|
+ }
|
|
|
+ let imgParams = [newPath, '-geometry', '+'+imgPositionX+'+'+imgPositionY, '-composite'];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params).then(res => {
|
|
|
+ dealNum ++;
|
|
|
+ imgParamsArr = imgParamsArr.concat(imgParams);
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ errorIndex = index;
|
|
|
+ this.$notify.error({
|
|
|
+ title: '第【'+Number(index+1)+'】张图片出错',
|
|
|
+ message: '请调整后重试!' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.mergeInterval = setInterval(() => {
|
|
|
+ if(this.mergeData.row * this.mergeData.col == dealNum || dealNum == this.mergeList.length){ // 裁剪完成 准备拼接图片
|
|
|
+ clearInterval(this.mergeInterval);
|
|
|
+ // 拼接命令参数 ['2.jpg', '-geometry', '+256+0', '-composite'];
|
|
|
+ let suffix = '.jpg';
|
|
|
+ if(Number(this.mergeData.backgroundColor.match(/[\d.]+/g)[3]) < 1){
|
|
|
+ suffix = '.png';
|
|
|
+ }
|
|
|
+ let outPath = this.handleData.newPath+separator+pjson.softInfo.softName+separator+'图片拼接'+this.$utils.formatTime(newTime/1000)+suffix;
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-size',
|
|
|
+ this.mergeData.width+'x'+this.mergeData.height,
|
|
|
+ '-strip',
|
|
|
+ 'xc:'+this.mergeData.backgroundColor,
|
|
|
+ ...imgParamsArr,
|
|
|
+ outPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params2).then(res => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ this.$message({message: '恭喜你,图片拼接完成!', type: 'success'});
|
|
|
+ try{
|
|
|
+ // 未购买 添加系统水印
|
|
|
+ this.addWatermark(0, {width:this.mergeData.width, height: this.mergeData.height}, outPath);
|
|
|
+ // 删除裁剪的图片
|
|
|
+ fs.readdir(newFolderPath, (err, files) => {
|
|
|
+ for (let i = 0; i < files.length; i++) {
|
|
|
+ let statFile = newFolderPath+separator+files[i];
|
|
|
+ fs.unlinkSync(statFile);
|
|
|
+ }
|
|
|
+ fs.rmdir(newFolderPath, (err) => {
|
|
|
+ if(err){
|
|
|
+ console.log(err);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }catch(e){
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+ setTimeout(() => { // 延迟打开
|
|
|
+ electronApi.call('showItemInfolder',[outPath])
|
|
|
+ }, 1000);
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ this.$notify.error({
|
|
|
+ title: '图片拼接失败-3',
|
|
|
+ message: '请调整后重试!' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }else if(errorIndex >= 0){ // 文件处理出错
|
|
|
+ clearInterval(this.mergeInterval);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ }, 300)
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ this.$notify.error({
|
|
|
+ title: '图片【'+Number(index+1)+'】出错',
|
|
|
+ message: '请调整后重试!遮盖层' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ console.log('圆角遮盖层创建失败',err.stderr.toString())
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 图片拼接-横图和竖图
|
|
|
+ exportMerge2(){ // 先按照移动比列裁剪 在拼接图片
|
|
|
+ //convert src.jpg -resize 500x500 -crop 100x80+50+30 dest.jpg
|
|
|
+ clearInterval(this.mergeInterval);
|
|
|
+ this.mergeLoading = this.$loading({
|
|
|
+ lock: true,
|
|
|
+ text: '图片处理中,请稍后...',
|
|
|
+ spinner: 'el-icon-loading',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+ setTimeout(()=>{ // 3分钟后加载层消失防止进程出错
|
|
|
+ this.mergeLoading.close();
|
|
|
+ }, 1000 * 60 * 3);
|
|
|
+
|
|
|
+ let newFolderPath = this.handleData.newPath;
|
|
|
+ let newTime = new Date().getTime();
|
|
|
+ fs.mkdirSync(os.tmpdir() + separator + pjson.softInfo.softMid+newTime);
|
|
|
+ newFolderPath = os.tmpdir() + separator + pjson.softInfo.softMid+newTime;
|
|
|
+
|
|
|
+ setTimeout(async() => { // 延迟执行
|
|
|
+ let contentWidth = 0, contentHeight = 0;
|
|
|
+ let dealNum = 0;
|
|
|
+ let errorIndex = -1;
|
|
|
+ let imgParamsArr = []; // 所有图片的位置参数
|
|
|
+ for(let index = 0; index < this.mergeList.length; index++){
|
|
|
+ let item = this.mergeList[index];
|
|
|
+ let firstItem = this.mergeList[0];
|
|
|
+
|
|
|
+ let borderWidth = 0, spaceWidth = 0, blockWidth = 0, blockHeight = 0, radiusWidth = 0;
|
|
|
+ if(this.mergeData.sortType == 1){ // 横版
|
|
|
+ borderWidth = firstItem.height * (this.mergeData.border / 500); // 边框的宽度
|
|
|
+ spaceWidth = firstItem.height * (this.mergeData.space / 500); // 间距的宽度
|
|
|
+ blockWidth = item.width / (item.height / firstItem.height);
|
|
|
+ blockHeight = firstItem.height;
|
|
|
+ radiusWidth = this.mergeData.radius / 2 / 100 * blockWidth || 0;
|
|
|
+ }else if(this.mergeData.sortType == 2){ // 竖版
|
|
|
+ borderWidth = firstItem.width * (this.mergeData.border / 500); // 边框的宽度
|
|
|
+ spaceWidth = firstItem.width * (this.mergeData.space / 500); // 间距的宽度
|
|
|
+ blockHeight = item.height / (item.width / firstItem.width);
|
|
|
+ blockWidth = firstItem.width;
|
|
|
+ radiusWidth = this.mergeData.radius / 2 / 100 * blockWidth || 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成圆角MASK遮盖层 convert -size "$W"x"$H" xc:none -draw "roundrectangle 0,0,$W,$H,$R,$R" $MASK
|
|
|
+ let maskPath = os.tmpdir()+separator+'radius'+index+'.png';
|
|
|
+ let radiusStr = 'roundrectangle 0,0,'+blockWidth+','+blockHeight+','+radiusWidth+','+radiusWidth;
|
|
|
+ if(this.mergeData.radius == 0){
|
|
|
+ radiusStr = 'rectangle 0,0,'+blockWidth+','+blockHeight;
|
|
|
+ }
|
|
|
+ let paramsRadius = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-size',
|
|
|
+ blockWidth+'x'+blockHeight,
|
|
|
+ 'xc:none',
|
|
|
+ '-draw',
|
|
|
+ radiusStr,
|
|
|
+ maskPath
|
|
|
+ ];
|
|
|
+ await electronApi.spawnExec(paramsRadius).then(async(res) => {
|
|
|
+ let newTime2 = new Date().getTime();
|
|
|
+ let newPath = newFolderPath + separator + item.name.slice(0, item.name.lastIndexOf('.')) +newTime+Math.random()+ '.png';
|
|
|
+ let params = [
|
|
|
+ 'convert.exe',
|
|
|
+ item.path,
|
|
|
+ '-resize',
|
|
|
+ blockWidth+'x'+blockHeight,
|
|
|
+ '-matte',
|
|
|
+ maskPath,
|
|
|
+ '-compose',
|
|
|
+ 'DstIn',
|
|
|
+ '-composite',
|
|
|
+ newPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ contentWidth += blockWidth;
|
|
|
+ contentHeight += blockHeight;
|
|
|
+
|
|
|
+ let imgPositionX = 0;
|
|
|
+ let imgPositionY = 0;
|
|
|
+ if(this.mergeData.sortType == 1){ // 横版
|
|
|
+ imgPositionX = borderWidth + (contentWidth - blockWidth) + spaceWidth * index;
|
|
|
+ imgPositionY = borderWidth;
|
|
|
+ }else if(this.mergeData.sortType == 2){ // 竖版
|
|
|
+ imgPositionX = borderWidth;
|
|
|
+ imgPositionY = borderWidth + (contentHeight - blockHeight) + spaceWidth * index;
|
|
|
+ }
|
|
|
+
|
|
|
+ let imgParams = [newPath, '-geometry', '+'+imgPositionX+'+'+imgPositionY, '-composite'];
|
|
|
+ await electronApi.spawnExec(params).then(res => {
|
|
|
+ dealNum ++;
|
|
|
+ imgParamsArr = imgParamsArr.concat(imgParams);
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ errorIndex = index;
|
|
|
+ this.$notify.error({
|
|
|
+ title: '图片【'+Number(index+1)+'】出错',
|
|
|
+ message: '请调整后重试!' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ this.$notify.error({
|
|
|
+ title: '图片【'+Number(index+1)+'】出错',
|
|
|
+ message: '请调整后重试!遮盖层' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ console.log('圆角遮盖层创建失败',err.stderr.toString())
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ this.mergeInterval = setInterval(() => {
|
|
|
+ if(dealNum == this.mergeList.length){ // 裁剪完成 准备拼接图片
|
|
|
+ clearInterval(this.mergeInterval);
|
|
|
+ // 拼接命令参数 ['2.jpg', '-geometry', '+256+0', '-composite'];
|
|
|
+ let suffix = '.jpg';
|
|
|
+ if(Number(this.mergeData.backgroundColor.match(/[\d.]+/g)[3]) < 1){
|
|
|
+ suffix = '.png';
|
|
|
+ }
|
|
|
+ let outPath = this.handleData.newPath+separator+pjson.softInfo.softName+separator+'图片拼接'+this.$utils.formatTime(newTime/1000)+suffix;
|
|
|
+ let params2 = [
|
|
|
+ 'convert.exe',
|
|
|
+ '-size',
|
|
|
+ this.mergeData.width+'x'+this.mergeData.height,
|
|
|
+ '-strip',
|
|
|
+ 'xc:'+this.mergeData.backgroundColor,
|
|
|
+ ...imgParamsArr,
|
|
|
+ '-resize',
|
|
|
+ Number(this.mergeData.outWidth / this.mergeData.width) * 100 + '%',
|
|
|
+ outPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ electronApi.spawnExec(params2).then(res => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ this.$message({message: '恭喜你,图片拼接完成!', type: 'success'});
|
|
|
+ try{
|
|
|
+ // 未购买 添加系统水印
|
|
|
+ this.addWatermark(0, {width:this.mergeData.outWidth, height: this.mergeData.outHeight}, outPath);
|
|
|
+ // 删除裁剪的图片
|
|
|
+ fs.readdir(newFolderPath, (err, files) => {
|
|
|
+ for (let i = 0; i < files.length; i++) {
|
|
|
+ let statFile = newFolderPath+separator+files[i];
|
|
|
+ fs.unlinkSync(statFile);
|
|
|
+ }
|
|
|
+ fs.rmdir(newFolderPath, (err) => {
|
|
|
+ if(err){
|
|
|
+ console.log(err);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }catch(e){
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+ setTimeout(() => { // 延迟打开
|
|
|
+ electronApi.call('showItemInfolder',[outPath])
|
|
|
+ }, 1000);
|
|
|
+ }).catch(err => {
|
|
|
+ this.mergeLoading.close();
|
|
|
+ this.$notify.error({
|
|
|
+ title: '图片拼接失败',
|
|
|
+ message: '请调整后重试!' + err.stderr.toString()
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }else if(errorIndex >= 0){ // 文件处理出错
|
|
|
+ clearInterval(this.mergeInterval);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ }, 300)
|
|
|
+ },
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+ @import '../assets/css/font/iconfont.css';
|
|
|
+ @import '../assets/css/home.scss';
|
|
|
+
|
|
|
+ .ivu-input-number-controls-outside-btn i{
|
|
|
+ font-weight: 800;
|
|
|
+ }
|
|
|
+
|
|
|
+ .update-point{
|
|
|
+ display: inline-block;
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #ff0000;
|
|
|
+ top: 14px;
|
|
|
+ position: absolute;
|
|
|
+ left: -13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title-flex{
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ justify-content: flex-start;
|
|
|
+ }
|
|
|
+ .demo-spin-icon-load{
|
|
|
+ animation: ani-demo-spin 1s linear infinite;
|
|
|
+ }
|
|
|
+
|
|
|
+ .line-density{
|
|
|
+ display: inline-block;
|
|
|
+ width: calc(100% - 74px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .handle-item{
|
|
|
+ .handle-label{
|
|
|
+ width: 70px;
|
|
|
+ }
|
|
|
+ .ivu-input-number-handler-wrap{
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .set-height{
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .merge-flex{
|
|
|
+ padding: 10px;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ justify-content: flex-start;
|
|
|
+
|
|
|
+ .merge-content{
|
|
|
+ width: calc(100% - 140px);
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .merge-top{
|
|
|
+ overflow: hidden;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-right{
|
|
|
+ width: 70px;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ justify-content: space-between;
|
|
|
+ line-height: 1;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ .action-ritem:hover{
|
|
|
+ color: #ce0000;
|
|
|
+ }
|
|
|
+
|
|
|
+ .iconfont{
|
|
|
+ font-size: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .merge-left{
|
|
|
+ width: 110px;
|
|
|
+ text-align: center;
|
|
|
+ height: 100%;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+ .img-area{
|
|
|
+ width: 90px;
|
|
|
+ height: 60px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 56px;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ }
|
|
|
+ .merge-scroll{
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ overflow: hidden auto;
|
|
|
+ position: relative;
|
|
|
+ width: 130px;
|
|
|
+ flex-direction: column;
|
|
|
+ margin-right: 8px;
|
|
|
+ }
|
|
|
+ .merge-item{
|
|
|
+ width: 90px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+ .merge-imgdel{
|
|
|
+ position: absolute;
|
|
|
+ right: -8px;
|
|
|
+ top: 0px;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 2px;
|
|
|
+ background-color: #ccc;
|
|
|
+ border-radius: 50%;
|
|
|
+ color: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover{
|
|
|
+ background-color: #ce0000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .mergelist-img{
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 100%;
|
|
|
+ vertical-align: middle;
|
|
|
+ }
|
|
|
+ .merge-name{
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow:ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ }
|
|
|
+ .mer-title{
|
|
|
+ font-weight: 600;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar {
|
|
|
+ /*滚动条整体样式*/
|
|
|
+ width: 6px; /*高宽分别对应横竖滚动条的尺寸*/
|
|
|
+ height: 6px;
|
|
|
+ }
|
|
|
+ ::-webkit-scrollbar-thumb {
|
|
|
+ /*滚动条里面小方块*/
|
|
|
+ border-radius: 10px;
|
|
|
+ box-shadow: inset 0 0 5px rgba(97, 184, 179, 0.1);
|
|
|
+ background: #666;
|
|
|
+ }
|
|
|
+ ::-webkit-scrollbar-track {
|
|
|
+ /*滚动条里面轨道*/
|
|
|
+ box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1);
|
|
|
+ border-radius: 10px;
|
|
|
+ background: #ededed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .mlist-scroll{
|
|
|
+ overflow: auto;
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 5px;
|
|
|
+ height: calc(100% - 45px);
|
|
|
+
|
|
|
+ &.bgmini{
|
|
|
+ background: url('../assets/image/bgmini.png');
|
|
|
+ }
|
|
|
+
|
|
|
+ .mlist-content{
|
|
|
+ width: 50%;
|
|
|
+ position: relative;
|
|
|
+ box-shadow: 2px 2px 6px #ddd, -2px -2px 6px #ddd;
|
|
|
+ margin: auto;
|
|
|
+ transform-origin: 50% 0;
|
|
|
+ }
|
|
|
+ .mlist-area{
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+ .merge-row{
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ justify-content: space-between;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ .merge-col{
|
|
|
+ text-align: center;
|
|
|
+ overflow: hidden;
|
|
|
+ position: relative;
|
|
|
+ &:hover{
|
|
|
+ // border: 2px solid #2b83e0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .merge-img{
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ cursor:move;
|
|
|
+ }
|
|
|
+ .merge-img2{
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 100%;
|
|
|
+ vertical-align: middle;
|
|
|
+ position: absolute;
|
|
|
+ top: 0 !important;
|
|
|
+ left: 0 !important;
|
|
|
+ right: 0 !important;
|
|
|
+ bottom: 0 !important;
|
|
|
+ margin: auto;
|
|
|
+ }
|
|
|
+ .merge-add{
|
|
|
+ font-size: 50px;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #fafafa;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover{
|
|
|
+ background-color: #f3f3f3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .disnone{
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 横图
|
|
|
+ .horizontal-scroll{
|
|
|
+ width: 80%;
|
|
|
+ margin: auto;
|
|
|
+ height: 250px;
|
|
|
+ margin-top: 10%;
|
|
|
+ box-shadow: 2px 2px 6px #ddd, -2px -2px 6px #ddd;
|
|
|
+ overflow: auto;
|
|
|
+ box-sizing: content-box;
|
|
|
+ }
|
|
|
+ .horizontal-content{
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ justify-content: flex-start;
|
|
|
+ .horizontal-item{
|
|
|
+ display: flex;
|
|
|
+ }
|
|
|
+ .horizontal-area{
|
|
|
+ display: inline-block;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ .horizontal-img{
|
|
|
+ height: 100%;
|
|
|
+ box-sizing: content-box;
|
|
|
+ flex-shrink: 0;
|
|
|
+ &:last-child{
|
|
|
+ margin-right: 0 !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 竖图
|
|
|
+ .vertical-content{
|
|
|
+ width: 250px;
|
|
|
+ margin: auto;
|
|
|
+ box-shadow: 2px 2px 6px #ddd, -2px -2px 6px #ddd;
|
|
|
+ box-sizing: content-box;
|
|
|
+ .vertical-img{
|
|
|
+ width: 100%;
|
|
|
+ display: inherit;
|
|
|
+ &:last-child{
|
|
|
+ margin-bottom: 0 !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .i-fanzhuan{
|
|
|
+ font-size: 25px;
|
|
|
+ margin-right: 20px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:hover,&.active{
|
|
|
+ color: #ce0000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .flex-crop{
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ justify-content: space-between;
|
|
|
+
|
|
|
+ .crop-button{
|
|
|
+ width: 65px;
|
|
|
+ margin: 10px 0 !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .show-preview{
|
|
|
+ margin: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .popper-open{
|
|
|
+ text-align: center !important;
|
|
|
+ padding: 10px !important;
|
|
|
+ background: #303133 !important;
|
|
|
+ color: #fff !important;
|
|
|
+ min-width: 120px !important;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .popper-open[x-placement^=bottom] .popper__arrow::after{
|
|
|
+ border-bottom-color: #303133 !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-aside,.el-menu{
|
|
|
+ border-right: none !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .vxebtn-del{
|
|
|
+ position: absolute !important;
|
|
|
+ right: 0;
|
|
|
+ top: 10px;
|
|
|
+ color: #F56C6C !important;
|
|
|
+ z-index: 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ .m-image{
|
|
|
+ width: 25px;
|
|
|
+ margin-right: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-menu-item.is-active{
|
|
|
+ font-weight: 800;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-menu-item:hover{
|
|
|
+ font-weight: 800;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+</style>
|