• javaScript蓝桥杯----图⽚⽔印⽣成



    一、介绍

    很多⽹站都会通过给图⽚添加⽔印的形式来标记图⽚来源,维护版权。前端⽣成⽔印通常是通过canvas 实现,但实际上我们也可以直接利⽤ CSS 来实现图⽚⽔印,这样做会有更好的浏览器兼容
    性。
    本题中你将封装⼀个创建⽂字⽔印的函数。

    二、准备

    开始答题前,需要先打开本题的项⽬代码⽂件夹,⽬录结构如下:

    ├── css
    │ └── style.css
    ├── images
    │ └── origin.png
    ├── index.html
    └── js
    ├── dom-to-image.min.js
    └── index.js
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其中:

    • index.html 是主⻚⾯。
    • css/style.css 是样式⽂件。
    • js/index.js 是需要补充代码的 js ⽂件。
    • js/dom-to-image.min.js 是⽣成图⽚的第三⽅库,此⽂件⽆需修改。
    • images/origin.png 是项⽬中的原始图⽚⽂件。

    在浏览器中预览 index.html ⻚⾯效果如下所示
    在这里插入图片描述

    三、⽬标

    请完善 js/index.js ⽂件中的 TODO 部分,实现创建⽔印函数的功能 ,创建的⽔印需要使⽤ 标签展示。
    createWatermark 函数参数说明:
    在这里插入图片描述
    完成后的效果如下:
    在这里插入图片描述

    四、代码

    index.htmll

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="css/style.css" />
        <title>图片水印生成title>
      head>
    
      <body>
        <main>
          <div class="container">
            <img src="images/origin.png" alt="cat" />
          div>
          <button>保存图片button>
        main>
        <script src="js/dom-to-image.min.js">script>
        <script src="js/index.js">script>
      body>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    style.css

    main {
      display: flex;
      align-items: center;
      flex-direction: column;
    }
    
    .container {
      width: 700px;
      display: inline-block;
      position: relative;
    }
    
    .container img {
      width: 100%;
      height: 100%;
    }
    
    .watermark {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
      pointer-events: none;
      white-space: nowrap;
      overflow: hidden;
    }
    
    .watermark span {
      line-height: 30px;
      display: inline-block;
      position: relative;
      top: 50%;
      transform: translateY(-50%);
      font: "sans serif";
    }
    
    button {
      display: block;
      margin-top: 1rem;
      border: none;
      padding: 1rem 1.5rem;
      cursor: pointer;
      border-radius: 5px;
    }
    
    button:active {
      background-color: gainsboro;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    images—>origin.png
    在这里插入图片描述
    dom-to-image.min.js

    /*!
     * Powered by uglifiyJS v2.6.1, Build by http://tool.uis.cc/jsmin/
     * build time: Tue Mar 21 2023 14:53:38 GMT+0800 (中国标准时间)
    */
    !function(global){"use strict";function toSvg(node,options){function applyOptions(clone){return options.bgcolor&&(clone.style.backgroundColor=options.bgcolor),options.width&&(clone.style.width=options.width+"px"),options.height&&(clone.style.height=options.height+"px"),options.style&&Object.keys(options.style).forEach(function(property){clone.style[property]=options.style[property]}),clone}return options=options||{},copyOptions(options),Promise.resolve(node).then(function(node){return cloneNode(node,options.filter,!0)}).then(embedFonts).then(inlineImages).then(applyOptions).then(function(clone){return makeSvgDataUri(clone,options.width||util.width(node),options.height||util.height(node))})}function toPixelData(node,options){return draw(node,options||{}).then(function(canvas){return canvas.getContext("2d").getImageData(0,0,util.width(node),util.height(node)).data})}function toPng(node,options){return draw(node,options||{}).then(function(canvas){return canvas.toDataURL()})}function toJpeg(node,options){return options=options||{},draw(node,options).then(function(canvas){return canvas.toDataURL("image/jpeg",options.quality||1)})}function toBlob(node,options){return draw(node,options||{}).then(util.canvasToBlob)}function copyOptions(options){"undefined"==typeof options.imagePlaceholder?domtoimage.impl.options.imagePlaceholder=defaultOptions.imagePlaceholder:domtoimage.impl.options.imagePlaceholder=options.imagePlaceholder,"undefined"==typeof options.cacheBust?domtoimage.impl.options.cacheBust=defaultOptions.cacheBust:domtoimage.impl.options.cacheBust=options.cacheBust}function draw(domNode,options){function newCanvas(domNode){var canvas=document.createElement("canvas");if(canvas.width=options.width||util.width(domNode),canvas.height=options.height||util.height(domNode),options.bgcolor){var ctx=canvas.getContext("2d");ctx.fillStyle=options.bgcolor,ctx.fillRect(0,0,canvas.width,canvas.height)}return canvas}return toSvg(domNode,options).then(util.makeImage).then(util.delay(100)).then(function(image){var canvas=newCanvas(domNode);return canvas.getContext("2d").drawImage(image,0,0),canvas})}function cloneNode(node,filter,root){function makeNodeCopy(node){return node instanceof HTMLCanvasElement?util.makeImage(node.toDataURL()):node.cloneNode(!1)}function cloneChildren(original,clone,filter){function cloneChildrenInOrder(parent,children,filter){var done=Promise.resolve();return children.forEach(function(child){done=done.then(function(){return cloneNode(child,filter)}).then(function(childClone){childClone&&parent.appendChild(childClone)})}),done}var children=original.childNodes;return 0===children.length?Promise.resolve(clone):cloneChildrenInOrder(clone,util.asArray(children),filter).then(function(){return clone})}function processClone(original,clone){function cloneStyle(){function copyStyle(source,target){function copyProperties(source,target){util.asArray(source).forEach(function(name){target.setProperty(name,source.getPropertyValue(name),source.getPropertyPriority(name))})}source.cssText?target.cssText=source.cssText:copyProperties(source,target)}copyStyle(window.getComputedStyle(original),clone.style)}function clonePseudoElements(){function clonePseudoElement(element){function formatPseudoElementStyle(className,element,style){function formatCssText(style){var content=style.getPropertyValue("content");return style.cssText+" content: "+content+";"}function formatCssProperties(style){function formatProperty(name){return name+": "+style.getPropertyValue(name)+(style.getPropertyPriority(name)?" !important":"")}return util.asArray(style).map(formatProperty).join("; ")+";"}var selector="."+className+":"+element,cssText=style.cssText?formatCssText(style):formatCssProperties(style);return document.createTextNode(selector+"{"+cssText+"}")}var style=window.getComputedStyle(original,element),content=style.getPropertyValue("content");if(""!==content&&"none"!==content){var className=util.uid();clone.className=clone.className+" "+className;var styleElement=document.createElement("style");styleElement.appendChild(formatPseudoElementStyle(className,element,style)),clone.appendChild(styleElement)}}[":before",":after"].forEach(function(element){clonePseudoElement(element)})}function copyUserInput(){original instanceof HTMLTextAreaElement&&(clone.innerHTML=original.value),original instanceof HTMLInputElement&&clone.setAttribute("value",original.value)}function fixSvg(){clone instanceof SVGElement&&(clone.setAttribute("xmlns","http://www.w3.org/2000/svg"),clone instanceof SVGRectElement&&["width","height"].forEach(function(attribute){var value=clone.getAttribute(attribute);value&&clone.style.setProperty(attribute,value)}))}return clone instanceof Element?Promise.resolve().then(cloneStyle).then(clonePseudoElements).then(copyUserInput).then(fixSvg).then(function(){return clone}):clone}return root||!filter||filter(node)?Promise.resolve(node).then(makeNodeCopy).then(function(clone){return cloneChildren(node,clone,filter)}).then(function(clone){return processClone(node,clone)}):Promise.resolve()}function embedFonts(node){return fontFaces.resolveAll().then(function(cssText){var styleNode=document.createElement("style");return node.appendChild(styleNode),styleNode.appendChild(document.createTextNode(cssText)),node})}function inlineImages(node){return images.inlineAll(node).then(function(){return node})}function makeSvgDataUri(node,width,height){return Promise.resolve(node).then(function(node){return node.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),(new XMLSerializer).serializeToString(node)}).then(util.escapeXhtml).then(function(xhtml){return''+xhtml+""}).then(function(foreignObject){return'+width+'" height="'+height+'">'+foreignObject+""}).then(function(svg){return"data:image/svg+xml;charset=utf-8,"+svg})}function newUtil(){function mimes(){var WOFF="application/font-woff",JPEG="image/jpeg";return{woff:WOFF,woff2:WOFF,ttf:"application/font-truetype",eot:"application/vnd.ms-fontobject",png:"image/png",jpg:JPEG,jpeg:JPEG,gif:"image/gif",tiff:"image/tiff",svg:"image/svg+xml"}}function parseExtension(url){var match=/\.([^\.\/]*?)$/g.exec(url);return match?match[1]:""}function mimeType(url){var extension=parseExtension(url).toLowerCase();return mimes()[extension]||""}function isDataUrl(url){return-1!==url.search(/^(data:)/)}function toBlob(canvas){return new Promise(function(resolve){for(var binaryString=window.atob(canvas.toDataURL().split(",")[1]),length=binaryString.length,binaryArray=new Uint8Array(length),i=0;length>i;i++)binaryArray[i]=binaryString.charCodeAt(i);resolve(new Blob([binaryArray],{type:"image/png"}))})}function canvasToBlob(canvas){return canvas.toBlob?new Promise(function(resolve){canvas.toBlob(resolve)}):toBlob(canvas)}function resolveUrl(url,baseUrl){var doc=document.implementation.createHTMLDocument(),base=doc.createElement("base");doc.head.appendChild(base);var a=doc.createElement("a");return doc.body.appendChild(a),base.href=baseUrl,a.href=url,a.href}function uid(){var index=0;return function(){function fourRandomChars(){return("0000"+(Math.random()*Math.pow(36,4)<<0).toString(36)).slice(-4)}return"u"+fourRandomChars()+index++}}function makeImage(uri){return new Promise(function(resolve,reject){var image=new Image;image.onload=function(){resolve(image)},image.onerror=reject,image.src=uri})}function getAndEncode(url){var TIMEOUT=3e4;return domtoimage.impl.options.cacheBust&&(url+=(/\?/.test(url)?"&":"?")+(new Date).getTime()),new Promise(function(resolve){function done(){if(4===request.readyState){if(200!==request.status)return void(placeholder?resolve(placeholder):fail("cannot fetch resource: "+url+", status: "+request.status));var encoder=new FileReader;encoder.onloadend=function(){var content=encoder.result.split(/,/)[1];resolve(content)},encoder.readAsDataURL(request.response)}}function timeout(){placeholder?resolve(placeholder):fail("timeout of "+TIMEOUT+"ms occured while fetching resource: "+url)}function fail(message){resolve("")}var request=new XMLHttpRequest;request.onreadystatechange=done,request.ontimeout=timeout,request.responseType="blob",request.timeout=TIMEOUT,request.open("GET",url,!0),request.send();var placeholder;if(domtoimage.impl.options.imagePlaceholder){var split=domtoimage.impl.options.imagePlaceholder.split(/,/);split&&split[1]&&(placeholder=split[1])}})}function dataAsUrl(content,type){return"data:"+type+";base64,"+content}function escape(string){return string.replace(/([.*+?^${}()|\[\]\/\\])/g,"\\$1")}function delay(ms){return function(arg){return new Promise(function(resolve){setTimeout(function(){resolve(arg)},ms)})}}function asArray(arrayLike){for(var array=[],length=arrayLike.length,i=0;length>i;i++)array.push(arrayLike[i]);return array}function escapeXhtml(string){return string.replace(/#/g,"%23").replace(/\n/g,"%0A")}function width(node){var leftBorder=px(node,"border-left-width"),rightBorder=px(node,"border-right-width");return node.scrollWidth+leftBorder+rightBorder}function height(node){var topBorder=px(node,"border-top-width"),bottomBorder=px(node,"border-bottom-width");return node.scrollHeight+topBorder+bottomBorder}function px(node,styleProperty){var value=window.getComputedStyle(node).getPropertyValue(styleProperty);return parseFloat(value.replace("px",""))}return{escape:escape,parseExtension:parseExtension,mimeType:mimeType,dataAsUrl:dataAsUrl,isDataUrl:isDataUrl,canvasToBlob:canvasToBlob,resolveUrl:resolveUrl,getAndEncode:getAndEncode,uid:uid(),delay:delay,asArray:asArray,escapeXhtml:escapeXhtml,makeImage:makeImage,width:width,height:height}}function newInliner(){function shouldProcess(string){return-1!==string.search(URL_REGEX)}function readUrls(string){for(var match,result=[];null!==(match=URL_REGEX.exec(string));)result.push(match[1]);return result.filter(function(url){return!util.isDataUrl(url)})}function inline(string,url,baseUrl,get){function urlAsRegex(url){return new RegExp("(url\\(['\"]?)("+util.escape(url)+")(['\"]?\\))","g")}return Promise.resolve(url).then(function(url){return baseUrl?util.resolveUrl(url,baseUrl):url}).then(get||util.getAndEncode).then(function(data){return util.dataAsUrl(data,util.mimeType(url))}).then(function(dataUrl){return string.replace(urlAsRegex(url),"$1"+dataUrl+"$3")})}function inlineAll(string,baseUrl,get){function nothingToInline(){return!shouldProcess(string)}return nothingToInline()?Promise.resolve(string):Promise.resolve(string).then(readUrls).then(function(urls){var done=Promise.resolve(string);return urls.forEach(function(url){done=done.then(function(string){return inline(string,url,baseUrl,get)})}),done})}var URL_REGEX=/url\(['"]?([^'"]+?)['"]?\)/g;return{inlineAll:inlineAll,shouldProcess:shouldProcess,impl:{readUrls:readUrls,inline:inline}}}function newFontFaces(){function resolveAll(){return readAll(document).then(function(webFonts){return Promise.all(webFonts.map(function(webFont){return webFont.resolve()}))}).then(function(cssStrings){return cssStrings.join("\n")})}function readAll(){function selectWebFontRules(cssRules){return cssRules.filter(function(rule){return rule.type===CSSRule.FONT_FACE_RULE}).filter(function(rule){return inliner.shouldProcess(rule.style.getPropertyValue("src"))})}function getCssRules(styleSheets){var cssRules=[];return styleSheets.forEach(function(sheet){try{util.asArray(sheet.cssRules||[]).forEach(cssRules.push.bind(cssRules))}catch(e){}}),cssRules}function newWebFont(webFontRule){return{resolve:function(){var baseUrl=(webFontRule.parentStyleSheet||{}).href;return inliner.inlineAll(webFontRule.cssText,baseUrl)},src:function(){return webFontRule.style.getPropertyValue("src")}}}return Promise.resolve(util.asArray(document.styleSheets)).then(getCssRules).then(selectWebFontRules).then(function(rules){return rules.map(newWebFont)})}return{resolveAll:resolveAll,impl:{readAll:readAll}}}function newImages(){function newImage(element){function inline(get){return util.isDataUrl(element.src)?Promise.resolve():Promise.resolve(element.src).then(get||util.getAndEncode).then(function(data){return util.dataAsUrl(data,util.mimeType(element.src))}).then(function(dataUrl){return new Promise(function(resolve,reject){element.onload=resolve,element.onerror=reject,element.src=dataUrl})})}return{inline:inline}}function inlineAll(node){function inlineBackground(node){var background=node.style.getPropertyValue("background");return background?inliner.inlineAll(background).then(function(inlined){node.style.setProperty("background",inlined,node.style.getPropertyPriority("background"))}).then(function(){return node}):Promise.resolve(node)}return node instanceof Element?inlineBackground(node).then(function(){return node instanceof HTMLImageElement?newImage(node).inline():Promise.all(util.asArray(node.childNodes).map(function(child){return inlineAll(child)}))}):Promise.resolve(node)}return{inlineAll:inlineAll,impl:{newImage:newImage}}}var util=newUtil(),inliner=newInliner(),fontFaces=newFontFaces(),images=newImages(),defaultOptions={imagePlaceholder:void 0,cacheBust:!1},domtoimage={toSvg:toSvg,toPng:toPng,toJpeg:toJpeg,toBlob:toBlob,toPixelData:toPixelData,impl:{fontFaces:fontFaces,images:images,util:util,inliner:inliner,options:{}}};"undefined"!=typeof module?module.exports=domtoimage:global.domtoimage=domtoimage}(this);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    index.js

    /**
     * 创建一个文字水印的div
     * @param  {string} text - 水印文字
     * @param  {string} color - 水印颜色
     * @param  {number} deg - 水印旋转角度
     * @param  {number} opacity - 水印透明度
     * @param  {number} count - 水印数量
     */
    function createWatermark(text, color, deg, opacity, count) {
      // 创建水印容器
      const container = document.createElement('div')
      container.className = 'watermark'
    
      // TODO: 根据输入参数创建文字水印
    
      return container
    }
    
    // 以下代码不需要修改
    // 调用createWatermark方法,创建图片水印
    const watermark = createWatermark('WaterMark', 'white', 45, 0.5, 11)
    // 将水印挂载到图片容器上
    const container = document.querySelector('.container')
    container.appendChild(watermark)
    
    // 提供图片保存功能
    const button = document.querySelector('button')
    button.addEventListener('click', () => {
      domtoimage.toJpeg(document.querySelector('.container')).then((dataUrl) => {
        const link = document.createElement('a')
        link.download = 'image.jpeg'
        link.href = dataUrl
        link.click()
      })
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    五、完成

    index.js

    /**
     * 创建一个文字水印的div
     * @param  {string} text - 水印文字
     * @param  {string} color - 水印颜色
     * @param  {number} deg - 水印旋转角度
     * @param  {number} opacity - 水印透明度
     * @param  {number} count - 水印数量
     */
    function createWatermark(text, color, deg, opacity, count) {
      // 创建水印容器
      const container = document.createElement('div')
      container.className = 'watermark'
    
      // TODO: 根据输入参数创建文字水印
      for (let i = 0; i < count; i++) {
        const span = document.createElement('span')
        span.style.color = color
        span.style.transform = `rotate(${deg}deg)`
        span.style.opacity = opacity
        span.innerText += text
        container.appendChild(span)
      }
    
      return container
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    C Primer Plus(6) 中文版 第10章 数组和指针 10.9 复合字面值 10.10 关键概念 10.11 本章小结
    摊还分析在算法设计中的应用
    论文《Enhancing Hypergraph Neural Networks with Intent Disentanglement for SBR》阅读
    UE5射击游戏案例蓝图篇(一)
    题目0097-数组组成的最小数字
    探索无界,共创未来 —来自 TDengine 的伙伴招募邀请
    进入数字化供应链高潮期,与IBM咨询共创无边界竞争力
    【MySQL】索引的创建、查看和删除
    【持久层框架】- SpringData - JPA
    shell实例第24讲:zookeeper启动、停止、查看状态脚本
  • 原文地址:https://blog.csdn.net/m0_58065010/article/details/131078865