You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
4.7 KiB
124 lines
4.7 KiB
const sharp = require('sharp');
|
|
|
|
class ImageProcessor {
|
|
/**
|
|
* 为图片添加文字水印
|
|
* @param {Buffer} imageBuffer - 原始图片的Buffer数据
|
|
* @param {String} text - 水印文字内容
|
|
* @param {Object} options - 水印配置选项
|
|
* @returns {Promise<Buffer>} - 添加水印后的图片Buffer
|
|
*/
|
|
static async addWatermark(imageBuffer, text = '又鸟蛋平台', options = {}) {
|
|
try {
|
|
console.log('【图片处理】开始添加水印');
|
|
|
|
// 设置默认配置
|
|
const defaultOptions = {
|
|
fontSize: 20, // 字体大小 - 减小以确保完整显示
|
|
color: 'rgba(0,0,0,0.5)', // 文字颜色(加深以便更清晰)
|
|
position: 'bottom-right', // 水印位置
|
|
marginX: -50, // X轴边距 - 调整使水印居中在红色框中
|
|
marginY: 10 // Y轴边距 - 减小使水印靠下,放入红色框中
|
|
};
|
|
|
|
// 强制使用'bottom-right'位置
|
|
options.position = 'bottom-right';
|
|
|
|
const config = { ...defaultOptions, ...options };
|
|
|
|
// 使用sharp处理图片
|
|
const image = sharp(imageBuffer);
|
|
|
|
// 获取图片信息以确定水印位置
|
|
const metadata = await image.metadata();
|
|
const width = metadata.width || 800;
|
|
const height = metadata.height || 600;
|
|
|
|
// 确定水印位置
|
|
let x = config.marginX;
|
|
let y = config.marginY;
|
|
|
|
if (config.position === 'bottom-right') {
|
|
// 右下角位置,需要计算文字宽度(这里简化处理,实际应该根据字体计算)
|
|
// 这里使用一个简单的估算:每个字符约占字体大小的0.6倍宽度
|
|
const estimatedTextWidth = text.length * config.fontSize * 0.6;
|
|
x = width - estimatedTextWidth - config.marginX;
|
|
y = height - config.fontSize - config.marginY;
|
|
} else if (config.position === 'center') {
|
|
x = (width / 2) - (text.length * config.fontSize * 0.3);
|
|
y = height / 2;
|
|
} else if (config.position === 'top-left') {
|
|
// 左上角,使用默认的margin值
|
|
}
|
|
|
|
// 确保位置不会超出图片边界
|
|
x = Math.max(0, Math.min(x, width - 1));
|
|
y = Math.max(config.fontSize, Math.min(y, height - 1));
|
|
|
|
// 添加文字水印
|
|
const watermarkedBuffer = await image
|
|
.composite([{
|
|
input: Buffer.from(`<svg width="${width}" height="${height}">
|
|
<text x="${x}" y="${y}" font-family="Arial" font-size="${config.fontSize}" fill="${config.color}">${text}</text>
|
|
</svg>`),
|
|
gravity: 'southeast'
|
|
}])
|
|
.toBuffer();
|
|
|
|
console.log('【图片处理】水印添加成功');
|
|
return watermarkedBuffer;
|
|
} catch (error) {
|
|
console.error('【图片处理】添加水印失败:', error.message);
|
|
console.error('【图片处理】错误详情:', error);
|
|
// 如果水印添加失败,返回原始图片
|
|
return imageBuffer;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 批量为图片添加水印
|
|
* @param {Array<Buffer>} imageBuffers - 图片Buffer数组
|
|
* @param {String} text - 水印文字内容
|
|
* @param {Object} options - 水印配置选项
|
|
* @returns {Promise<Array<Buffer>>} - 添加水印后的图片Buffer数组
|
|
*/
|
|
static async addWatermarkToMultiple(imageBuffers, text = '又鸟蛋平台', options = {}) {
|
|
try {
|
|
console.log(`【图片处理】开始批量添加水印,共${imageBuffers.length}张图片`);
|
|
|
|
const watermarkedPromises = imageBuffers.map(buffer =>
|
|
this.addWatermark(buffer, text, options)
|
|
);
|
|
|
|
const results = await Promise.all(watermarkedPromises);
|
|
console.log('【图片处理】批量水印添加完成');
|
|
return results;
|
|
} catch (error) {
|
|
console.error('【图片处理】批量添加水印失败:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 为Base64编码的图片添加水印
|
|
* @param {String} base64Image - Base64编码的图片
|
|
* @param {String} text - 水印文字内容
|
|
* @param {Object} options - 水印配置选项
|
|
* @returns {Promise<Buffer>} - 添加水印后的图片Buffer
|
|
*/
|
|
static async addWatermarkToBase64(base64Image, text = '又鸟蛋平台', options = {}) {
|
|
try {
|
|
// 移除Base64前缀
|
|
const base64Data = base64Image.replace(/^data:image\/(png|jpeg|jpg|gif);base64,/, '');
|
|
// 转换为Buffer
|
|
const buffer = Buffer.from(base64Data, 'base64');
|
|
// 添加水印
|
|
return await this.addWatermark(buffer, text, options);
|
|
} catch (error) {
|
|
console.error('【图片处理】为Base64图片添加水印失败:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = ImageProcessor;
|
|
|