This commit is contained in:
2025-09-19 14:25:20 +08:00
parent 269893a435
commit fbf3f77229
24949 changed files with 2839404 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
import Watermark from './src/watermark.vue';
import type { SFCWithInstall } from 'element-plus/es/utils';
export declare const ElWatermark: SFCWithInstall<typeof Watermark>;
export default ElWatermark;
export * from './src/watermark';

View File

@@ -0,0 +1,8 @@
import Watermark from './src/watermark2.mjs';
export { watermarkProps } from './src/watermark.mjs';
import { withInstall } from '../../utils/vue/install.mjs';
const ElWatermark = withInstall(Watermark);
export { ElWatermark, ElWatermark as default };
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":["../../../../../packages/components/watermark/index.ts"],"sourcesContent":["import { withInstall } from '@element-plus/utils'\nimport Watermark from './src/watermark.vue'\n\nimport type { SFCWithInstall } from '@element-plus/utils'\n\nexport const ElWatermark: SFCWithInstall<typeof Watermark> =\n withInstall(Watermark)\nexport default ElWatermark\n\nexport * from './src/watermark'\n"],"names":[],"mappings":";;;;AAEY,MAAC,WAAW,GAAG,WAAW,CAAC,SAAS;;;;"}

View File

@@ -0,0 +1,7 @@
import type { WatermarkProps } from './watermark';
export declare const FontGap = 3;
/**
* Get the clips of text content.
* This is a lazy hook function since SSR no need this
*/
export default function useClips(): (content: NonNullable<WatermarkProps["content"]> | HTMLImageElement, rotate: number, ratio: number, width: number, height: number, font: Required<NonNullable<WatermarkProps["font"]>>, gapX: number, gapY: number, space: number) => [dataURL: string, finalWidth: number, finalHeight: number];

View File

@@ -0,0 +1,100 @@
import { isArray } from '@vue/shared';
const FontGap = 3;
const TEXT_ALIGN_RATIO_MAP = {
left: [0, 0.5],
start: [0, 0.5],
center: [0.5, 0],
right: [1, -0.5],
end: [1, -0.5]
};
function prepareCanvas(width, height, ratio = 1) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const realWidth = width * ratio;
const realHeight = height * ratio;
canvas.setAttribute("width", `${realWidth}px`);
canvas.setAttribute("height", `${realHeight}px`);
ctx.save();
return [ctx, canvas, realWidth, realHeight];
}
function useClips() {
function getClips(content, rotate, ratio, width, height, font, gapX, gapY, space) {
const [ctx, canvas, contentWidth, contentHeight] = prepareCanvas(width, height, ratio);
if (content instanceof HTMLImageElement) {
ctx.drawImage(content, 0, 0, contentWidth, contentHeight);
} else {
const {
color,
fontSize,
fontStyle,
fontWeight,
fontFamily,
textAlign,
textBaseline
} = font;
const mergedFontSize = Number(fontSize) * ratio;
ctx.font = `${fontStyle} normal ${fontWeight} ${mergedFontSize}px/${height}px ${fontFamily}`;
ctx.fillStyle = color;
ctx.textAlign = textAlign;
ctx.textBaseline = textBaseline;
const contents = isArray(content) ? content : [content];
contents == null ? void 0 : contents.forEach((item, index) => {
const [alignRatio, spaceRatio] = TEXT_ALIGN_RATIO_MAP[textAlign];
ctx.fillText(item != null ? item : "", contentWidth * alignRatio + space * spaceRatio, index * (mergedFontSize + FontGap * ratio));
});
}
const angle = Math.PI / 180 * Number(rotate);
const maxSize = Math.max(width, height);
const [rCtx, rCanvas, realMaxSize] = prepareCanvas(maxSize, maxSize, ratio);
rCtx.translate(realMaxSize / 2, realMaxSize / 2);
rCtx.rotate(angle);
if (contentWidth > 0 && contentHeight > 0) {
rCtx.drawImage(canvas, -contentWidth / 2, -contentHeight / 2);
}
function getRotatePos(x, y) {
const targetX = x * Math.cos(angle) - y * Math.sin(angle);
const targetY = x * Math.sin(angle) + y * Math.cos(angle);
return [targetX, targetY];
}
let left = 0;
let right = 0;
let top = 0;
let bottom = 0;
const halfWidth = contentWidth / 2;
const halfHeight = contentHeight / 2;
const points = [
[0 - halfWidth, 0 - halfHeight],
[0 + halfWidth, 0 - halfHeight],
[0 + halfWidth, 0 + halfHeight],
[0 - halfWidth, 0 + halfHeight]
];
points.forEach(([x, y]) => {
const [targetX, targetY] = getRotatePos(x, y);
left = Math.min(left, targetX);
right = Math.max(right, targetX);
top = Math.min(top, targetY);
bottom = Math.max(bottom, targetY);
});
const cutLeft = left + realMaxSize / 2;
const cutTop = top + realMaxSize / 2;
const cutWidth = right - left;
const cutHeight = bottom - top;
const realGapX = gapX * ratio;
const realGapY = gapY * ratio;
const filledWidth = (cutWidth + realGapX) * 2;
const filledHeight = cutHeight + realGapY;
const [fCtx, fCanvas] = prepareCanvas(filledWidth, filledHeight);
function drawImg(targetX = 0, targetY = 0) {
fCtx.drawImage(rCanvas, cutLeft, cutTop, cutWidth, cutHeight, targetX, targetY, cutWidth, cutHeight);
}
drawImg();
drawImg(cutWidth + realGapX, -cutHeight / 2 - realGapY / 2);
drawImg(cutWidth + realGapX, +cutHeight / 2 + realGapY / 2);
return [fCanvas.toDataURL(), filledWidth / ratio, filledHeight / ratio];
}
return getClips;
}
export { FontGap, useClips as default };
//# sourceMappingURL=useClips.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
import type { CSSProperties } from 'vue';
/** converting camel-cased strings to be lowercase and link it with Separator */
export declare function toLowercaseSeparator(key: string): string;
export declare function getStyleStr(style: CSSProperties): string;
/** Returns the ratio of the device's physical pixel resolution to the css pixel resolution */
export declare function getPixelRatio(): number;
/** Whether to re-render the watermark */
export declare const reRendering: (mutation: MutationRecord, watermarkElement?: HTMLElement) => boolean;

View File

@@ -0,0 +1,22 @@
function toLowercaseSeparator(key) {
return key.replace(/([A-Z])/g, "-$1").toLowerCase();
}
function getStyleStr(style) {
return Object.keys(style).map((key) => `${toLowercaseSeparator(key)}: ${style[key]};`).join(" ");
}
function getPixelRatio() {
return window.devicePixelRatio || 1;
}
const reRendering = (mutation, watermarkElement) => {
let flag = false;
if (mutation.removedNodes.length && watermarkElement) {
flag = Array.from(mutation.removedNodes).includes(watermarkElement);
}
if (mutation.type === "attributes" && mutation.target === watermarkElement) {
flag = true;
}
return flag;
};
export { getPixelRatio, getStyleStr, reRendering, toLowercaseSeparator };
//# sourceMappingURL=utils.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"utils.mjs","sources":["../../../../../../packages/components/watermark/src/utils.ts"],"sourcesContent":["import type { CSSProperties } from 'vue'\n\n/** converting camel-cased strings to be lowercase and link it with Separator */\nexport function toLowercaseSeparator(key: string) {\n return key.replace(/([A-Z])/g, '-$1').toLowerCase()\n}\n\nexport function getStyleStr(style: CSSProperties): string {\n return Object.keys(style)\n .map(\n (key) =>\n `${toLowercaseSeparator(key)}: ${style[key as keyof CSSProperties]};`\n )\n .join(' ')\n}\n\n/** Returns the ratio of the device's physical pixel resolution to the css pixel resolution */\nexport function getPixelRatio() {\n return window.devicePixelRatio || 1\n}\n\n/** Whether to re-render the watermark */\nexport const reRendering = (\n mutation: MutationRecord,\n watermarkElement?: HTMLElement\n) => {\n let flag = false\n // Whether to delete the watermark node\n if (mutation.removedNodes.length && watermarkElement) {\n flag = Array.from(mutation.removedNodes).includes(watermarkElement)\n }\n // Whether the watermark dom property value has been modified\n if (mutation.type === 'attributes' && mutation.target === watermarkElement) {\n flag = true\n }\n return flag\n}\n"],"names":[],"mappings":"AAAO,SAAS,oBAAoB,CAAC,GAAG,EAAE;AAC1C,EAAE,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AACtD,CAAC;AACM,SAAS,WAAW,CAAC,KAAK,EAAE;AACnC,EAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,oBAAoB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnG,CAAC;AACM,SAAS,aAAa,GAAG;AAChC,EAAE,OAAO,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;AACtC,CAAC;AACW,MAAC,WAAW,GAAG,CAAC,QAAQ,EAAE,gBAAgB,KAAK;AAC3D,EAAE,IAAI,IAAI,GAAG,KAAK,CAAC;AACnB,EAAE,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,IAAI,gBAAgB,EAAE;AACxD,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AACxE,GAAG;AACH,EAAE,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,IAAI,QAAQ,CAAC,MAAM,KAAK,gBAAgB,EAAE;AAC9E,IAAI,IAAI,GAAG,IAAI,CAAC;AAChB,GAAG;AACH,EAAE,OAAO,IAAI,CAAC;AACd;;;;"}

View File

@@ -0,0 +1,35 @@
import type { ExtractPropTypes, __ExtractPublicPropTypes } from 'vue';
import type Watermark from './watermark.vue';
export interface WatermarkFontType {
color?: string;
fontSize?: number | string;
fontWeight?: 'normal' | 'light' | 'weight' | number;
fontStyle?: 'none' | 'normal' | 'italic' | 'oblique';
fontFamily?: string;
textAlign?: 'start' | 'end' | 'left' | 'right' | 'center';
textBaseline?: 'top' | 'hanging' | 'middle' | 'alphabetic' | 'ideographic' | 'bottom';
}
export declare const watermarkProps: {
readonly zIndex: import("element-plus/es/utils").EpPropFinalized<NumberConstructor, unknown, unknown, 9, boolean>;
readonly rotate: import("element-plus/es/utils").EpPropFinalized<NumberConstructor, unknown, unknown, -22, boolean>;
readonly width: NumberConstructor;
readonly height: NumberConstructor;
readonly image: StringConstructor;
readonly content: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => string | string[]) | (() => string | string[]) | ((new (...args: any[]) => string | string[]) | (() => string | string[]))[], unknown, unknown, "Element Plus", boolean>;
readonly font: {
readonly type: import("vue").PropType<WatermarkFontType>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
readonly gap: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => [number, number]) | (() => [number, number]) | ((new (...args: any[]) => [number, number]) | (() => [number, number]))[], unknown, unknown, () => number[], boolean>;
readonly offset: {
readonly type: import("vue").PropType<[number, number]>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
};
export type WatermarkProps = ExtractPropTypes<typeof watermarkProps>;
export type WatermarkPropsPublic = __ExtractPublicPropTypes<typeof watermarkProps>;
export type WatermarkInstance = InstanceType<typeof Watermark> & unknown;

View File

@@ -0,0 +1,32 @@
import { buildProps, definePropType } from '../../../utils/vue/props/runtime.mjs';
const watermarkProps = buildProps({
zIndex: {
type: Number,
default: 9
},
rotate: {
type: Number,
default: -22
},
width: Number,
height: Number,
image: String,
content: {
type: definePropType([String, Array]),
default: "Element Plus"
},
font: {
type: definePropType(Object)
},
gap: {
type: definePropType(Array),
default: () => [100, 100]
},
offset: {
type: definePropType(Array)
}
});
export { watermarkProps };
//# sourceMappingURL=watermark.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"watermark.mjs","sources":["../../../../../../packages/components/watermark/src/watermark.ts"],"sourcesContent":["import { buildProps, definePropType } from '@element-plus/utils'\n\nimport type { ExtractPropTypes, __ExtractPublicPropTypes } from 'vue'\nimport type Watermark from './watermark.vue'\n\nexport interface WatermarkFontType {\n color?: string\n fontSize?: number | string\n fontWeight?: 'normal' | 'light' | 'weight' | number\n fontStyle?: 'none' | 'normal' | 'italic' | 'oblique'\n fontFamily?: string\n textAlign?: 'start' | 'end' | 'left' | 'right' | 'center'\n textBaseline?:\n | 'top'\n | 'hanging'\n | 'middle'\n | 'alphabetic'\n | 'ideographic'\n | 'bottom'\n}\n\nexport const watermarkProps = buildProps({\n /**\n * @description The z-index of the appended watermark element\n */\n zIndex: {\n type: Number,\n default: 9,\n },\n /**\n * @description The rotation angle of the watermark\n */\n rotate: {\n type: Number,\n default: -22,\n },\n /**\n * @description The width of the watermark\n */\n width: Number,\n /**\n * @description The height of the watermark\n */\n height: Number,\n /**\n * @description Image source, it is recommended to export 2x or 3x image, high priority (support base64 format)\n */\n image: String,\n /**\n * @description Watermark text content\n */\n content: {\n type: definePropType<string | string[]>([String, Array]),\n default: 'Element Plus',\n },\n /**\n * @description Text style\n */\n font: {\n type: definePropType<WatermarkFontType>(Object),\n },\n /**\n * @description The spacing between watermarks\n */\n gap: {\n type: definePropType<[number, number]>(Array),\n default: () => [100, 100],\n },\n /**\n * @description The offset of the watermark from the upper left corner of the container. The default is gap/2\n */\n offset: {\n type: definePropType<[number, number]>(Array),\n },\n} as const)\n\nexport type WatermarkProps = ExtractPropTypes<typeof watermarkProps>\nexport type WatermarkPropsPublic = __ExtractPublicPropTypes<\n typeof watermarkProps\n>\nexport type WatermarkInstance = InstanceType<typeof Watermark> & unknown\n"],"names":[],"mappings":";;AACY,MAAC,cAAc,GAAG,UAAU,CAAC;AACzC,EAAE,MAAM,EAAE;AACV,IAAI,IAAI,EAAE,MAAM;AAChB,IAAI,OAAO,EAAE,CAAC;AACd,GAAG;AACH,EAAE,MAAM,EAAE;AACV,IAAI,IAAI,EAAE,MAAM;AAChB,IAAI,OAAO,EAAE,CAAC,EAAE;AAChB,GAAG;AACH,EAAE,KAAK,EAAE,MAAM;AACf,EAAE,MAAM,EAAE,MAAM;AAChB,EAAE,KAAK,EAAE,MAAM;AACf,EAAE,OAAO,EAAE;AACX,IAAI,IAAI,EAAE,cAAc,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACzC,IAAI,OAAO,EAAE,cAAc;AAC3B,GAAG;AACH,EAAE,IAAI,EAAE;AACR,IAAI,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC;AAChC,GAAG;AACH,EAAE,GAAG,EAAE;AACP,IAAI,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC;AAC/B,IAAI,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC;AAC7B,GAAG;AACH,EAAE,MAAM,EAAE;AACV,IAAI,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC;AAC/B,GAAG;AACH,CAAC;;;;"}

View File

@@ -0,0 +1,56 @@
declare function __VLS_template(): {
default?(_: {}): any;
};
declare const __VLS_component: import("vue").DefineComponent<{
readonly zIndex: import("element-plus/es/utils").EpPropFinalized<NumberConstructor, unknown, unknown, 9, boolean>;
readonly rotate: import("element-plus/es/utils").EpPropFinalized<NumberConstructor, unknown, unknown, -22, boolean>;
readonly width: NumberConstructor;
readonly height: NumberConstructor;
readonly image: StringConstructor;
readonly content: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => string | string[]) | (() => string | string[]) | ((new (...args: any[]) => string | string[]) | (() => string | string[]))[], unknown, unknown, "Element Plus", boolean>;
readonly font: {
readonly type: import("vue").PropType<import("./watermark").WatermarkFontType>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
readonly gap: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => [number, number]) | (() => [number, number]) | ((new (...args: any[]) => [number, number]) | (() => [number, number]))[], unknown, unknown, () => number[], boolean>;
readonly offset: {
readonly type: import("vue").PropType<[number, number]>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
readonly zIndex: import("element-plus/es/utils").EpPropFinalized<NumberConstructor, unknown, unknown, 9, boolean>;
readonly rotate: import("element-plus/es/utils").EpPropFinalized<NumberConstructor, unknown, unknown, -22, boolean>;
readonly width: NumberConstructor;
readonly height: NumberConstructor;
readonly image: StringConstructor;
readonly content: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => string | string[]) | (() => string | string[]) | ((new (...args: any[]) => string | string[]) | (() => string | string[]))[], unknown, unknown, "Element Plus", boolean>;
readonly font: {
readonly type: import("vue").PropType<import("./watermark").WatermarkFontType>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
readonly gap: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => [number, number]) | (() => [number, number]) | ((new (...args: any[]) => [number, number]) | (() => [number, number]))[], unknown, unknown, () => number[], boolean>;
readonly offset: {
readonly type: import("vue").PropType<[number, number]>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
}>>, {
readonly content: import("element-plus/es/utils").EpPropMergeType<(new (...args: any[]) => string | string[]) | (() => string | string[]) | ((new (...args: any[]) => string | string[]) | (() => string | string[]))[], unknown, unknown>;
readonly rotate: number;
readonly zIndex: number;
readonly gap: [number, number];
}>;
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
export default _default;
type __VLS_WithTemplateSlots<T, S> = T & {
new (): {
$slots: S;
};
};

View File

@@ -0,0 +1,226 @@
import { defineComponent, computed, shallowRef, ref, onMounted, watch, onBeforeUnmount, openBlock, createElementBlock, normalizeStyle, renderSlot } from 'vue';
import { useMutationObserver } from '@vueuse/core';
import { watermarkProps } from './watermark.mjs';
import { reRendering, getStyleStr, getPixelRatio } from './utils.mjs';
import useClips, { FontGap } from './useClips.mjs';
import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
import { isArray } from '@vue/shared';
import { isUndefined } from '../../../utils/types.mjs';
const __default__ = defineComponent({
name: "ElWatermark"
});
const _sfc_main = /* @__PURE__ */ defineComponent({
...__default__,
props: watermarkProps,
setup(__props) {
const props = __props;
const style = {
position: "relative"
};
const color = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.color) != null ? _b : "rgba(0,0,0,.15)";
});
const fontSize = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.fontSize) != null ? _b : 16;
});
const fontWeight = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.fontWeight) != null ? _b : "normal";
});
const fontStyle = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.fontStyle) != null ? _b : "normal";
});
const fontFamily = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.fontFamily) != null ? _b : "sans-serif";
});
const textAlign = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.textAlign) != null ? _b : "center";
});
const textBaseline = computed(() => {
var _a, _b;
return (_b = (_a = props.font) == null ? void 0 : _a.textBaseline) != null ? _b : "hanging";
});
const gapX = computed(() => props.gap[0]);
const gapY = computed(() => props.gap[1]);
const gapXCenter = computed(() => gapX.value / 2);
const gapYCenter = computed(() => gapY.value / 2);
const offsetLeft = computed(() => {
var _a, _b;
return (_b = (_a = props.offset) == null ? void 0 : _a[0]) != null ? _b : gapXCenter.value;
});
const offsetTop = computed(() => {
var _a, _b;
return (_b = (_a = props.offset) == null ? void 0 : _a[1]) != null ? _b : gapYCenter.value;
});
const getMarkStyle = () => {
const markStyle = {
zIndex: props.zIndex,
position: "absolute",
left: 0,
top: 0,
width: "100%",
height: "100%",
pointerEvents: "none",
backgroundRepeat: "repeat"
};
let positionLeft = offsetLeft.value - gapXCenter.value;
let positionTop = offsetTop.value - gapYCenter.value;
if (positionLeft > 0) {
markStyle.left = `${positionLeft}px`;
markStyle.width = `calc(100% - ${positionLeft}px)`;
positionLeft = 0;
}
if (positionTop > 0) {
markStyle.top = `${positionTop}px`;
markStyle.height = `calc(100% - ${positionTop}px)`;
positionTop = 0;
}
markStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`;
return markStyle;
};
const containerRef = shallowRef(null);
const watermarkRef = shallowRef();
const stopObservation = ref(false);
const destroyWatermark = () => {
if (watermarkRef.value) {
watermarkRef.value.remove();
watermarkRef.value = void 0;
}
};
const appendWatermark = (base64Url, markWidth) => {
var _a;
if (containerRef.value && watermarkRef.value) {
stopObservation.value = true;
watermarkRef.value.setAttribute("style", getStyleStr({
...getMarkStyle(),
backgroundImage: `url('${base64Url}')`,
backgroundSize: `${Math.floor(markWidth)}px`
}));
(_a = containerRef.value) == null ? void 0 : _a.append(watermarkRef.value);
setTimeout(() => {
stopObservation.value = false;
});
}
};
const getMarkSize = (ctx) => {
let defaultWidth = 120;
let defaultHeight = 64;
let space = 0;
const { image, content, width, height, rotate } = props;
if (!image && ctx.measureText) {
ctx.font = `${Number(fontSize.value)}px ${fontFamily.value}`;
const contents = isArray(content) ? content : [content];
let maxWidth = 0;
let maxHeight = 0;
contents.forEach((item) => {
const {
width: width2,
fontBoundingBoxAscent,
fontBoundingBoxDescent,
actualBoundingBoxAscent,
actualBoundingBoxDescent
} = ctx.measureText(item);
const height2 = isUndefined(fontBoundingBoxAscent) ? actualBoundingBoxAscent + actualBoundingBoxDescent : fontBoundingBoxAscent + fontBoundingBoxDescent;
if (width2 > maxWidth)
maxWidth = Math.ceil(width2);
if (height2 > maxHeight)
maxHeight = Math.ceil(height2);
});
defaultWidth = maxWidth;
defaultHeight = maxHeight * contents.length + (contents.length - 1) * FontGap;
const angle = Math.PI / 180 * Number(rotate);
space = Math.ceil(Math.abs(Math.sin(angle) * defaultHeight) / 2);
defaultWidth += space;
}
return [width != null ? width : defaultWidth, height != null ? height : defaultHeight, space];
};
const getClips = useClips();
const renderWatermark = () => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const image = props.image;
const content = props.content;
const rotate = props.rotate;
if (ctx) {
if (!watermarkRef.value) {
watermarkRef.value = document.createElement("div");
}
const ratio = getPixelRatio();
const [markWidth, markHeight, space] = getMarkSize(ctx);
const drawCanvas = (drawContent) => {
const [textClips, clipWidth] = getClips(drawContent || "", rotate, ratio, markWidth, markHeight, {
color: color.value,
fontSize: fontSize.value,
fontStyle: fontStyle.value,
fontWeight: fontWeight.value,
fontFamily: fontFamily.value,
textAlign: textAlign.value,
textBaseline: textBaseline.value
}, gapX.value, gapY.value, space);
appendWatermark(textClips, clipWidth);
};
if (image) {
const img = new Image();
img.onload = () => {
drawCanvas(img);
};
img.onerror = () => {
drawCanvas(content);
};
img.crossOrigin = "anonymous";
img.referrerPolicy = "no-referrer";
img.src = image;
} else {
drawCanvas(content);
}
}
};
onMounted(() => {
renderWatermark();
});
watch(() => props, () => {
renderWatermark();
}, {
deep: true,
flush: "post"
});
onBeforeUnmount(() => {
destroyWatermark();
});
const onMutate = (mutations) => {
if (stopObservation.value) {
return;
}
mutations.forEach((mutation) => {
if (reRendering(mutation, watermarkRef.value)) {
destroyWatermark();
renderWatermark();
}
});
};
useMutationObserver(containerRef, onMutate, {
attributes: true,
subtree: true,
childList: true
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref_key: "containerRef",
ref: containerRef,
style: normalizeStyle([style])
}, [
renderSlot(_ctx.$slots, "default")
], 4);
};
}
});
var Watermark = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "watermark.vue"]]);
export { Watermark as default };
//# sourceMappingURL=watermark2.mjs.map

File diff suppressed because one or more lines are too long

View File

View File

@@ -0,0 +1,2 @@
//# sourceMappingURL=css.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"css.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}

View File

View File

@@ -0,0 +1,2 @@
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}