Watermark.mjs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { defineComponent, nextTick, onUnmounted, ref, watch, watchEffect, createVNode as _createVNode } from "vue";
  2. import { extend, truthProp, numericProp, createNamespace, getZIndexStyle, makeNumberProp, makeNumericProp, makeStringProp } from "../utils/index.mjs";
  3. const [name, bem] = createNamespace("watermark");
  4. const watermarkProps = {
  5. gapX: makeNumberProp(0),
  6. gapY: makeNumberProp(0),
  7. image: String,
  8. width: makeNumberProp(100),
  9. height: makeNumberProp(100),
  10. rotate: makeNumericProp(-22),
  11. zIndex: numericProp,
  12. content: String,
  13. opacity: numericProp,
  14. fullPage: truthProp,
  15. textColor: makeStringProp("#dcdee0")
  16. };
  17. var stdin_default = defineComponent({
  18. name,
  19. props: watermarkProps,
  20. setup(props, {
  21. slots
  22. }) {
  23. const svgElRef = ref();
  24. const watermarkUrl = ref("");
  25. const imageBase64 = ref("");
  26. const renderWatermark = () => {
  27. const rotateStyle = {
  28. transformOrigin: "center",
  29. transform: `rotate(${props.rotate}deg)`
  30. };
  31. const svgInner = () => {
  32. if (props.image && !slots.content) {
  33. return _createVNode("image", {
  34. "href": imageBase64.value,
  35. "xlink:href": imageBase64.value,
  36. "x": "0",
  37. "y": "0",
  38. "width": props.width,
  39. "height": props.height,
  40. "style": rotateStyle
  41. }, null);
  42. }
  43. return _createVNode("foreignObject", {
  44. "x": "0",
  45. "y": "0",
  46. "width": props.width,
  47. "height": props.height
  48. }, [_createVNode("div", {
  49. "xmlns": "http://www.w3.org/1999/xhtml",
  50. "style": rotateStyle
  51. }, [slots.content ? slots.content() : _createVNode("span", {
  52. "style": {
  53. color: props.textColor
  54. }
  55. }, [props.content])])]);
  56. };
  57. const svgWidth = props.width + props.gapX;
  58. const svgHeight = props.height + props.gapY;
  59. return _createVNode("svg", {
  60. "viewBox": `0 0 ${svgWidth} ${svgHeight}`,
  61. "width": svgWidth,
  62. "height": svgHeight,
  63. "xmlns": "http://www.w3.org/2000/svg",
  64. "xmlns:xlink": "http://www.w3.org/1999/xlink",
  65. "style": {
  66. padding: `0 ${props.gapX}px ${props.gapY}px 0`,
  67. opacity: props.opacity
  68. }
  69. }, [svgInner()]);
  70. };
  71. const makeImageToBase64 = (url) => {
  72. const canvas = document.createElement("canvas");
  73. const image = new Image();
  74. image.crossOrigin = "anonymous";
  75. image.referrerPolicy = "no-referrer";
  76. image.onload = () => {
  77. canvas.width = image.naturalWidth;
  78. canvas.height = image.naturalHeight;
  79. const ctx = canvas.getContext("2d");
  80. ctx == null ? void 0 : ctx.drawImage(image, 0, 0);
  81. imageBase64.value = canvas.toDataURL();
  82. };
  83. image.src = url;
  84. };
  85. const makeSvgToBlobUrl = (svgStr) => {
  86. const svgBlob = new Blob([svgStr], {
  87. type: "image/svg+xml"
  88. });
  89. return URL.createObjectURL(svgBlob);
  90. };
  91. watchEffect(() => {
  92. if (props.image) {
  93. makeImageToBase64(props.image);
  94. }
  95. });
  96. watch(() => [imageBase64.value, props.content, props.textColor, props.height, props.width, props.rotate, props.gapX, props.gapY], () => {
  97. nextTick(() => {
  98. if (svgElRef.value) {
  99. if (watermarkUrl.value) {
  100. URL.revokeObjectURL(watermarkUrl.value);
  101. }
  102. watermarkUrl.value = makeSvgToBlobUrl(svgElRef.value.innerHTML);
  103. }
  104. });
  105. }, {
  106. immediate: true
  107. });
  108. onUnmounted(() => {
  109. if (watermarkUrl.value) {
  110. URL.revokeObjectURL(watermarkUrl.value);
  111. }
  112. });
  113. return () => {
  114. const style = extend({
  115. backgroundImage: `url(${watermarkUrl.value})`
  116. }, getZIndexStyle(props.zIndex));
  117. return _createVNode("div", {
  118. "class": bem({
  119. full: props.fullPage
  120. }),
  121. "style": style
  122. }, [_createVNode("div", {
  123. "class": bem("wrapper"),
  124. "ref": svgElRef
  125. }, [renderWatermark()])]);
  126. };
  127. }
  128. });
  129. export {
  130. stdin_default as default,
  131. watermarkProps
  132. };