1. 上传时加水印
  • 用户上传原始图片 => 服务器保留原始图片以及水印图片
  1. 动态水印
  • 用户上传原始图片 => 服务器只保留原始图片,
  • 请求图片的时候,服务器动态添加水印

插件:jimp

官网:https://github.com/oliver-moran/jimp/tree/master/packages/jimp

安装jimp

npm i jimp@0.10.3

封装添加水印的方法

  1. // 给一张图片加水印
  2. async function mark(
  3. waterFile,
  4. originFile,
  5. targetFile,
  6. proportion = 5,
  7. marginProportion = 0.01
  8. ) {
  9. const [water, origin] = await Promise.all([
  10. jimp.read(waterFile),
  11. jimp.read(originFile),
  12. ]);
  13. // 对水印图片进行缩放
  14. const curProportion = origin.bitmap.width / water.bitmap.width;
  15. water.scale(curProportion / proportion);
  16. // 计算位置
  17. const right = origin.bitmap.width * marginProportion;
  18. const bottom = origin.bitmap.height * marginProportion;
  19. const x = origin.bitmap.width - right - water.bitmap.width;
  20. const y = origin.bitmap.height - bottom - water.bitmap.height;
  21. // 写入水印
  22. origin.composite(water, x, y, {
  23. mode: jimp.BLEND_SOURCE_OVER,
  24. opacitySource: 0.3,
  25. });
  26. await origin.write(targetFile);
  27. }
  1. 参数
  • waterFile : 水印图片的地址
  • originFile: 源图片的地址,
  • targetFile: 添加好图片以后,图片存放的地址
  • proportion: 比例,原始图片的宽度/水印图片的宽度
  • marginProportion: 水印图片距离边框的距离,是一个比例,原始图片宽度和高度的比例
  1. 对水印图片进行缩放
    1. // 对水印图片进行缩放
    2. const curProportion = origin.bitmap.width / water.bitmap.width;
    3. water.scale(curProportion / proportion);
    image.png
  • 位图: origin.bitmap 一个一个的像素点
  1. 计算图片水印的位置

    1. // 计算位置
    2. const right = origin.bitmap.width * marginProportion;
    3. const bottom = origin.bitmap.height * marginProportion;
    4. const x = origin.bitmap.width - right - water.bitmap.width;
    5. const y = origin.bitmap.height - bottom - water.bitmap.height;
  2. 写入水印

    1. origin.composite(water, x, y, {
    2. mode: jimp.BLEND_SOURCE_OVER,
    3. opacitySource: 0.3,
    4. });
    5. await origin.write(targetFile);

使用水印方法

在图片上传的时候,调用水印方法,可以利用缩放water.scale(比例),做成不同尺寸(大小)的图片

  1. const express = require('express');
  2. const router = express.Router();
  3. const multer = require('multer');
  4. const path = require('path');
  5. const jimp = require('jimp');
  6. // 给一张图片加水印
  7. async function mark(
  8. waterFile,
  9. originFile,
  10. targetFile,
  11. proportion = 5,
  12. marginProportion = 0.01
  13. ) {
  14. const [water, origin] = await Promise.all([
  15. jimp.read(waterFile),
  16. jimp.read(originFile),
  17. ]);
  18. // 对水印图片进行缩放
  19. const curProportion = origin.bitmap.width / water.bitmap.width;
  20. water.scale(curProportion / proportion);
  21. // 计算位置
  22. const right = origin.bitmap.width * marginProportion;
  23. const bottom = origin.bitmap.height * marginProportion;
  24. const x = origin.bitmap.width - right - water.bitmap.width;
  25. const y = origin.bitmap.height - bottom - water.bitmap.height;
  26. // 写入水印
  27. origin.composite(water, x, y, {
  28. mode: jimp.BLEND_SOURCE_OVER,
  29. opacitySource: 0.3,
  30. });
  31. await origin.write(targetFile);
  32. }
  33. const storage = multer.diskStorage({
  34. destination: function (req, file, cb) {
  35. cb(null, path.resolve(__dirname, '../../public/upload'))
  36. },
  37. filename: function (req, file, cb) {
  38. // 时间戳 - 6位随机字符.文件后缀
  39. const timeStamp = Date.now();
  40. const ramdomStr = Math.random().toString(36).slice(-6);
  41. const ext = path.extname(file.originalname);
  42. const filename = `${timeStamp}-${ramdomStr}${ext}`;
  43. cb(null, filename);
  44. }
  45. })
  46. const upload = multer({
  47. storage,
  48. limits: {
  49. fileSize: 1024 * 2014 * 10
  50. },
  51. fileFilter(req, file, cb) {
  52. // 文件名
  53. const extname = path.extname(file.originalname);
  54. const whiteList = ['.jpg', '.gif', '.png', '.jpeg'];
  55. if (whiteList.includes(extname)) {
  56. cb(null, true);
  57. } else {
  58. cb(new Error(`you ext name of ${extname} is not support`));
  59. }
  60. }
  61. });
  62. const waterImg = path.resolve(__dirname, '../../public/img/sy.jpeg')
  63. router.post('/', upload.single('avatar'), function (req, res, next) {
  64. const url = `http://localhost:12306/upload/${req.file.filename}`;
  65. const targetPath = path.resolve(__dirname, `../../public/upload/sy_${req.file.filename}`);
  66. mark(waterImg, req.file.path, targetPath)
  67. res.send({
  68. success: true,
  69. uid: "0",
  70. name: "IMG.png",
  71. state: "done",
  72. url: url,
  73. downloadURL: url,
  74. imgURL: url,
  75. size: 2000
  76. })
  77. })
  78. module.exports = router;

这里在同一个文件夹下面,添加了一个增加前缀sy_的同名图片