UNPKG

antd-watermark

Version:
232 lines (198 loc) 8.84 kB
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import React, { useEffect, useRef } from 'react'; import useMutationObserver from "./useMutationObserver"; import { getStyleStr, getPixelRatio, rotateWatermark } from "./utils"; /** * Base size of the canvas, 1 for parallel layout and 2 for alternate layout * Only alternate layout is currently supported */ var BaseSize = 2; var FontGap = 3; var Watermark = function Watermark(props) { var _offset$, _offset$2; var _props$zIndex = props.zIndex, zIndex = _props$zIndex === void 0 ? 9 : _props$zIndex, _props$rotate = props.rotate, rotate = _props$rotate === void 0 ? -22 : _props$rotate, width = props.width, height = props.height, image = props.image, content = props.content, _props$font = props.font, font = _props$font === void 0 ? {} : _props$font, style = props.style, className = props.className, _props$gap = props.gap, gap = _props$gap === void 0 ? [100, 100] : _props$gap, offset = props.offset, children = props.children; var _font$color = font.color, color = _font$color === void 0 ? 'rgba(0,0,0,.15)' : _font$color, _font$fontSize = font.fontSize, fontSize = _font$fontSize === void 0 ? 16 : _font$fontSize, _font$fontWeight = font.fontWeight, fontWeight = _font$fontWeight === void 0 ? 'normal' : _font$fontWeight, _font$fontStyle = font.fontStyle, fontStyle = _font$fontStyle === void 0 ? 'normal' : _font$fontStyle, _font$fontFamily = font.fontFamily, fontFamily = _font$fontFamily === void 0 ? 'sans-serif' : _font$fontFamily; var _gap = _slicedToArray(gap, 2), gapX = _gap[0], gapY = _gap[1]; var gapXCenter = gapX / 2; var gapYCenter = gapY / 2; var offsetLeft = (_offset$ = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _offset$ !== void 0 ? _offset$ : gapXCenter; var offsetTop = (_offset$2 = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _offset$2 !== void 0 ? _offset$2 : gapYCenter; var getMarkStyle = function getMarkStyle() { var markStyle = { zIndex: zIndex, position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', pointerEvents: 'none', backgroundRepeat: 'repeat' }; /** Calculate the style of the offset */ var positionLeft = offsetLeft - gapXCenter; var positionTop = offsetTop - gapYCenter; if (positionLeft > 0) { markStyle.left = "".concat(positionLeft, "px"); markStyle.width = "calc(100% - ".concat(positionLeft, "px)"); positionLeft = 0; } if (positionTop > 0) { markStyle.top = "".concat(positionTop, "px"); markStyle.height = "calc(100% - ".concat(positionTop, "px)"); positionTop = 0; } markStyle.backgroundPosition = "".concat(positionLeft, "px ").concat(positionTop, "px"); return markStyle; }; var containerRef = useRef(null); var watermarkRef = useRef(); var _useMutationObserver = useMutationObserver(), createObserver = _useMutationObserver.createObserver, destroyObserver = _useMutationObserver.destroyObserver, reRendering = _useMutationObserver.reRendering; var destroyWatermark = function destroyWatermark() { if (watermarkRef.current) { watermarkRef.current.remove(); watermarkRef.current = undefined; } }; var appendWatermark = function appendWatermark(base64Url, markWidth) { if (containerRef.current && watermarkRef.current) { var _containerRef$current; destroyObserver(); watermarkRef.current.setAttribute('style', getStyleStr(_objectSpread(_objectSpread({}, getMarkStyle()), {}, { backgroundImage: "url('".concat(base64Url, "')"), backgroundSize: "".concat((gapX + markWidth) * BaseSize, "px") }))); (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.append(watermarkRef.current); createObserver(containerRef.current, function (mutations) { mutations.forEach(function (mutation) { if (reRendering(mutation, watermarkRef.current)) { destroyWatermark(); // eslint-disable-next-line @typescript-eslint/no-use-before-define renderWatermark(); } }); }); } }; /** * Get the width and height of the watermark. The default values are as follows * Image: [120, 64]; Content: It's calculated by content; */ var getMarkSize = function getMarkSize(ctx) { var defaultWidth = 120; var defaultHeight = 64; if (!image && ctx.measureText) { ctx.font = "".concat(Number(fontSize), "px ").concat(fontFamily); var contents = Array.isArray(content) ? content : [content]; var widths = contents.map(function (item) { return ctx.measureText(item).width; }); defaultWidth = Math.ceil(Math.max.apply(Math, _toConsumableArray(widths))); defaultHeight = Number(fontSize) * contents.length + (contents.length - 1) * FontGap; } return [width !== null && width !== void 0 ? width : defaultWidth, height !== null && height !== void 0 ? height : defaultHeight]; }; var fillTexts = function fillTexts(ctx, drawX, drawY, drawWidth, drawHeight) { var ratio = getPixelRatio(); var mergedFontSize = Number(fontSize) * ratio; ctx.font = "".concat(fontStyle, " normal ").concat(fontWeight, " ").concat(mergedFontSize, "px/").concat(drawHeight, "px ").concat(fontFamily); ctx.fillStyle = color; ctx.textAlign = 'center'; ctx.textBaseline = 'top'; ctx.translate(drawWidth / 2, 0); var contents = Array.isArray(content) ? content : [content]; contents === null || contents === void 0 ? void 0 : contents.forEach(function (item, index) { ctx.fillText(item !== null && item !== void 0 ? item : '', drawX, drawY + index * (mergedFontSize + FontGap * ratio)); }); }; var renderWatermark = function renderWatermark() { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); if (ctx) { if (!watermarkRef.current) { watermarkRef.current = document.createElement('div'); } var ratio = getPixelRatio(); var _getMarkSize = getMarkSize(ctx), _getMarkSize2 = _slicedToArray(_getMarkSize, 2), markWidth = _getMarkSize2[0], markHeight = _getMarkSize2[1]; var canvasWidth = (gapX + markWidth) * ratio; var canvasHeight = (gapY + markHeight) * ratio; canvas.setAttribute('width', "".concat(canvasWidth * BaseSize, "px")); canvas.setAttribute('height', "".concat(canvasHeight * BaseSize, "px")); var drawX = gapX * ratio / 2; var drawY = gapY * ratio / 2; var drawWidth = markWidth * ratio; var drawHeight = markHeight * ratio; var rotateX = (drawWidth + gapX * ratio) / 2; var rotateY = (drawHeight + gapY * ratio) / 2; /** Alternate drawing parameters */ var alternateDrawX = drawX + canvasWidth; var alternateDrawY = drawY + canvasHeight; var alternateRotateX = rotateX + canvasWidth; var alternateRotateY = rotateY + canvasHeight; ctx.save(); rotateWatermark(ctx, rotateX, rotateY, rotate); if (image) { var img = new Image(); img.onload = function () { ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight); /** Draw interleaved pictures after rotation */ ctx.restore(); rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate); ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight); appendWatermark(canvas.toDataURL(), markWidth); }; img.crossOrigin = 'anonymous'; img.referrerPolicy = 'no-referrer'; img.src = image; } else { fillTexts(ctx, drawX, drawY, drawWidth, drawHeight); /** Fill the interleaved text after rotation */ ctx.restore(); rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate); fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight); appendWatermark(canvas.toDataURL(), markWidth); } } }; useEffect(renderWatermark, [rotate, zIndex, width, height, image, content, color, fontSize, fontWeight, fontStyle, fontFamily, gapX, gapY, offsetLeft, offsetTop]); return /*#__PURE__*/React.createElement("div", { ref: containerRef, className: className, style: _objectSpread({ position: 'relative' }, style) }, children); }; export default Watermark;