Skip to content

Commit

Permalink
feat: 添加水印功能
Browse files Browse the repository at this point in the history
  • Loading branch information
JiangShuQ authored and Qiu-Jun committed Nov 4, 2023
1 parent 60c6d4f commit 47086bd
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 3 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module.exports = {
'vue/multi-word-component-names': 'off', // 开启组件需要多单词
'vue/no-setup-props-destructure': 'off',
'vuejs-accessibility/anchor-has-content': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
},
overrides: [
{
Expand Down
179 changes: 179 additions & 0 deletions src/components/waterMark.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<!--
* @Author: June
* @Description:
* @Date: 2023-11-01 11:54:10
* @LastEditors: June
* @LastEditTime: 2023-11-04 16:11:12
-->
<template>
<Button type="text" @click="addWaterMark">
{{ $t('waterMark.text') }}
</Button>

<Modal
v-model="showWaterMadal"
:title="$t('waterMark.modalTitle')"
@on-ok="onModalOk"
@on-cancel="onMadalCancel"
>
<div class="setting-item">
<span class="mr-10px">{{ $t('waterMark.setting.name') }}</span>
<Input
class="w-320"
v-model="waterMarkState.text"
maxlength="15"
show-word-limit
:placeholder="$t('placeholder')"
/>
</div>
<div class="setting-item">
<span class="mr-10px">{{ $t('waterMark.setting.size') }}</span>

<Slider class="w-320" v-model="waterMarkState.size" :min="18" :max="48"></Slider>
</div>
<div class="setting-item">
<span class="mr-10px">{{ $t('waterMark.setting.position.label') }}</span>

<RadioGroup v-model="waterMarkState.position">
<Radio label="lt">{{ $t('waterMark.setting.position.lt') }}</Radio>
<Radio label="rt">{{ $t('waterMark.setting.position.rt') }}</Radio>
<Radio label="lb">{{ $t('waterMark.setting.position.lb') }}</Radio>
<Radio label="rb">{{ $t('waterMark.setting.position.rb') }}</Radio>
</RadioGroup>
</div>
</Modal>
</template>

<script name="WaterMark" lang="ts" setup>
import { debounce } from 'lodash-es';
import { Message } from 'view-ui-plus';
import useSelect from '@/hooks/select';

const { canvasEditor }: any = useSelect();
const waterMarkState = reactive({
text: '',
size: 24,
isRotate: 0, // 组件不支持boolean
font: 'serif', // 可考虑自定义字体
color: '#ccc', // 可考虑自定义颜色
position: 'lt', // lt 左上 lr 右上 lb 左下 rb 右下
});

const showWaterMadal = ref(false);
const onMadalCancel = () => {
waterMarkState.text = '';
waterMarkState.size = 24;
waterMarkState.font = 'serif';
waterMarkState.color = '#ccc';
waterMarkState.position = 'lt';
waterMarkState.isRotate = 0;
};

const createCanvas = (width: number, height: number) => {
const waterCanvas = document.createElement('canvas');
waterCanvas.width = width;
waterCanvas.height = height;
waterCanvas.style.position = 'fixed';
waterCanvas.style.opacity = '0';
waterCanvas.style.zIndex = '-1';
return waterCanvas;
};

const drawWaterMark: Record<string, any> = {
lt: (width: number, height: number, cb: (imgString: string) => void) => {
let waterCanvas: HTMLCanvasElement | null = createCanvas(width, height);
const w = waterCanvas.width || width;
let ctx: CanvasRenderingContext2D | null = waterCanvas.getContext('2d')!;
ctx.fillStyle = waterMarkState.color;
ctx.font = `${waterMarkState.size}px ${waterMarkState.font}`;
ctx.fillText(waterMarkState.text, 10, waterMarkState.size + 10, w - 20);
cb && cb(waterCanvas.toDataURL());
waterCanvas = null;
ctx = null;
},
rt: (width: number, height: number, cb: (imgString: string) => void) => {
let waterCanvas: HTMLCanvasElement | null = createCanvas(width, height);
let ctx: CanvasRenderingContext2D | null = waterCanvas.getContext('2d')!;
const w = waterCanvas.width || width;
ctx.fillStyle = waterMarkState.color;
ctx.font = `${waterMarkState.size}px ${waterMarkState.font}`;
ctx.fillText(
waterMarkState.text,
w - ctx.measureText(waterMarkState.text).width - 20,
waterMarkState.size + 10,
w - 20
);
cb && cb(waterCanvas.toDataURL());
waterCanvas = null;
ctx = null;
},
lb: (width: number, height: number, cb: (imgString: string) => void) => {
let waterCanvas: HTMLCanvasElement | null = createCanvas(width, height);
let ctx: CanvasRenderingContext2D | null = waterCanvas.getContext('2d')!;
const w = waterCanvas.width || width;
const h = waterCanvas.height || height;
ctx.fillStyle = waterMarkState.color;
ctx.font = `${waterMarkState.size}px ${waterMarkState.font}`;
ctx.fillText(waterMarkState.text, 10, h - waterMarkState.size, w - 20);
cb && cb(waterCanvas.toDataURL());
waterCanvas = null;
ctx = null;
},
rb: (width: number, height: number, cb: (imgString: string) => void) => {
let waterCanvas: HTMLCanvasElement | null = createCanvas(width, height);
let ctx: CanvasRenderingContext2D | null = waterCanvas.getContext('2d')!;
const w = waterCanvas.width || width;
ctx.fillStyle = waterMarkState.color;
ctx.font = `${waterMarkState.size}px ${waterMarkState.font}`;
ctx.fillText(
waterMarkState.text,
w - ctx.measureText(waterMarkState.text).width - 20,
height - waterMarkState.size,
width - 20
);
cb && cb(waterCanvas.toDataURL());
waterCanvas = null;
ctx = null;
},
};

const onModalOk = () => {
if (!waterMarkState.text) return Message.warning('水印名字不能为空');
const workspace = canvasEditor.canvas.getObjects().find((item: any) => item.id === 'workspace');
const { width, height, left, top } = workspace;
drawWaterMark[waterMarkState.position](width, height, (imgString: string) => {
canvasEditor.canvas.overlayImage = null; // 清空覆盖层
canvasEditor.canvas.setOverlayImage(
imgString,
canvasEditor.canvas.renderAll.bind(canvasEditor.canvas),
{
left: left || 0,
top: top || 0,
originX: 'left',
originY: 'top',
}
);
});
onMadalCancel();
};

const addWaterMark = debounce(function () {
showWaterMadal.value = true;
}, 250);
</script>

<style lang="less" scoped>
.mr-10px {
margin-right: 10px;
}
.w-320 {
width: 320px;
}
.setting-item {
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
}
</style>
21 changes: 20 additions & 1 deletion src/language/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"templates": "Templates",
"elements": "Elements",
"background": "Background",
"placeholder": "Please input",
"size": "Size",
"width": "Width",
"height": "Height",
Expand Down Expand Up @@ -32,6 +33,23 @@
"import_files": "Import files",
"select_json": "Select JSON",
"repleaceImg": "repleace Image",
"waterMark": {
"text": "WaterMark",
"modalTitle": "WaterMark Setting",
"setting": {
"name": "Mark Name",
"size": "MarK Size",
"angle": "Mark Angle",
"position": {
"label": "Mark Position",
"lt": "Left Top",
"rt": "Right Top",
"lb": "Left Bottom",
"rb": "Right Bottom",
"full": "Full"
}
}
},
"material": {
"cartoon": "cartoon"
},
Expand Down Expand Up @@ -87,6 +105,7 @@
"insert": "insert",
"insert_picture": "Insert picture",
"insert_SVG": "Insert SVG",
"insert_PSD": "insert PSD",
"insert_SVGStr": "Insert SVG String",
"insert_SVGStr_placeholder": "Please enter SVG String",
"modal_tittle": "Please enter"
Expand Down Expand Up @@ -164,4 +183,4 @@
"replaceTip": "Are you sure you want to add to the canvas?",
"ok": "ok",
"cancel": "cancel"
}
}
7 changes: 7 additions & 0 deletions src/language/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/*
* @Author: June
* @Description:
* @Date: 2023-10-29 12:18:14
* @LastEditors: June
* @LastEditTime: 2023-11-01 12:01:24
*/
import { createI18n } from 'vue-i18n';
import zh from 'view-ui-plus/dist/locale/zh-CN';
import en from 'view-ui-plus/dist/locale/en-US'; //新版本把'iview'改成'view-design'
Expand Down
17 changes: 17 additions & 0 deletions src/language/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@
"insert_SVGStr_placeholder": "Please enter SVG String",
"modal_tittle": "Please enter"
},
"waterMark": {
"text": "WaterMark",
"modalTitle": "WaterMark Setting",
"setting": {
"name": "Mark Name",
"size": "MarK Size",
"angle": "Mark Angle",
"position": {
"label": "Mark Position",
"lt": "Left Top",
"rt": "Right Top",
"lb": "Left Bottom",
"rb": "Right Bottom",
"full": "Full"
}
}
},
"upload_background": "Carregar plano de fundo",
"mouseMenu": {
"layer": "Gestão de camadas",
Expand Down
21 changes: 20 additions & 1 deletion src/language/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"width": "宽度",
"height": "高度",
"grid": "网格",
"placeholder": "请输入",
"common_elements": "基础要素",
"draw_elements": "绘制元素",
"color_macthing": "配色",
Expand All @@ -32,6 +33,23 @@
"import_files": "导入文件",
"select_json": "选择JSON文件",
"repleaceImg": "替换图片",
"waterMark": {
"text": "水印",
"modalTitle": "配置水印",
"setting": {
"name": "水印名称",
"size": "水印大小",
"angle": "水印角度",
"position": {
"label": "水印位置",
"lt": "左上角",
"rt": "右上角",
"lb": "左下角",
"rb": "右下角",
"full": "平铺"
}
}
},
"material": {
"cartoon": "卡通"
},
Expand Down Expand Up @@ -92,6 +110,7 @@
"insert_picture": "插入图片",
"insert_SVG": "插入SVG元素",
"insert_SVGStr": "插入SVG字符",
"insert_PSD": "插入PSD",
"insert_SVGStr_placeholder": "请输入SVG字符串",
"modal_tittle": "请输入"
},
Expand Down Expand Up @@ -153,4 +172,4 @@
"replaceTip": "确定要添加到画布中吗?",
"ok": "确认",
"cancel": "取消"
}
}
3 changes: 2 additions & 1 deletion src/views/home/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<div style="float: right">
<!-- 预览 -->
<previewCurrent />
<waterMark />
<save></save>
<lang></lang>
</div>
Expand Down Expand Up @@ -144,7 +145,7 @@ import zoom from '@/components/zoom.vue';
import dragMode from '@/components/dragMode.vue';
import lock from '@/components/lock.vue';
import dele from '@/components/del.vue';
import waterMark from '@/components/waterMark';
// 左侧组件
import importTmpl from '@/components/importTmpl.vue';
import tools from '@/components/tools.vue';
Expand Down

0 comments on commit 47086bd

Please sign in to comment.