/ 昌里大金猪的空间 / Watermark.js for NodeJS

Watermark.js for NodeJS

2011-06-22 posted in [node]

感谢LearnBoost团队对node-canvas的研究以及Patrick Wiedwatermark.js project,我在两者基础上进行整合并尝试将watermark.js移植到NodeJS下,借此实现给指定目录下的所有图片打上水印。简单说下技术要点和实现原理。

如何制作水印?


根据Patrick Wied watermark.js的指导,可简单分为三个步骤。

第一步,把水印图片画到canvas上。由于在NodeJS中运行,于是对其稍作修改:

  1. // 获取img元素对象,并设置srcPath  
  2. var img = new Image;  
  3. img.src = srcPath; 

  4. // 创建canvas元素对象  
  5. canvas = new Canvas; 

  6. // 获取canvas上下文  
  7. ctx = canvas.getContext("2d"); 

  8. // 设置canvas元素宽高,一般来说与img元素尺寸相同即可  
  9. canvas.width = img.width;  
  10. canvas.height = img.height; 

  11. // 在canvas中描绘img元素  
  12. ctx.drawImage(img, 0, 0);

srcPath可以是一段url、绝对路径或者相对路径,关于path详细参考Node.js Manual

第二步,修改水印图片的透明度:

  1. // 获取imageData对象  
  2. var image = ctx.getImageData(0, 0, 500, 200); 

  3. // 获取imageData对象值  
  4. var imageData = image.data, length = imageData.length; 

  5. // imageData中一个像素包含四个值,分别是R/G/B和alpha(rgba),故此处循环时每隔4改变一次imageData对应的alpha值(0 <= alpha <= 255)  
  6. for (var i = 3; i < length; i += 4) {  
  7.     imageData[i] = 50;  


  8. // 重置数据  
  9. image.data = imageData; 

  10. // 将其重新置于canvas中  
  11. ctx.putImageData(image, 0, 0);

第三步,给图片设置转化后的dataUrl:img.src = canvas.toDataURL();,以此获得调整过的img对象。

  1. img.src = canvas.toDataURL();
  2. ctx.drawImage(img, 0, 0);
  3. ctx.drawImage(originImage, x, y);

把两张图片画在canvas不同的位置,最终实现了打水印。

TODO:watermarkImage.src = canvas.toDataURL();这段代码将toDataURL转换后的base64值作为src赋给watermarkImage,在NodeJS下并不会触发image元素的onload事件(即加载失败),但在浏览器环境下却能正常加载。最终导致在NodeJS环境下无法打出具有一定透明度的水印。

如何保存打过水印的新图片?

这个问题很简单,node-canvas提供了createSyncPNGStream接口,该接口扩展自Stream,用来保存PNG流:

  1. var out = fs.createWriteStream(imagePath + '.watermark.png'),   
  2.     stream = canvas.createSyncPNGStream();  
  3. stream.on('data'function(chunk){out.write(chunk);});  
  4. stream.on('end'function(){out.end();}); 

实际效果如图所示:
Watermark.js for NodeJS - 昌里大金猪 - Nomospace

注意此处都是png格式的图片,调试过程中得知node-canvas目前只支持png格式文件的读取、写入,在源代码中也有这么一段:

  1. // Canvas.prototype.toDataURL
  2. // Throw on non-png  
  3. if ('image/png' != type) throw new Error('currently only image/png is supported');

有兴趣的读者可以参考watermark for NodeJS@github,细节部分不再赘述。


参考资料
Introducing node-canvas. Server side HTML5 canvas API
Canvas - Dive Into HTML5
Canvas tutorial