说在前面
加水印是为了保护图片的版权和安全。在互联网上,很容易将图片下载或者截屏保存下来,然后进行二次使用,这就侵犯了原作者的版权。而加上水印可以使得图片更难被盗用,因为盗用者需要花费时间和精力去处理水印,而这个过程可能会破坏原始图片的质量。
此外,水印也可以帮助识别图片的来源和所有者。如果一张图片被恶意使用或者未经授权的使用,通过水印可以追踪到图片的来源和版权所有人,从而维护原作者的权益。
因此,加水印对于保护图片的版权和安全具有重要意义。
代码实现
1、依赖引入
(1)@jyeontu/j-inquirer
@jyeontu/j-inquirer
是一个 Node.js 的命令行交互模块,它可以方便地创建一个交互式命令行界面,用于与用户进行交互。它提供了多种常见的输入方式,如单选、多选、输入框、文件选择、目录选择等等,并且可以自定义提示信息、选项等。
(2)@jyeontu/progress-bar
@jyeontu/progress-bar
是一个 Node.js 的进度条模块,它可以在命令行中展示一个进度条,用于显示正在进行的操作的进度。它支持多种样式和配置选项,可以根据需要调整进度条的样式、长度、颜色等等。
(3)fs
fs
是 Node.js 内置的文件系统模块,它提供了多种操作文件和目录的方法,如读取文件、写入文件、创建目录、删除文件等等。在 Node.js 中,我们可以使用 fs
模块来读取和处理本地的文件。
(4)jimp
jimp
是一个纯 JavaScript 的图像处理库,它可以用于处理各种类型的图片,如 PNG、JPEG、BMP 等等。它提供了多种图像处理方法,如调整大小、裁剪、旋转、添加水印等等,可以轻松地实现各种图像处理需求。在 Node.js 中,我们可以使用 jimp
来读取和处理本地的图片文件。
2、命令行交互获取处理参数
const textWaterMarkOptions = [
{
type: "folder",
message: "请选择需要添加水印的图片目录",
name: "inputFolder",
default: "",
dirname: baseDir,
},
{
type: "input",
message: "请输入水印文字",
name: "watermarkText",
default: "",
},
{
type: "list",
message: "请选择水印位置",
name: "watermarkPos",
default: "center",
choices: [
"上左",
"上中",
"上右",
"中左",
"正中",
"中右",
"下左",
"下中",
"下右",
],
},
];
async function ask(options) {
const answers = await new inquirer(options).prompt();
return answers;
}
async function textWaterMark(inputFolder, outputFolder) {
const { watermarkText, watermarkPos } = await ask(textWaterMarkOptions);
…………
}
获取用户需要添加水印的目录、水印文字内容及水印添加位置。
3、图片添加水印
(1)获取目录下的所有图片
const IMG_TYPE = ["jpg", "png", "jpeg"];
function checkImgType(file) {
const tmp = file.split(".");
return IMG_TYPE.includes(tmp[tmp.length - 1].toLocaleLowerCase());
}
const imageFiles = fs
.readdirSync(inputFolder)
.filter((file) => checkImgType(file));
目前支持处理”jpg”, “png”, “jpeg”类型的图片文件,获取指定目录下的符合类型的所有图片文件。
(2)水印位置计算
function getPosition(img, waterMark, pos) {
const imageWidth = img.width;
const imageHeight = img.height;
const watermarkWidth = waterMark.width;
const watermarkHeight = waterMark.height;
let x = (imageWidth - watermarkWidth) / 2; // 水印横坐标
let y = (imageHeight - watermarkHeight) / 2; // 水印纵坐标
switch (pos) {
case "上左":
x = 10; // 水印横坐标
y = 10; // 水印纵坐标
break;
case "上中":
x = (imageWidth - watermarkWidth) / 2; // 水印横坐标
y = 10; // 水印纵坐标
break;
case "上右":
x = imageWidth - watermarkWidth - 20; // 水印横坐标
y = 10; // 水印纵坐标
break;
case "中左":
x = 10; // 水印横坐标
y = (imageHeight - watermarkHeight) / 2; // 水印纵坐标
break;
case "正中":
x = (imageWidth - watermarkWidth) / 2; // 水印横坐标
y = (imageHeight - watermarkHeight) / 2; // 水印纵坐标
break;
case "中右":
x = imageWidth - watermarkWidth - 20; // 水印横坐标
y = (imageHeight - watermarkHeight) / 2; // 水印纵坐标
break;
case "下左":
x = 10; // 水印横坐标
y = imageHeight - watermarkHeight - 20; // 水印纵坐标
break;
case "下中":
x = (imageWidth - watermarkWidth) / 2; // 水印横坐标
y = imageHeight - watermarkHeight - 20; // 水印纵坐标
break;
case "下右":
x = imageWidth - watermarkWidth - 20; // 水印横坐标
y = imageHeight - watermarkHeight - 20; // 水印纵坐标
break;
}
return {
x,
y,
};
}
(3)添加文字水印
使用 jimp
模块读取输入图片,根据水印文字和位置参数创建水印图层,并与原始图片进行合成,最后保存处理后的图片到输出路径。具体说明已在下面代码中注释。
async function addWaterMark(
inputFilePath,
outputFilePath,
watermarkText,
watermarkPos,
textconfig = {}
) {
//接收五个参数:`inputFilePath`(输入图片文件路径)、`outputFilePath`(输出图片文件路径)、`watermarkText`(水印文字内容)、`watermarkPos`(水印位置)、`textconfig`(文本配置,可选)。
textOptions.text = watermarkText;
for (const k in textconfig) {
textOptions[k] = textconfig[k];
}
// 使用 `Jimp.read` 方法读取输入图片文件,并使用 `Jimp.loadFont` 方法加载字体文件
const image = await Jimp.read(inputFilePath);
const font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE);
// 获取输入图片和水印的宽度和高度,使用 `Jimp.measureText` 方法测量水印文字的宽度,使用 `Jimp.measureTextHeight` 方法测量水印文字的高度。
const imageWidth = image.getWidth();
const imageHeight = image.getHeight();
const watermarkWidth = Jimp.measureText(font, watermarkText);
const watermarkHeight = Jimp.measureTextHeight(
font,
watermarkText,
watermarkWidth
);
// 调用 `getPosition` 函数计算水印放置的位置,根据输入图片和水印的尺寸以及水印位置参数 `watermarkPos`。
const { x, y } = getPosition(
{
height: imageHeight,
width: imageWidth,
},
{ height: watermarkHeight, width: watermarkWidth },
watermarkPos
);
// 创建一个新的 `Jimp` 对象作为背景图层,宽度为水印宽度加上 20 像素,高度为水印高度加上 20 像素,并设置背景颜色为半透明黑色(0x00000030)
const background = new Jimp(
watermarkWidth + 20,
watermarkHeight + 20,
0x00000030
); // 0x00000080 表示半透明黑色背景
// 将水印文字打印到背景图层上,使用指定的字体、起始坐标(10, 10)、文本配置 `textOptions`,并指定水印文字的宽度和高度。
background.print(font, 10, 10, textOptions, watermarkWidth, watermarkHeight);
// 将背景图层与原始图片进行合成,使用指定的合成模式 `Jimp.BLEND_SOURCE_OVER`。
image.composite(background, x, y, { mode: Jimp.BLEND_SOURCE_OVER });
// 将处理后的图片保存到输出图片文件路径 `outputFilePath`。
await image.writeAsync(outputFilePath);
}
插件体验
安装
npm install -g jyeontu
使用
jyeontu img
按交互提示进行选择操作即可。
源码
gitee
公众号
关注公众号『前端也能这么有趣
』,发送jyeontu
获取源码。
获取更多有趣内容
关注公众号『前端也能这么有趣
』,获取更多有趣内容。
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。
原文链接:https://juejin.cn/post/7314860085930197007 作者:JYeontu