Feature: add buildin watermark process and image resize/compress/rotate/convert feature

This commit is contained in:
萌萌哒赫萝
2023-03-04 20:21:36 +08:00
parent a5b3954534
commit da42bb4897
7 changed files with 861 additions and 38 deletions

View File

@@ -90,6 +90,18 @@
{{ $T('SETTINGS_CLICK_TO_SET') }}
</el-button>
</el-form-item>
<el-form-item
label="设置图片水印和压缩-格式转换等参数"
>
<el-button
type="primary"
round
size="small"
@click="imageProcessDialogVisible = true"
>
{{ $T('SETTINGS_CLICK_TO_SET') }}
</el-button>
</el-form-item>
<el-form-item
:label="$T('SETTINGS_SET_PROXY_AND_MIRROR')"
>
@@ -516,13 +528,221 @@
</el-button>
</template>
</el-dialog>
<el-dialog
v-model="imageProcessDialogVisible"
title="图片处理设置"
width="50%"
draggable
center
align-center
>
<el-form
label-position="top"
require-asterisk-position="right"
label-width="10vw"
size="default"
:model="waterMarkForm"
>
<el-form-item label="是否添加水印">
<el-switch
v-model="waterMarkForm.isAddWatermark"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印类型"
>
<el-radio-group v-model="waterMarkForm.watermarkType">
<el-radio label="text">
文字
</el-radio>
<el-radio label="image">
图片
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="是否全屏水印"
>
<el-switch
v-model="waterMarkForm.isFullScreenWatermark"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印角度"
>
<el-input-number
v-model="waterMarkForm.watermarkDegree"
:step="1"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
label="水印文字"
>
<el-input v-model="waterMarkForm.watermarkText" />
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
label="水印字体路径(留空默认使用simhei.ttf)"
>
<el-input v-model="waterMarkForm.watermarkFontPath" />
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印占原图比例"
>
<el-input-number
v-model="waterMarkForm.watermarkScaleRatio"
:min="0"
:max="1"
:step="0.01"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
label="水印颜色,请从取色器中选择"
>
<el-color-picker
v-model="waterMarkForm.watermarkColor"
show-alpha
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'image'"
label="水印图片路径(留空使用默认图片)"
>
<el-input v-model="waterMarkForm.watermarkImagePath" />
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印位置"
>
<el-radio-group
v-model="waterMarkForm.watermarkPosition"
>
<el-radio
v-for="item in waterMarkPositionMap"
:key="item[0]"
:label="item[0]"
>
{{ item[1] }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="压缩质量">
<el-input-number
v-model="compressForm.quality"
:min="0"
:max="100"
:step="1"
/>
</el-form-item>
<el-form-item label="是否转换格式">
<el-switch
v-model="compressForm.isConvert"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isConvert"
label="选择转换目的格式"
>
<el-select v-model="compressForm.convertFormat">
<el-option
v-for="item in availableFormat"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="是否按固定尺寸调整图片">
<el-switch
v-model="compressForm.isReSize"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isReSize"
label="调整尺寸宽度"
>
<el-input-number
v-model="compressForm.reSizeWidth"
:min="0"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isReSize"
label="调整尺寸高度"
>
<el-input-number
v-model="compressForm.reSizeHeight"
:min="0"
/>
</el-form-item>
<el-form-item label="是否按比例调整尺寸,优先级高于固定尺寸">
<el-switch
v-model="compressForm.isReSizeByPercent"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isReSizeByPercent"
label="调整尺寸比例, 输入50表示50%"
>
<el-input-number
v-model="compressForm.reSizePercent"
:min="0"
/>
</el-form-item>
<el-form-item
label="是否旋转"
>
<el-switch
v-model="compressForm.isRotate"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isRotate"
label="旋转角度"
>
<el-input-number
v-model="compressForm.rotateDegree"
:step="1"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="handelSaveConfig"
>
保存
</el-button>
<el-button @click="closeDialog">
取消
</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ElForm, ElMessage as $message, FormRules } from 'element-plus'
import { Reading, QuestionFilled } from '@element-plus/icons-vue'
import pkg from 'root/package.json'
import { IConfig } from 'piclist'
import { PICGO_OPEN_FILE, OPEN_URL, GET_PICBEDS } from '#/events/constants'
import {
ipcRenderer
@@ -532,10 +752,92 @@ import { enforceNumber } from '~/universal/utils/common'
import { getLatestVersion } from '#/utils/getLatestVersion'
import { compare } from 'compare-versions'
import { STABLE_RELEASE_URL } from '#/utils/static'
import { computed, onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue'
import { computed, onBeforeMount, onBeforeUnmount, reactive, ref, toRaw } from 'vue'
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
import { useRouter } from 'vue-router'
import { SHORTKEY_PAGE } from '@/router/config'
import { IConfig, IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
const imageProcessDialogVisible = ref(false)
const waterMarkPositionMap = new Map([
['north', '上'],
['northeast', '右上'],
['southeast', '右下'],
['south', '下'],
['southwest', '左下'],
['northwest', '左上'],
['west', '左'],
['east', '右'],
['centre', '中']
])
const availableFormat = ['avif', 'dz', 'fits', 'gif', 'heif', 'input', 'jpeg', 'jpg', 'jp2', 'jxl', 'magick', 'openslide', 'pdf', 'png', 'ppm', 'raw', 'svg', 'tiff', 'tif', 'v', 'webp']
const waterMarkForm = reactive<any>({
isAddWatermark: false,
watermarkType: 'text',
isFullScreenWatermark: false,
watermarkDegree: 0,
watermarkText: '',
watermarkFontPath: '',
watermarkScaleRatio: 0.15,
watermarkColor: '#CCCCCC73',
watermarkImagePath: '',
watermarkPosition: 'southeast'
})
const compressForm = reactive<any>({
quality: 100,
isConvert: false,
convertFormat: 'jpg',
isReSize: false,
reSizeWidth: 500,
reSizeHeight: 500,
isReSizeByPercent: false,
reSizePercent: 50,
isRotate: false,
rotateDegree: 0
})
function closeDialog () {
imageProcessDialogVisible.value = false
}
function handelSaveConfig () {
saveConfig('buildIn.compress', toRaw(compressForm))
saveConfig('buildIn.watermark', toRaw(waterMarkForm))
closeDialog()
}
async function initForm () {
const compress = await getConfig<IBuildInCompressOptions>('buildIn.compress')
const watermark = await getConfig<IBuildInWaterMarkOptions>('buildIn.watermark')
if (compress) {
compressForm.quality = compress.quality ?? 100
compressForm.isConvert = compress.isConvert ?? false
compressForm.convertFormat = compress.convertFormat ?? 'jpg'
compressForm.isReSize = compress.isReSize ?? false
compressForm.reSizeWidth = compress.reSizeWidth ?? 500
compressForm.reSizeHeight = compress.reSizeHeight ?? 500
compressForm.isReSizeByPercent = compress.isReSizeByPercent ?? false
compressForm.reSizePercent = compress.reSizePercent ?? 50
compressForm.isRotate = compress.isRotate ?? false
compressForm.rotateDegree = compress.rotateDegree ?? 0
}
if (watermark) {
waterMarkForm.isAddWatermark = watermark.isAddWatermark ?? false
waterMarkForm.watermarkType = watermark.watermarkType ?? 'text'
waterMarkForm.isFullScreenWatermark = watermark.isFullScreenWatermark ?? false
waterMarkForm.watermarkDegree = watermark.watermarkDegree ?? 0
waterMarkForm.watermarkText = watermark.watermarkText ?? ''
waterMarkForm.watermarkFontPath = watermark.watermarkFontPath ?? ''
waterMarkForm.watermarkScaleRatio = watermark.watermarkScaleRatio ?? 0.15
waterMarkForm.watermarkColor = watermark.watermarkColor === undefined || watermark.watermarkColor === '' ? '#CCCCCC73' : watermark.watermarkColor
waterMarkForm.watermarkImagePath = watermark.watermarkImagePath ?? ''
waterMarkForm.watermarkPosition = watermark.watermarkPosition ?? 'southeast'
}
}
const $customLink = ref<InstanceType<typeof ElForm> | null>(null)
@@ -628,6 +930,7 @@ onBeforeMount(() => {
sendToMain(GET_PICBEDS)
ipcRenderer.on(GET_PICBEDS, getPicBeds)
initData()
initForm()
})
async function initData () {

View File

@@ -46,6 +46,7 @@
</el-input>
</el-row>
<el-row
id="pluginList"
v-loading="loading"
:gutter="10"
class="plugin-list"
@@ -214,7 +215,7 @@ import {
GET_PICBEDS,
PICGO_HANDLE_PLUGIN_DONE
} from '#/events/constants'
import { computed, ref, onBeforeMount, onBeforeUnmount, watch } from 'vue'
import { computed, ref, onBeforeMount, onBeforeUnmount, watch, onMounted } from 'vue'
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
import { ElMessageBox } from 'element-plus'
import axios from 'axios'
@@ -352,6 +353,17 @@ async function buildContextMenu (plugin: IPicGoPlugin) {
sendToMain(SHOW_PLUGIN_PAGE_MENU, plugin)
}
function handleResize () {
const myDiv = document.getElementById('pluginList') as HTMLElement
const windowHeight = window.innerHeight
const newHeight = windowHeight * 0.75
myDiv.style.height = newHeight + 'px'
}
onMounted(() => {
window.addEventListener('resize', handleResize)
})
function getPluginList () {
sendToMain('getPluginList')
}
@@ -529,6 +541,7 @@ function handleImportLocalPlugin () {
}
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
ipcRenderer.removeAllListeners('pluginList')
ipcRenderer.removeAllListeners('installPlugin')
ipcRenderer.removeAllListeners('uninstallSuccess')
@@ -554,7 +567,7 @@ $darwinBg = #172426
background-color rgba(0, 0, 0, 0.8)
.plugin-list
align-content flex-start
height: 339px;
height: 600px;
box-sizing: border-box;
padding: 8px 15px;
overflow-y: auto;

View File

@@ -15,6 +15,16 @@
>
<CaretBottom />
</el-icon>
<el-button
type="primary"
round
size="small"
class="quick-upload"
style="margin-left: 6px"
@click="handleImageProcess"
>
图片处理
</el-button>
</div>
<div
id="upload-area"
@@ -110,6 +120,214 @@
</div>
</el-col>
</el-row>
<el-dialog
v-model="imageProcessDialogVisible"
title="图片处理设置"
width="50%"
draggable
center
align-center
>
<el-form
label-position="top"
require-asterisk-position="right"
label-width="10vw"
size="default"
:model="waterMarkForm"
>
<el-form-item label="是否添加水印">
<el-switch
v-model="waterMarkForm.isAddWatermark"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印类型"
>
<el-radio-group v-model="waterMarkForm.watermarkType">
<el-radio label="text">
文字
</el-radio>
<el-radio label="image">
图片
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="是否全屏水印"
>
<el-switch
v-model="waterMarkForm.isFullScreenWatermark"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印角度"
>
<el-input-number
v-model="waterMarkForm.watermarkDegree"
:step="1"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
label="水印文字"
>
<el-input v-model="waterMarkForm.watermarkText" />
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
label="水印字体路径(留空默认使用simhei.ttf)"
>
<el-input v-model="waterMarkForm.watermarkFontPath" />
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印占原图比例"
>
<el-input-number
v-model="waterMarkForm.watermarkScaleRatio"
:min="0"
:max="1"
:step="0.01"
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
label="水印颜色,请从取色器中选择"
>
<el-color-picker
v-model="waterMarkForm.watermarkColor"
show-alpha
/>
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'image'"
label="水印图片路径(留空使用默认图片)"
>
<el-input v-model="waterMarkForm.watermarkImagePath" />
</el-form-item>
<el-form-item
v-show="waterMarkForm.isAddWatermark"
label="水印位置"
>
<el-radio-group
v-model="waterMarkForm.watermarkPosition"
>
<el-radio
v-for="item in waterMarkPositionMap"
:key="item[0]"
:label="item[0]"
>
{{ item[1] }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="压缩质量">
<el-input-number
v-model="compressForm.quality"
:min="0"
:max="100"
:step="1"
/>
</el-form-item>
<el-form-item label="是否转换格式">
<el-switch
v-model="compressForm.isConvert"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isConvert"
label="选择转换目的格式"
>
<el-select v-model="compressForm.convertFormat">
<el-option
v-for="item in availableFormat"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="是否按固定尺寸调整图片">
<el-switch
v-model="compressForm.isReSize"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isReSize"
label="调整尺寸宽度"
>
<el-input-number
v-model="compressForm.reSizeWidth"
:min="0"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isReSize"
label="调整尺寸高度"
>
<el-input-number
v-model="compressForm.reSizeHeight"
:min="0"
/>
</el-form-item>
<el-form-item label="是否按比例调整尺寸,优先级高于固定尺寸">
<el-switch
v-model="compressForm.isReSizeByPercent"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isReSizeByPercent"
label="调整尺寸比例, 输入50表示50%"
>
<el-input-number
v-model="compressForm.reSizePercent"
:min="0"
/>
</el-form-item>
<el-form-item
label="是否旋转"
>
<el-switch
v-model="compressForm.isRotate"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
v-show="compressForm.isRotate"
label="旋转角度"
>
<el-input-number
v-model="compressForm.rotateDegree"
:step="1"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="handelSaveConfig"
>
保存
</el-button>
<el-button @click="closeDialog">
取消
</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
@@ -118,7 +336,7 @@ import {
ipcRenderer,
IpcRendererEvent
} from 'electron'
import { ref, onBeforeMount, onBeforeUnmount, watch } from 'vue'
import { ref, reactive, onBeforeMount, onBeforeUnmount, watch, toRaw } from 'vue'
import { T as $T } from '@/i18n'
import $bus from '@/utils/bus'
import {
@@ -132,6 +350,89 @@ import {
} from '~/universal/utils/common'
import { ElMessage as $message } from 'element-plus'
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
import { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
const imageProcessDialogVisible = ref(false)
const waterMarkPositionMap = new Map([
['north', '上'],
['northeast', '右上'],
['southeast', '右下'],
['south', '下'],
['southwest', '左下'],
['northwest', '左上'],
['west', '左'],
['east', '右'],
['centre', '中']
])
const availableFormat = ['avif', 'dz', 'fits', 'gif', 'heif', 'input', 'jpeg', 'jpg', 'jp2', 'jxl', 'magick', 'openslide', 'pdf', 'png', 'ppm', 'raw', 'svg', 'tiff', 'tif', 'v', 'webp']
const waterMarkForm = reactive<any>({
isAddWatermark: false,
watermarkType: 'text',
isFullScreenWatermark: false,
watermarkDegree: 0,
watermarkText: '',
watermarkFontPath: '',
watermarkScaleRatio: 0.15,
watermarkColor: '#CCCCCC73',
watermarkImagePath: '',
watermarkPosition: 'southeast'
})
const compressForm = reactive<any>({
quality: 100,
isConvert: false,
convertFormat: 'jpg',
isReSize: false,
reSizeWidth: 500,
reSizeHeight: 500,
isReSizeByPercent: false,
reSizePercent: 50,
isRotate: false,
rotateDegree: 0
})
function closeDialog () {
imageProcessDialogVisible.value = false
}
function handelSaveConfig () {
saveConfig('buildIn.compress', toRaw(compressForm))
saveConfig('buildIn.watermark', toRaw(waterMarkForm))
closeDialog()
}
async function initData () {
const compress = await getConfig<IBuildInCompressOptions>('buildIn.compress')
const watermark = await getConfig<IBuildInWaterMarkOptions>('buildIn.watermark')
if (compress) {
compressForm.quality = compress.quality ?? 100
compressForm.isConvert = compress.isConvert ?? false
compressForm.convertFormat = compress.convertFormat ?? 'jpg'
compressForm.isReSize = compress.isReSize ?? false
compressForm.reSizeWidth = compress.reSizeWidth ?? 500
compressForm.reSizeHeight = compress.reSizeHeight ?? 500
compressForm.isReSizeByPercent = compress.isReSizeByPercent ?? false
compressForm.reSizePercent = compress.reSizePercent ?? 50
compressForm.isRotate = compress.isRotate ?? false
compressForm.rotateDegree = compress.rotateDegree ?? 0
}
if (watermark) {
waterMarkForm.isAddWatermark = watermark.isAddWatermark ?? false
waterMarkForm.watermarkType = watermark.watermarkType ?? 'text'
waterMarkForm.isFullScreenWatermark = watermark.isFullScreenWatermark ?? false
waterMarkForm.watermarkDegree = watermark.watermarkDegree ?? 0
waterMarkForm.watermarkText = watermark.watermarkText ?? ''
waterMarkForm.watermarkFontPath = watermark.watermarkFontPath ?? ''
waterMarkForm.watermarkScaleRatio = watermark.watermarkScaleRatio ?? 0.15
waterMarkForm.watermarkColor = watermark.watermarkColor === undefined || watermark.watermarkColor === '' ? '#CCCCCC73' : watermark.watermarkColor
waterMarkForm.watermarkImagePath = watermark.watermarkImagePath ?? ''
waterMarkForm.watermarkPosition = watermark.watermarkPosition ?? 'southeast'
}
}
const dragover = ref(false)
const progress = ref(0)
const showProgress = ref(false)
@@ -141,6 +442,7 @@ const picBed = ref<IPicBedType[]>([])
const picBedName = ref('')
const customLink = ref('')
const picBedConfigName = ref('')
onBeforeMount(() => {
ipcRenderer.on('uploadProgress', (_event: IpcRendererEvent, _progress: number) => {
if (_progress !== -1) {
@@ -159,8 +461,13 @@ onBeforeMount(() => {
sendToMain(GET_PICBEDS)
ipcRenderer.on(GET_PICBEDS, getPicBeds)
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
initData()
})
const handleImageProcess = () => {
imageProcessDialogVisible.value = true
}
watch(progress, onProgressChange)
function onProgressChange (val: number) {