给图片添加水印

首选为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:\Windows\Fonts\STXINGKA.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;          width: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;          width: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\0;
 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页面添加水印

posted @ 2019-11-20 11:01  脚本小孩  阅读(820)  评论(0编辑  收藏  举报