一、总结

一句话总结:

 

1、如何从根本上美化上传控件框(替代思想)?

解答:隐藏上传控件,并加了一个新的按钮在它前面用选择器来触发这个上传控件。

2、通过隐藏上传控件,并加了一个新的按钮在它前面用选择器来触发这个上传控件的方法,怎么拿到上传的文件?

解答:通过event对象,var imgFile = event.target.files[0]; dom中有event,jquery中也有

选择文件后,文件上传控件会触发change事件,此时可以拿到文件。

 



$('#target_file').change(function (event) {
var imgFile = event.target.files[0];
......
});


3、文件转化为图片的方法?

解答:文件转换为图片实际上首先需要读取文件,这里需要用到FileReader。通过FileReaderreadAsDataURL函数读取文件可以获得Base64格式的图片数据,将图片数据赋值给一个Image对象。

4、怎么在图片上加水印?

解答:用canvas来给图片加水印。先将图片用drawImage渲染进canvas,再在指定的位置用fillText渲染文字即可,并将最后的canvas用toDataURL转化为图片数据即可。

5、拖动文字加水印的方法?

解答:在span元素上加drag事件。

当我们设置水印时,直接将文字渲染到canvas上,然后在文字上方安放一个颜色透明的内容为水印文字的span元素。

然后我们在这个span元素上加drag事件。

HTML5拖动功能网上一大堆,这里就不讲了。

6、拖动文字或者图片或者文件用的什么事件?

解答:用的drag事件。

7、因为博客园自动屏蔽了canvas标签和download属性,所以怎么实现在博客里面插入canvas标签和download属性?

解答:可以动态通过js插入。download属性:可以把download属性对应的标签一起插入进去。



 var initHtmlConstruct = function () {
$('#canvas-container').text('').append('<canvas id="target_canvas" width="100" height="100">浏览器不支持此功能,请升级</canvas><span draggable="true" id="watermark"></span>')
$('#toolbar').append('<a id="download_file" href="#" download="水印图片">下载合成图片</a>');
}


8、jquery中动态插入一个元素用的方法是什么?

解答:$().append()。 $('#toolbar').append('<a id="download_file" href="#" download="水印图片">下载合成图片</a>');

 

 

 

二、前言


想给自己的一些图片加上水印,于是就捣腾了这么个东西。


此功能没有考虑兼容性(太懒了),只在Chrome下测试通过,如果您在什么IE火狐下测试不通过就不要吐槽了。


因为应用了download属性,所以IE什么的就不用指望了,如果您是火狐浏览器的话,自己改一下兼容性应该是没问题的。


代码什么的开了F12自己拿吧,没有压缩哦。(最后吐槽一下,本来代码是贴进博客里面的,保存为草稿预览的时候也可以,结果在发布后js代码全被屏蔽了,最后只能写到页脚里了。所以获取js代码到页脚那里获取就好了)


当然你也可以访问下面这个github地址获取代码:​​代码地址​​。

 特意把代码从ES2015改成了ES5,所以多多少少有点乱,不过必要的注释都加上去了,这么辛苦,点个赞啊。


至于要改水印样式什么的,控制台里更改这个变量的属性即可。



var watermarkInfo = {
  fontSize: 18, // 像素值
  fontFamily: 'cursive',
  content: '',
  color: '#fffbf0'
};


 废话就不多说了,直接上作品。


选择背景图后,设置水印文字,然后拖动水印文字到任意位置,最后点击下载文件按钮即可。



选择背景图 设置水印


 


三、实现过程中的问题与解决方案

代码什么的就不全部贴上来了,只是讲一下其中遇到的一些问题与实现思路。

这些问题您可能已经大多了解了,不过为了兼顾所有人,所以还是会将一些比较简单的技术点也讲一下。

整个实现过程中遇到的问题如下

  • 获取图片
  • 将上传文件转换为图片
  • 在图片上加水印
  • 拖动文字加水印
  • 将最后修改的图片下载下来

四、获取图片

获取图片实际上就是用到文件上传控件,也就是




<input id="target_file" type="file"/>


然而原始的文件上传控件比较丑,所以隐藏此控件,并加了一个新的按钮在它前面



<a class="btn" id="btn_select_file" href="jacascript:void(0)">选择背景图</a>
<input id="target_file" type="file" style="display:none" />


而想实现点击选择背景图按钮去选择文件,用以下代码即可



// 按下选择的背景图
$('#btn_select_file').click(function () {
$('#target_file').click();
});


选择文件后,文件上传控件会触发change事件,此时可以拿到文件。




$('#target_file').change(function (event) {
var imgFile = event.target.files[0];
......
});


五、将文件转换为图片

文件转换为图片实际上首先需要读取文件,这里需要用到FileReader。



function setImgIntoCanvas(imgFile) {
  var reader = new FileReader();

  reader.onloadend = function (e) {
    var dataURL = e.target.result;
    img.onload = function (event) {
      var ctx = document.getElementById('target_canvas').getContext('2d');
      //将canvas大小设置为和图片一样大
      setCanvasSize(event.target.naturalWidth, event.target.naturalHeight);
      ctx.drawImage(img, 0, 0);
      setCanvasImgToDownloadLink();
    };
    img.src = dataURL;
  };
reader.readAsDataURL(imgFile);
resetWatermark();
};


 

以上为核心代码,通过FileReaderreadAsDataURL函数读取文件可以获得Base64格式的图片数据,将图片数据赋值给一个Image对象。

六、在图片上加水印


看了上面的代码,里面就有一个步骤是将图片渲染进canvas,实际上核心功能就是用canvas来给图片加水印。


操作思路就是先将图片用drawImage渲染进canvas,再在指定的位置用fillText渲染文字即可,并将最后的canvas用

toDataURL

转化为图片数据即可。

具体的用法可以参考我的代码,然后查一下canvas的API即可。


这种在新手看来很难的东西说穿了其实很简单,这里就不讲了。


 


但是接下来就麻烦了,如果是白色水印,图片上加水印的地方肯定不能和图片色差太小,要不然很难发现。


所以针对不同的图片,水印的位置肯定需要可调整。


最开始的方案是给定两个输入框,然后输入位置,接着渲染水印到文本上。


但是这个方案首先就面临一个易用性的问题,我怎么获得具体的位置呢,只能一个一个去试,并不是每个用户都会用截图软件去找位置。


所以这里采用拖动文字的方案。



七、拖动文字加水印

canvas虽然也能捕获事件,获取鼠标位置,并实现拖动文字效果,但是实现起来太麻烦。

所以这里采用更简单的方案。

当我们设置水印时,直接将文字渲染到canvas上,然后在文字上方安放一个颜色透明的内容为水印文字的span元素。

然后我们在这个span元素上加drag事件。

HTML5拖动功能网上一大堆,这里就不讲了。

主要讲一下实现思路:

在开始拖动时,重新用图片渲染canvas,使得之前渲染的文字消失。

在结束拖动时,获取到具体的位置,再重新将文字渲染进canvas。

这里说起来简单,其实还是有一些细节,包括css和js的配合,比如文字拖动到边界时的处理方式,又比如文字拖动到边界出现换行的情况。

还有一些其他的小坑点,需要你自己看代码去体会了。

这里贴出部分代码:



// 绑定移动水印相关事件
     var bindEvent4DragWatermark = function () {
$('#watermark').on('dragstart', function (e) {
var ctx = document.getElementById('target_canvas').getContext('2d');
ctx.clearRect(0, 0, $('#target_canvas').width(), $('#target_canvas').height());
ctx.drawImage(img, 0, 0);
// 显示可拖拽水印
$(this).addClass('selected');
watermarkInfo.offsetX = e.originalEvent.offsetX + canvasInfo.left;
watermarkInfo.offsetY = e.originalEvent.offsetY + canvasInfo.top;
});
// 让水印跟着鼠标移动
$('#watermark').on('drag', function (e) {
var x = e.originalEvent.pageX;
var y = e.originalEvent.pageY;
if (x === 0 && y === 0) {
return;
}
x -= watermarkInfo.offsetX;
y -= watermarkInfo.offsetY;

$('#watermark').css('left', x).css('top', y);
});
$('#watermark').on('dragend', function (e) {
// 调整位置,使水印无法超出canvas边界
var x = e.originalEvent.pageX - watermarkInfo.offsetX;
var y = e.originalEvent.pageY - watermarkInfo.offsetY;
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}

var maxX = canvasInfo.width - watermarkInfo.width;
var maxY = canvasInfo.height - watermarkInfo.height;
if (x > maxX) {
x = maxX;
}
if (y > maxY) {
y = maxY;
}
$('#watermark').css('left', x).css('top', y);
// 拖拽完水印,文本隐藏
$('#watermark').removeClass('selected');
setTextIntoCanvas();
});
// 让鼠标不显示禁用样式
$('#canvas-container').on('dragover', function (e) {
e.preventDefault();
});
}


八、将最后修改的图片下载下来

之前我们已经讲到了用canvas的toDataURL函数获取最后的图片数据,然后关于下载就需要用到一个HTML5的download属性。




<a class="btn" id="download_file" href="#" download="水印图片">下载合成图片</a>


接下来是设置图片数据的代码



/**
* 设置canvas图像到下载链接上
*/
function setCanvasImgToDownloadLink() {
var imgData = document.getElementById('target_canvas').toDataURL();
$('#download_file').attr('href', imgData);
};


九、将功能写进博客里

至于这部分首先要申请JS权限。

其次如果观察仔细,还可以在我的代码中看到下列代码



 var initHtmlConstruct = function () {
$('#canvas-container').text('').append('<canvas id="target_canvas" width="100" height="100">浏览器不支持此功能,请升级</canvas><span draggable="true" id="watermark"></span>')
$('#toolbar').append('<a id="download_file" href="#" download="水印图片">下载合成图片</a>');
}


十、总结

总的来说,这其实是一个很小的功能,但是要把它做得好用一点,涉及到的知识点并不少,也不并不仅仅我提到的这一点(比如canvas的透明度样式并不是用图片哦,而是用css样式,还是从《css揭秘》那本书上学到的)。

当然这个东西或多或少还是有那么一些瑕疵,也存在一些兼容性上的问题,不过对我而言够用就好。

也希望上面介绍的一些东西对您也有收获。


 

十一、测试题-简答题

1、如何从根本上美化上传控件框(替代思想)?

解答:隐藏上传控件,并加了一个新的按钮在它前面用选择器来触发这个上传控件。

2、通过隐藏上传控件,并加了一个新的按钮在它前面用选择器来触发这个上传控件的方法,怎么拿到上传的文件?

解答:通过event对象,var imgFile = event.target.files[0]; dom中有event,jquery中也有

选择文件后,文件上传控件会触发change事件,此时可以拿到文件。

 



$('#target_file').change(function (event) {
var imgFile = event.target.files[0];
......
});


3、文件转化为图片的方法?

解答:文件转换为图片实际上首先需要读取文件,这里需要用到FileReader。通过FileReaderreadAsDataURL函数读取文件可以获得Base64格式的图片数据,将图片数据赋值给一个Image对象。

4、怎么在图片上加水印?

解答:用canvas来给图片加水印。先将图片用drawImage渲染进canvas,再在指定的位置用fillText渲染文字即可,并将最后的canvas用toDataURL转化为图片数据即可。

5、拖动文字加水印的方法?

解答:在span元素上加drag事件。

当我们设置水印时,直接将文字渲染到canvas上,然后在文字上方安放一个颜色透明的内容为水印文字的span元素。

然后我们在这个span元素上加drag事件。

HTML5拖动功能网上一大堆,这里就不讲了。

6、拖动文字或者图片或者文件用的什么事件?

解答:用的drag事件。

7、因为博客园自动屏蔽了canvas标签和download属性,所以怎么实现在博客里面插入canvas标签和download属性?

解答:可以动态通过js插入。download属性:可以把download属性对应的标签一起插入进去。



 var initHtmlConstruct = function () {
$('#canvas-container').text('').append('<canvas id="target_canvas" width="100" height="100">浏览器不支持此功能,请升级</canvas><span draggable="true" id="watermark"></span>')
$('#toolbar').append('<a class="btn" id="download_file" href="#" download="水印图片">下载合成图片</a>');
}


8、jquery中动态插入一个元素用的方法是什么?

解答:$().append()。 $('#toolbar').append('<a id="download_file" href="#" download="水印图片">下载合成图片</a>');