{"version":3,"sources":["jsdelivr-header.js","/npm/@pansy/watermark@2.3.0/src/index.ts","/npm/@pansy/watermark@2.3.0/src/config.ts","/npm/@pansy/watermark@2.3.0/src/utils.ts"],"names":[],"mappings":"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","file":"/npm/@pansy/watermark@2.3.0/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@pansy/watermark@2.3.0/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import {\n  getDrawPattern,\n  getStyleStr,\n  getRandomId,\n  getContainer,\n  getContent,\n  getDataSetKey,\n  getMutationObserver,\n} from './utils';\nimport { defaultOptions, attributeNameTag, observeOptions } from './config';\nimport { WatermarkOptions } from './types';\nimport { blindDecryption } from './utils';\n\nconst MutationObserver = getMutationObserver();\n\nexport class Watermark {\n  /** 水印配置 */\n  private options: WatermarkOptions;\n  /** 水印挂载容器 */\n  private container: HTMLElement | undefined;\n  /** 水印的包含节点 */\n  private watermarkContent: HTMLElement | undefined;\n  /** 水印节点 */\n  private watermarkDom: HTMLElement | undefined;\n  /** 水印样式 */\n  private style: Record<string, any>;\n  private watermarkTag: string;\n  private shadowRoot: ShadowRoot | HTMLElement | undefined;\n  private mutationObserver: MutationObserver | null;\n\n  constructor(options: WatermarkOptions = {}) {\n    this.options = Object.assign({}, defaultOptions, options);\n    this.style = {\n      position: 'absolute',\n      left: 0,\n      top: 0,\n      right: 0,\n      bottom: 0,\n      pointerEvents: 'none',\n      overflow: 'hidden',\n      backgroundColor: 'transparent',\n      backgroundRepeat: 'repeat',\n    };\n    this.style.zIndex = this.options.zIndex;\n    this.watermarkTag = getRandomId('watermark');\n    this.mutationObserver = null;\n\n    this._render();\n  }\n\n  /**\n   * 更新水印配置，并重新渲染\n   * @param options\n   */\n  update(options: WatermarkOptions = {}) {\n    this.options = {\n      ...this.options,\n      ...options,\n    };\n    this.style.zIndex = this.options.zIndex;\n\n    this._render();\n  }\n\n  /**\n   * 显示水印\n   */\n  show() {\n    if (this.watermarkDom) {\n      this.style.display = 'block';\n      this.watermarkDom.setAttribute('style', getStyleStr(this.style));\n    }\n  }\n\n  /**\n   * 隐藏水印\n   */\n  hide() {\n    if (this.watermarkDom) {\n      this.style.display = 'none';\n      this.watermarkDom.setAttribute('style', getStyleStr(this.style));\n    }\n  }\n\n  /**\n   * 销毁水印\n   */\n  destroy() {\n    this.shadowRoot = undefined;\n\n    if (this.watermarkContent) {\n      this.watermarkContent.remove();\n      this.watermarkContent = undefined;\n    }\n\n    if (this.watermarkDom) {\n      this.watermarkDom.remove();\n      this.watermarkDom = undefined;\n    }\n\n    this._destroyMutationObserver();\n  }\n\n  /**\n   * 判断是否发起重新生成水印\n   * @param mutation\n   */\n  _isAgainRender = (mutation: MutationRecord) => {\n    // 修改样式或属性\n    if (mutation.type === 'attributes') {\n      if (mutation.attributeName === attributeNameTag) {\n        return true;\n      }\n      if (this.watermarkTag === this._getNodeRandomId(mutation.target)) {\n        return true;\n      }\n    }\n\n    // 删除节点\n    if (\n      mutation.removedNodes.length &&\n      this.watermarkTag === this._getNodeRandomId(mutation.removedNodes[0])\n    ) {\n      return true;\n    }\n\n    return false;\n  };\n\n  _getNodeRandomId = (node: Node) => {\n    return node?.['dataset']?.[getDataSetKey(attributeNameTag)];\n  };\n\n  /**\n   * 销毁MutationObserver\n   */\n  _destroyMutationObserver = () => {\n    if (this.mutationObserver) {\n      this.mutationObserver.takeRecords();\n      this.mutationObserver.disconnect();\n      this.mutationObserver = null;\n    }\n  };\n\n  /**\n   * 获取水印节点\n   * @param height\n   */\n  _getWatermarkDom = async (watermarkHeight: number) => {\n    if (!this.watermarkDom) {\n      this.watermarkDom = document.createElement('div');\n    }\n\n    if (typeof watermarkHeight === 'number' && watermarkHeight) {\n      this.style.height = `${watermarkHeight}px`;\n    }\n\n    const backgroundConfig = await getDrawPattern(this.options);\n\n    if (backgroundConfig?.url) {\n      const background = backgroundConfig.url;\n\n      if (this.options.mode === 'repeat') {\n        this.style.backgroundImage = `url(${background})`;\n      } else {\n        this.style.backgroundImage = `url(${background}), url(${background})`;\n        this.style.backgroundRepeat = 'repeat, repeat';\n        this.style.backgroundPosition = `${backgroundConfig.width / 2}px ${\n          backgroundConfig.height / 2\n        }px, 0 0`;\n      }\n      // 直接挂载在到body\n      if (!this.options.container) {\n        this.style.position = 'fixed';\n        this.style.height = undefined;\n      }\n      this.watermarkDom.setAttribute('style', getStyleStr(this.style));\n    }\n\n    this.watermarkDom.setAttribute(attributeNameTag, this.watermarkTag);\n\n    return this.watermarkDom;\n  };\n\n  _getWatermarkHeight = () => {\n    if (!this.container) return 0;\n    // 解决滚动区域无水印问题\n    let height = 0;\n\n    const { scrollHeight = 0, clientHeight = 0 }: HTMLElement = this.options.container\n      ? (this.container.parentNode as HTMLElement)\n      : this.container;\n\n    if (scrollHeight > clientHeight) {\n      height = Math.max(scrollHeight, clientHeight);\n    }\n\n    return height;\n  };\n\n  async _render() {\n    this._destroyMutationObserver();\n\n    // 获取水印挂载节点\n    this.container = getContainer(\n      this.options.container,\n      this.watermarkTag,\n      this.options.containerStyle,\n      this.options.pack,\n    );\n    // 获取水印父节点\n    if (!this.watermarkContent) {\n      this.watermarkContent = getContent(this.watermarkTag);\n      this.container.append(this.watermarkContent);\n    }\n\n    // 解决滚动区域无水印问题\n    const height = this._getWatermarkHeight();\n    // 获取水印DOM\n    this.watermarkDom = await this._getWatermarkDom(height);\n\n    // 删除已有水印\n    if (this.watermarkContent) {\n      const childs = this.watermarkContent.childNodes || [];\n\n      for (let i = 0; i < childs.length; i++) {\n        this.watermarkContent.removeChild(childs[i]);\n      }\n    }\n\n    // 判断是否支持 Shadow DOM\n    if (typeof this.watermarkContent.attachShadow === 'function') {\n      if (!this.shadowRoot) {\n        this.shadowRoot = this.watermarkContent.attachShadow({\n          mode: 'open',\n        });\n      }\n    } else {\n      this.shadowRoot = this.watermarkContent;\n    }\n\n    this.shadowRoot.append(this.watermarkDom);\n\n    if (MutationObserver && this.options.monitor) {\n      this.mutationObserver = new MutationObserver(mutations => {\n        mutations.forEach(mutation => {\n          if (this._isAgainRender(mutation)) {\n            this.destroy();\n            this._render();\n            return;\n          }\n        });\n      });\n      this.mutationObserver.observe(this.container, observeOptions);\n      this.shadowRoot && this.mutationObserver.observe(this.shadowRoot, observeOptions);\n    }\n  }\n}\n\nexport { WatermarkOptions } from './types';\nexport { defaultOptions } from './config';\nexport { blindDecryption };\n","import { WatermarkOptions } from './types';\n\nexport const defaultOptions: Partial<WatermarkOptions> = {\n  gapX: 100,\n  gapY: 100,\n  offsetLeft: 0,\n  offsetTop: 0,\n  width: 120,\n  height: 64,\n  opacity: 0.15,\n  rotate: -22,\n  fontSize: 16,\n  fontStyle: 'normal',\n  fontVariant: 'normal',\n  fontWeight: '300',\n  fontColor: '#000',\n  fontFamily: 'sans-serif',\n  textAlign: 'center',\n  textBaseline: 'alphabetic',\n  monitor: true,\n  zIndex: 9999,\n  mode: 'interval',\n  pack: true,\n  blindFontSize: 16,\n  blindOpacity: 0.005,\n};\n\n/** 用于标记是否需要保护 */\nexport const attributeNameTag = 'data-watermark-tag';\n\nexport const observeOptions = {\n  childList: true,\n  subtree: true,\n  attributeFilter: ['style', 'class', attributeNameTag],\n};\n","import { attributeNameTag } from './config';\nimport { WatermarkOptions, DrawPatternResult } from './types';\n\n/**\n * 获取 MutationObserver 对象\n */\nexport function getMutationObserver(): typeof MutationObserver {\n  // @ts-ignore\n  return window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;\n}\n\n/**\n * 获取DataSetKey\n * @param attributeName\n * @returns\n */\nexport function getDataSetKey(attributeName: string) {\n  return attributeName\n    .split('-')\n    .slice(1)\n    .reduce((prev, cur, index) => {\n      if (index === 0) {\n        return cur;\n      }\n\n      return `${prev}${cur[0].toUpperCase() + cur.slice(1)}`;\n    });\n}\n\n/**\n * 将样式对象转换为字符串\n * @param style\n */\nexport const getStyleStr = (style: object): string => {\n  let str = '';\n\n  Object.keys(style).forEach(item => {\n    const key = item.replace(/([A-Z])/g, '-$1').toLowerCase();\n    str += `${key}:${style[item]};`;\n  });\n\n  return str;\n};\n\nconst encrypt = (str: string): string => {\n  return window.btoa(decodeURI(encodeURIComponent(str)));\n};\n\n/**\n * 获取任意的ID\n * @param prefix\n * @returns\n */\nexport const getRandomId = (prefix = '') => {\n  return `${encrypt(prefix)}-${new Date().getTime()}-${Math.floor(\n    Math.random() * Math.pow(10, 8),\n  )}`;\n};\n\n/**\n * 获取水印挂载节点\n * @param container\n * @param watermarkId\n * @returns\n */\nexport const getContainer = (\n  container: WatermarkOptions['container'],\n  watermarkId: string,\n  containerStyle: Record<string, any> = {},\n  pack?: boolean,\n): HTMLElement => {\n  let dom: HTMLElement | null;\n\n  if (typeof container === 'string') {\n    dom = document.getElementById(container);\n    if (!dom) {\n      throw new Error(`水印挂载节点未找到，请检查#${container}是否存在`);\n    }\n  } else {\n    dom = container ?? document.body;\n  }\n\n  dom.setAttribute(attributeNameTag, watermarkId);\n\n  const style: Record<string, any> = {\n    position: 'relative',\n    ...containerStyle,\n  };\n\n  if (!pack) {\n    delete style.position;\n  }\n\n  dom.setAttribute('style', getStyleStr(style));\n\n  return dom;\n};\n\n// 盲水印解密\nexport const blindDecryption = (ctx: CanvasRenderingContext2D) => {\n  const originalData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);\n  let data = originalData.data;\n  for (let i = 0; i < data.length; i++) {\n    //筛选每个像素点的R值\n    if (i % 4 == 0) {\n      if (data[i] % 2 == 0) {\n        //如果R值为偶数，说明这个点是没有水印信息的，将其R值设为0\n        data[i] = 0;\n      } else {\n        //如果R值为奇数，说明这个点是有水印信息的，将其R值设为255\n        data[i] = 255;\n      }\n    } else if (i % 4 == 3) {\n      //透明度不作处理\n      continue;\n    } else {\n      // G、B值设置为0，不影响\n      data[i] = 0;\n    }\n  }\n  // // 至此，带有水印信息的点都将展示为255,0,0   而没有水印信息的点将展示为0,0,0  将结果绘制到画布\n  ctx.putImageData(originalData, 0, 0);\n};\n\nexport const getContent = (watermarkId: string) => {\n  const dom = document.createElement('div');\n  dom.setAttribute(\n    'style',\n    getStyleStr({\n      pointerEvents: 'none',\n    }),\n  );\n  dom.setAttribute(attributeNameTag, watermarkId);\n\n  return dom;\n};\n\nexport function getDrawPattern(config: WatermarkOptions): Promise<DrawPatternResult> {\n  const {\n    text,\n    gapX,\n    gapY,\n    offsetTop,\n    offsetLeft,\n    width,\n    height,\n    rotate,\n    opacity,\n    fontSize,\n    fontStyle,\n    fontVariant,\n    fontWeight,\n    fontFamily,\n    fontColor,\n    textAlign,\n    textBaseline,\n    image,\n    blindText,\n    blindFontSize,\n    blindOpacity,\n  } = config as Required<WatermarkOptions>;\n  return new Promise((resolve, reject) => {\n    const canvas = document.createElement('canvas');\n\n    const ctx = canvas.getContext('2d');\n    const ratio = 1;\n\n    const canvasWidth = (Number(gapX) + Number(width)) * ratio;\n    const canvasHeight = (Number(gapY) + Number(height)) * ratio;\n    const canvasOffsetLeft = Number(offsetLeft) || Number(gapX) / 2;\n    const canvasOffsetTop = Number(offsetTop) || Number(gapY) / 2;\n\n    canvas.setAttribute('width', `${canvasWidth}px`);\n    canvas.setAttribute('height', `${canvasHeight}px`);\n\n    if (ctx) {\n      const markWidth = width * ratio;\n      const markHeight = height * ratio;\n\n      ctx.translate(canvasOffsetLeft * ratio, canvasOffsetTop * ratio);\n      ctx.rotate((Math.PI / 180) * Number(rotate));\n\n      // 是否需要增加盲水印文字\n      if (blindText) {\n        // 盲水印需要低透明度\n        ctx.globalAlpha = blindOpacity;\n        ctx.font = `${blindFontSize}px normal`;\n        ctx.fillText(blindText, 0, 0);\n      }\n\n      // 设置透明度\n      ctx.globalAlpha = opacity;\n\n      // 优先使用图片\n      if (image) {\n        const img = new Image();\n        img.crossOrigin = 'anonymous';\n        img.referrerPolicy = 'no-referrer';\n        img.src = image;\n        img.onload = () => {\n          ctx.drawImage(img, 0, 0, markWidth, markHeight);\n          resolve({\n            url: ctx.canvas.toDataURL(),\n            width: canvasWidth,\n            height: canvasHeight,\n          });\n        };\n        return;\n      }\n\n      // 获取文本的最大宽度\n      const texts = Array.isArray(text) ? text : [text];\n      const widths = texts.map(item => ctx.measureText(item).width);\n      const maxWidth = Math.max(...widths);\n\n      const markSize = Number(fontSize) * ratio;\n\n      // 设置文本对齐方式\n      ctx.textAlign = textAlign;\n      // 设置文本位置\n      ctx.textBaseline = textBaseline;\n      // 设置字体颜色\n      ctx.fillStyle = fontColor;\n      // 设置字体\n      ctx.font = getFont(`${markSize}px`);\n\n      // 文案宽度大于画板宽度\n      if (maxWidth > width) {\n        ctx.font = getFont(`${markSize / 2}px`);\n      }\n\n      // 获取行高\n      const lineHeight = markSize + 5;\n\n      // 计算水印在y轴上的初始位置\n      let initY = (markHeight - (fontSize * texts.length + (texts.length - 1) * 5)) / 2;\n      initY = initY < 0 ? 0 : initY;\n\n      for (let i = 0; i < texts.length; i++) {\n        ctx.fillText(texts[i] || '', markWidth / 2, initY + lineHeight * i);\n      }\n      resolve({\n        url: ctx.canvas.toDataURL(),\n        width: canvasWidth,\n        height: canvasHeight,\n      });\n    }\n\n    function getFont(fontSize: string) {\n      return `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize} ${fontFamily}`;\n    }\n\n    return reject();\n  });\n}\n"]}