zoukankan      html  css  js  c++  java
  • 给图片添加水印

    首选为PS

    操作步骤:

    第一步,快捷键Ctrl+Shift+N新建空白图层,输入要添加的水印文本,比如“部落窝教育”,然后按CTRL+T,将水印文本旋转角度,旋转完毕角度之后,按下回车键确认变换。效果如下:

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第二步,隐藏水印文字下面的背景图层,使其不显示出来。注意观察图层面板。

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第三步,使用矩形选区工具,绘制一个矩形选区,将文字包含在选区里面。

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第四步,找到编辑菜单——定义图案,确定。

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第五步,按下CTRL+D,取消选区。然后将“背景”图层显示出来。

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第六步,按DEL键,将上面的水印文字图层删除。此时,就只有背景图层了。

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第七步,单击图层面板的“创建新图层”,创建一个新图层,为:图层1。

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     第八步,按下SHIFT+F5键,打开“填充”对话框。选择我们前面操作步骤定义的水印文字。截图如下:

    图片水印,通过PS给照片添加满屏水印_www.16xx8.com

     

    python也能够装逼

    from PIL import Image, ImageDraw, ImageFont
    
    
    def add_text_to_image(image, text):
        font = ImageFont.truetype ('C:WindowsFontsSTXINGKA.TTF', 36)
    
        # 添加背景
        new_img = Image.new ('RGBA', (image.size[0] * 3, image.size[1] * 3), (0, 0, 0, 0))
        new_img.paste (image, image.size)
    
        # 添加水印
        font_len = len (text)
        rgba_image = new_img.convert ('RGBA')
        text_overlay = Image.new ('RGBA', rgba_image.size, (255, 255, 255, 0))
        image_draw = ImageDraw.Draw (text_overlay)
    
        for i in range (0, rgba_image.size[0], font_len * 40 + 100):
            for j in range (0, rgba_image.size[1], 200):
                image_draw.text ((i, j), text, font=font, fill=(0, 0, 0, 50))
        text_overlay = text_overlay.rotate (-45)
        image_with_text = Image.alpha_composite (rgba_image, text_overlay)
    
        # 裁切图片
        image_with_text = image_with_text.crop ((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2))
        return image_with_text
    
    
    if __name__ == '__main__':
        img = Image.open ("scr.jpg")
        im_after = add_text_to_image (img, u'测试使用')
        im_after.save (u'测试使用.png')

    效果图

     HTML页面添加水印

    网页水印生成解决方案

    通过canvas生成水印

    这里我们用canvas来生成base64图片,通过CanIUse网站查询兼容性,如果在移动端以及一些管理系统使用,兼容性问题可以完全忽略。

    HTMLCanvasElement.toDataURL 方法返回一个包含图片展示的 data URI 。可以使用 type 参数其类型,默认为 PNG 格式。图片的分辨率为96dpi。

    如果画布的高度或宽度是0,那么会返回字符串“data:,”。 如果传入的类型非“image/png”,但是返回的值以“data:image/png”开头,那么该传入的类型是不支持的。 Chrome支持“image/webp”类型。具体参考HTMLCanvasElement.toDataURL

    具体代码实现如下:

    (function () {      // canvas 实现 watermark      function __canvasWM({        // 使用 ES6 的函数默认值方式设置参数的默认取值        // 具体参见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Default_parameters        container = document.body,        width = '200px',        height = '150px',        textAlign = 'center',        textBaseline = 'middle',        font = "20px microsoft yahei",        fillStyle = 'rgba(184, 184, 184, 0.8)',        content = '请勿外传',        rotate = '30',        zIndex = 1000      } = {}) {        var args = arguments[0];        var canvas = document.createElement('canvas');        canvas.setAttribute('width', width);        canvas.setAttribute('height', height);        var ctx = canvas.getContext("2d");        ctx.textAlign = textAlign;        ctx.textBaseline = textBaseline;        ctx.font = font;        ctx.fillStyle = fillStyle;        ctx.rotate(Math.PI / 180 * rotate);        ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2);        var base64Url = canvas.toDataURL();        const watermarkDiv = document.createElement("div");        watermarkDiv.setAttribute('style', `          position:absolute;          top:0;          left:0;          100%;          height:100%;          z-index:${zIndex};          pointer-events:none;          background-repeat:repeat;          background-image:url('${base64Url}')`);        container.style.position = 'relative';        container.insertBefore(watermarkDiv, container.firstChild);      });      window.__canvasWM = __canvasWM;    })();    // 调用    __canvasWM({      content: 'QQMusicFE'    })

    效果如下:

    为了使这个方法更通用,兼容不同的引用方式,我们还可以加上这段代码:

      // 为了兼容不同的环境      if (typeof module != 'undefined' && module.exports) {  //CMD        module.exports = __canvasWM;      } else if (typeof define == 'function' && define.amd) { // AMD        define(function () {          return __canvasWM;        });      } else {        window.__canvasWM = __canvasWM;      }

    这样似乎能满足我们的需求了,但是还有一个问题,稍微懂一点浏览器的使用或者网页知识的用户,可以用浏览器的开发者工具来动态更改DOM的属性或者结构就可以去掉了。这个时候有两个解决办法:

    1. 监测水印div的变化,记录刚生成的div的innerHTML,每隔几秒就取一次新的值,一旦发生变化,则重新生成水印。但是这种方式可能影响性能;
    2. 使用MutationObserver

    MutationObserver给开发者们提供了一种能在某个范围内的DOM树发生变化时作出适当反应的能力。

    通过兼容性表可以看出高级浏览器以及移动浏览器支持非常不错。 Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。 使用MutationObserver构造函数,新建一个观察器实例,实例的有一个回调函数,该回调函数接受两个参数,第一个是变动数组,第二个是观察器实例。MutationObserver 的实例的observe方法用来启动监听,它接受两个参数。 第一个参数:所要观察的 DOM 节点,第二个参数:一个配置对象,指定所要观察的特定变动,有以下几种:

    属性

    描述

    childList

    如果需要观察目标节点的子节点(新增了某个子节点,或者移除了某个子节点),则设置为true.

    attributes

    如果需要观察目标节点的属性节点(新增或删除了某个属性,以及某个属性的属性值发生了变化),则设置为true.

    characterData

    如果目标节点为characterData节点(一种抽象接口,具体可以为文本节点,注释节点,以及处理指令节点)时,也要观察该节点的文本内容是否发生变化,则设置为true.

    subtree

    除了目标节点,如果还需要观察目标节点的所有后代节点(观察目标节点所包含的整棵DOM树上的上述三种节点变化),则设置为true.

    attributeOldValue

    在attributes属性已经设为true的前提下,如果需要将发生变化的属性节点之前的属性值记录下来(记录到下面MutationRecord对象的oldValue属性中),则设置为true.

    characterDataOldValue

    在characterData属性已经设为true的前提下,如果需要将发生变化的characterData节点之前的文本内容记录下来(记录到下面MutationRecord对象的oldValue属性中),则设置为true.

    attributeFilter

    一个属性名数组(不需要指定命名空间),只有该数组中包含的属性名发生变化时才会被观察到,其他名称的属性发生变化后会被忽略.

    MutationObserver只能监测到诸如属性改变、增删子结点等,对于自己本身被删除,是没有办法的可以通过监测父结点来达到要求。因此最终改造之后代码为:

     (function () {      // canvas 实现 watermark      function __canvasWM({        // 使用 ES6 的函数默认值方式设置参数的默认取值        // 具体参见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Default_parameters        container = document.body,        width = '300px',        height = '200px',        textAlign = 'center',        textBaseline = 'middle',        font = "20px Microsoft Yahei",        fillStyle = 'rgba(184, 184, 184, 0.6)',        content = '请勿外传',        rotate = '30',        zIndex = 1000      } = {}) {        const args = arguments[0];        const canvas = document.createElement('canvas');        canvas.setAttribute('width', width);        canvas.setAttribute('height', height);        const ctx = canvas.getContext("2d");        ctx.textAlign = textAlign;        ctx.textBaseline = textBaseline;        ctx.font = font;        ctx.fillStyle = fillStyle;        ctx.rotate(Math.PI / 180 * rotate);        ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2);        const base64Url = canvas.toDataURL();        const __wm = document.querySelector('.__wm');        const watermarkDiv = __wm || document.createElement("div");        const styleStr = `          position:absolute;          top:0;          left:0;          100%;          height:100%;          z-index:${zIndex};          pointer-events:none;          background-repeat:repeat;          background-image:url('${base64Url}')`;        watermarkDiv.setAttribute('style', styleStr);        watermarkDiv.classList.add('__wm');        if (!__wm) {          container.style.position = 'relative';          container.insertBefore(watermarkDiv, container.firstChild);        }        const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;        if (MutationObserver) {          let mo = new MutationObserver(function () {            const __wm = document.querySelector('.__wm');            // 只在__wm元素变动才重新调用 __canvasWM            if ((__wm && __wm.getAttribute('style') !== styleStr) || !__wm) {              // 避免一直触发              mo.disconnect();              mo = null;            __canvasWM(JSON.parse(JSON.stringify(args)));            }          });          mo.observe(container, {            attributes: true,            subtree: true,            childList: true          })        }      }      if (typeof module != 'undefined' && module.exports) {  //CMD        module.exports = __canvasWM;      } else if (typeof define == 'function' && define.amd) { // AMD        define(function () {          return __canvasWM;        });      } else {        window.__canvasWM = __canvasWM;      }    })();    // 调用    __canvasWM({      content: 'QQMusicFE'    });

    通过SVG生成水印

    SVG:可缩放矢量图形(英语:Scalable Vector Graphics,SVG)是一种基于可扩展标记语言(XML),用于描述二维矢量图形的图形格式。 SVG由W3C制定,是一个开放标准。 -- 维基百科

    相比Canvas,SVG有更好的浏览器兼容性,使用SVG生成水印的方式与Canvas的方式类似,只是base64Url的生成方式换成了SVG。具体如下:

     (function () {      // svg 实现 watermark      function __svgWM({        container = document.body,        content = '请勿外传',        width = '300px',        height = '200px',        opacity = '0.2',        fontSize = '20px',        zIndex = 1000      } = {}) {        const args = arguments[0];        const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${width}">  <text x="50%" y="50%" dy="12px"    text-anchor="middle"    stroke="#000000"    stroke-width="1"    stroke-opacity="${opacity}"    fill="none"    transform="rotate(-45, 120 120)"    style="font-size: ${fontSize};">    ${content}  </text></svg>`;        const base64Url = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`;        const __wm = document.querySelector('.__wm');        const watermarkDiv = __wm || document.createElement("div");     // ...     // 与 canvas 的一致     // ...    })();    __svgWM({      content: 'QQMusicFE'    })

    身为现代前端开发者,Node.JS也是需要掌握的。我们同样可以通过NodeJS来生成网页水印(出于性能考虑更好的方式是利用用户客户端来生成)。前端发一个请求,参数带上水印内容,后台返回图片内容。 具体实现(Koa2环境):

    1. 安装gm以及相关环境,详情看gm文档
    2. ctx.type='image/png';设置响应为图片类型
    3. 生成图片过程是异步的,所以需要包装一层Promise,这样才能为通过 async/await 方式为 ctx.body 赋值
    const fs =  require ('fs' )const gm =  require ('gm' ); const imageMagick = gm 。子类({   imageMagick : true } ); const router =  require ('koa-router' )(); 路由器。get ('/ wm' , 异步 ( ctx , next ) => {   const  {     text   }  = ctx 。查询;   ctx 。类型=  'image / png' ;   ctx 。状态=  200 ;   ctx 。体=  AWAIT  ((() =>  {     返回 新 无极((决心,拒绝) =>  {      ImageMagick的(200 , 100 , “RGBA(255,255,255,0)” )        。fontSize (40 )        。的drawText (10 , 50 ,文本)        。写(要求('路径' )。加入( __dirname , `./ $ {文本} .png`), 功能 ( ERR ) {           如果 ( ERR ) {            拒绝( ERR );           }  其他 {            决心( FS 。readFileSync (要求('路径' )。加入( __dirname , `./ $ {文本} .png`)))          }         } );     } )  } )()); } );

    如果只是简单的水印展示,建议在浏览器生成,性能更好

    图片水印生成解决方案

    除了给网页加上水印之外,有时候我们需要给图片也加上水印,这样在用户保存图片后,带上了水印来源信息,既可以保护版权,水印的其他信息也可以防止泄密。

    通过canvas给图片加水印

    实现如下:

     (function() {      function __picWM({        url = '',        textAlign = 'center',        textBaseline = 'middle',        font = "20px Microsoft Yahei",        fillStyle = 'rgba(184, 184, 184, 0.8)',        content = '请勿外传',        cb = null,        textX = 100,        textY = 30      } = {}) {        const img = new Image();        img.src = url;        img.crossOrigin = 'anonymous';        img.onload = function() {          const canvas = document.createElement('canvas');          canvas.width = img.width;          canvas.height = img.height;          const ctx = canvas.getContext('2d');          ctx.drawImage(img, 0, 0);          ctx.textAlign = textAlign;          ctx.textBaseline = textBaseline;          ctx.font = font;          ctx.fillStyle = fillStyle;          ctx.fillText(content, img.width - textX, img.height - textY);          const base64Url = canvas.toDataURL();          cb && cb(base64Url);        }      }        if (typeof module != 'undefined' && module.exports) {  //CMD        module.exports = __picWM;      } else if (typeof define == 'function' && define.amd) { // AMD        define(function () {          return __picWM;        });      } else {        window.__picWM = __picWM;      }    })();    // 调用    __picWM({        url: 'http://localhost:3000/imgs/google.png',        content: 'QQMusicFE',        cb: (base64Url) => {          document.querySelector('img').src = base64Url        },      });

    效果如下:

    通过NodeJS批量为图片加水印

    我们同样可以通过gm这个库来给图片加上水印

    function picWM(path, text) {  imageMagick(path)    .drawText(10, 50, text)    .write(require('path').join(__dirname, `./${text}.png`), function (err) {      if (err) {        console.log(err);      }    });}

    如果需要批处理图片,只需要遍历相关文件即可

     

      1 <style type="text/css" media="screen">
      2     .cover {
      3         position:absolute;
      4         left:0;
      5         top:0;
      6         z-index:999999999999999;
      7         margin-right:0px;
      8         margin-left:0px;
      9         margin-top:5px;
     10         margin-bottom:140px;
     11         color:#fff;
     12         color:#ccc;
     13         display:block;
     14         padding:2px 1px;
     15         font-family:'宋体';
     16         font-size:16px;
     17         font-weight:bold;
     18         white-space:nowrap;
     19         text-shadow: 1px 0 0 #eee;
     20         transform:rotate(45deg);
     21         -ms-transform:rotate(45deg);
     22         -moz-transform:rotate(45deg);
     23         -webkit-transform:rotate(45deg);
     24         -o-transform:rotate(45deg);
     25         -moz-opacity:0.3; opacity:0.3;
     26         -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.7071067811865474, M12=-0.7071067811865477, M21=0.7071067811865477, M22=0.7071067811865474, SizingMethod='auto expand')";
     27     }
     28     .cover-Blink-area{ position:absolute;text-align: center;left:0;top:0;width:100%;height:100%;display:block;z-index:999999999999999; pointer-events: none;overflow: hidden;}
     29     .cover-Blink{
     30         display:inline-block;
     31         margin-right:50px;
     32         margin-left:50px;
     33         margin-top:140px;
     34         margin-bottom:140px;
     35         color:red;
     36         padding:2px 1px;
     37         font-family:'宋体';
     38         font-size:16px;
     39         font-weight:bold;
     40         color: pink;
     41         white-space:nowrap;
     42         text-shadow: 1px 0 0 rgba(0,0,0,.2);
     43         transform:rotate(45deg);
     44         -ms-transform:rotate(45deg);
     45         -moz-transform:rotate(45deg);
     46         -webkit-transform:rotate(45deg);
     47         -o-transform:rotate(45deg);
     48  
     49     }
     50 </style>
     51  
     52 <script type="text/javascript">
     53     $(function(){
     54         waterMark$();
     55     });
     56     function waterMark$(){
     57         if(navigator.appName == "Microsoft Internet Explorer"&& navigator.appVersion.match(/11./i)!="11."){
     58             $("p[name='p1$']").remove();
     59             var winwidth$ = document.body.scrollWidth-17;
     60             var winheight$ = document.body.scrollHeight;
     61             $("body").append("<p id='waterSum_11' name='p1$' class='cover_through cover js-click-to-alert'>测试张璐</p>");
     62             var fleft = Number($('#waterSum_11').css("margin-left").substring(0,$('#waterSum_11').css("margin-left").indexOf('p')));
     63             var ftop = Number($('#waterSum_11').css("margin-top").substring(0,$('#waterSum_11').css("margin-top").indexOf('p')));
     64             var perWidth = $("#waterSum_11").width();
     65             var perHeight = Number('140px'.substring(0,'140px'.indexOf('p')))+100;
     66             var lines = parseInt(winwidth$/(perWidth+fleft));
     67             var rows = Math.round(winheight$/(perHeight+ftop));
     68             var totalPWidth = perWidth*lines;
     69             var totalSpace = winwidth$-totalPWidth;
     70             var perSpace = parseInt(totalSpace/(lines+1));
     71             $('#waterSum_11').css("margin-left",perSpace);
     72             for(var i=1;i<=rows;i++) {
     73                 for(var j=1;j<=lines;j++){
     74                     if(i==1){
     75                         if(j<=lines-1){
     76                             var p = "<p id='waterSum_"+i+""+(j+1)+"' name='p1$' class='cover_through cover js-click-to-alert'>SK测试</p>";
     77                             var ileft = $('#waterSum_'+i+''+j).css("margin-left").substring(0,$('#waterSum_'+i+''+j).css("margin-left").indexOf('p'));
     78                             var itop = $('#waterSum_11').css("margin-top").substring(0,$('#waterSum_11').css("margin-top").indexOf('p'));
     79                             $("body").append(p);
     80                             $('#waterSum_'+i+''+(j+1)).css("margin-left",Number(ileft)+Number(perWidth)+perSpace);
     81                             $('#waterSum_'+i+''+(j+1)).css('margin-top',itop);
     82                         }
     83                     }else{
     84                         var p = "<p id='waterSum_"+i+""+j+"' name='p1$' class='cover_through cover js-click-to-alert'>${TmpContent}</p>";
     85                         var ileft = $('#waterSum_'+(i-1)+''+j).css("margin-left").substring(0,$('#waterSum_'+(i-1)+''+j).css("margin-left").indexOf('p'));
     86                         var itop =  $('#waterSum_'+(i-1)+''+j).css("margin-top").substring(0,$('#waterSum_'+(i-1)+''+j).css("margin-top").indexOf('p'));
     87                         $("body").append(p);
     88                         $('#waterSum_'+i+''+j).css("margin-left",Number(ileft));
     89                         $('#waterSum_'+i+''+j).css('margin-top',Number(itop)+Number(perHeight));
     90                     }
     91                 }
     92             }
     93             passThrough();
     94         }else{
     95             waterMarkNotIe$();
     96         }
     97     }
     98     function waterMarkNotIe$(){
     99         var winwidth$ = document.body.clientWidth;
    100         var winheight$ = document.body.scrollHeight;
    101         var waterSum$ = 100;
    102         var oldleft$=0;
    103         var maxI$=0;
    104         var k$=0;
    105         $("body").append("<div class='cover-Blink-area'> </div>");
    106         $('.cover-Blink-area').css('height','500px');
    107         for( var i=1;i<=waterSum$;i++) {
    108             $(".cover-Blink-area").append("<p id='waterSum_" +i+"' class='cover_through cover-Blink js-click-to-alert'>SK测试</p>");
    109             var left = Number(document.getElementById("waterSum_" +i).offsetLeft);
    110             if(left>oldleft$) {
    111                 oldleft$ = left;
    112                 maxI$ = i;
    113             }
    114             if (left<oldleft$&&k$==0){
    115                 var top = $("#waterSum_1").css("margin-top").substring(0,$("#waterSum_1").css("margin-top").indexOf('p'));
    116                 var bottom = $("#waterSum_1").css("margin-bottom").substring(0,$("#waterSum_1").css("margin-bottom").indexOf('p'));
    117                 var pHeight = $("#waterSum_1").height();
    118                 var totalHeight = Number(top)+Number(pHeight)+Number(bottom);
    119                 var Hnum = Math.round(500/(totalHeight/1.3));
    120                 waterSum$ = Hnum*maxI$;
    121                 k$++;
    122             }
    123         }
    124     }
    125     window.onresize = function(){
    126         waterMark$();
    127     }
    128     function passThrough() {
    129         $(".cover").mouseenter(function(){
    130             $(this).stop(true).fadeOut().delay(1500).fadeIn(50);
    131         });
    132     }
    133 </script>

    图片添加水印:http://www.16xx8.com/photoshop/jiaocheng/2019/148476.html

    HTML页面添加水印:https://blog.csdn.net/zhanglu1236789/article/details/79105442

    前端水印生成方案:https://cloud.tencent.com/developer/article/1158636

    html页面添加水印

  • 相关阅读:
    vuejs2从入门到精通视频教程
    vuejs2项目开发实战视频教程
    vuejs2从入门到精通视频教程
    Bootstrap视频教程
    开通博卡拉
    阿里云Ubuntu 16 FTP安装配置注意事项
    [解决方法] Java-Class.forName() 反射/映射子类 并转化为父类/接口
    [HTML/CSS] ul元素居中处理
    [HTML/Javascript] JS判断IE浏览器各版本
    [HTML/JS] JQuery 页面滚动回到顶部
  • 原文地址:https://www.cnblogs.com/scriptchild/p/11896334.html
Copyright © 2011-2022 走看看