Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 添加水印功能 #284

Merged
merged 3 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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