feat: ppt转图片

main
lichaojun 1 year ago
parent 6b209f3209
commit ee14c77205

@ -35,6 +35,18 @@ const config = {
pptFormat: new Set(['ppt', 'pptx']), pptFormat: new Set(['ppt', 'pptx']),
pdfFormat: new Set(['pdf']), pdfFormat: new Set(['pdf']),
}, },
merge: {
// 每行图片的个数
row: 3,
//画布背景颜色
bgColor: 'rgb(211, 211, 211)',
//画布宽度
width: 1000,
//画布外边距
margin: 3,
//图片间距
padding: 3,
},
}; };
module.exports = config; module.exports = config;

@ -6,7 +6,8 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"cover": "node ./src/product_cover_img.js", "cover": "node ./src/product_cover_img.js",
"ppt": "node ./src/ppt_to_img.js" "ppt": "node ./src/ppt_to_img.js",
"merge": "node ./src/img_merge.js"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",

@ -1,33 +1,31 @@
const imagePaths = [
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_0.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_1.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_2.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_3.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_4.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_5.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_6.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_7.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_8.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_9.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_10.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_11.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_12.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_13.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_14.png',
'C:/Users/Administrator/Desktop/test/ppt1001/img/01/slide_15.png',
];
const sharp = require('sharp'); const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
const { getInputDir } = require('../utils/index');
const { merge, cover } = require('../config/index');
//工作目录文件夹路径
const inputDir = getInputDir();
if (!inputDir) {
console.log('未执行ppt拼图功能工作目录不存在');
return;
}
//需要拼图的文件夹
const merageImgDir = `${inputDir}/img`;
const pdfDir = `${inputDir}/pdf`;
if (!merageImgDir) {
console.log('未执行ppt拼图功能工作目录下的图片文件夹不存在');
return;
}
/** //创建预览图输出文件夹
* 拼接图片 const previewDir = `${inputDir}/预览图`;
* @param {Array<string>} imagePaths - 图片路径数组 if (!fs.existsSync(previewDir)) {
* @param {number} num - 每行显示的图片数量 fs.mkdirSync(previewDir);
* @param {string} bgColor - 背景颜色例如'#ffffff' }
* @param {number} width - 拼接后的宽度
* @param {number} gap - 图片之间的间隙 async function stitchImages(imagePaths, { row, bgColor, width, margin, padding }, outputName) {
*/
async function stitchImages(imagePaths, num, bgColor, width, gap) {
// 获取第一张图片的信息 // 获取第一张图片的信息
const firstImageInfo = await sharp(imagePaths[0]).metadata(); const firstImageInfo = await sharp(imagePaths[0]).metadata();
const firstImageHeight = Math.floor((firstImageInfo.height / firstImageInfo.width) * width); // 根据比例计算高度 const firstImageHeight = Math.floor((firstImageInfo.height / firstImageInfo.width) * width); // 根据比例计算高度
@ -36,15 +34,15 @@ async function stitchImages(imagePaths, num, bgColor, width, gap) {
const remainingImagesInfo = await Promise.all( const remainingImagesInfo = await Promise.all(
imagePaths.slice(1).map(async (imagePath) => { imagePaths.slice(1).map(async (imagePath) => {
const { data, info } = await sharp(imagePath) const { data, info } = await sharp(imagePath)
.resize({ width: Math.floor((width - gap * (num - 1)) / num), fit: 'inside' }) .resize({ width: Math.floor((width - padding * 2 * row) / row), fit: 'inside' })
.toBuffer({ resolveWithObject: true }); .toBuffer({ resolveWithObject: true });
return { data, height: info.height }; // 返回图片数据及其高度 return { data, info }; // 返回图片数据及其高度
}) })
); );
const rows = Math.ceil(remainingImagesInfo.length / num); // 计算剩余图片的行数 const rows = Math.ceil(remainingImagesInfo.length / row); // 计算剩余图片的行数
const totalHeight = firstImageHeight + (remainingImagesInfo[0]?.height + gap) * rows + gap; // 总高度 const totalHeight = margin * 2 + (padding * 2 + firstImageHeight) + (remainingImagesInfo[0]?.info.height + padding * 2) * rows; // 总高度
const totalWidth = width + 2 * gap; // 总宽度,包括外层间隙 const totalWidth = width + 2 * margin; // 总宽度,包括外层间隙
// 创建拼接后的图片 // 创建拼接后的图片
const outputImage = await sharp({ const outputImage = await sharp({
@ -57,29 +55,60 @@ async function stitchImages(imagePaths, num, bgColor, width, gap) {
}) })
.composite([ .composite([
{ {
input: await sharp(imagePaths[0]).resize(width, firstImageHeight).toBuffer(), input: await sharp(imagePaths[0])
top: gap, // 第一张图片顶部留出外层间隙 .resize(width - 2 * padding, firstImageHeight)
left: gap, // 第一张图片左侧留出外层间隙 .toBuffer(),
top: margin + padding, // 第一张图片顶部留出外层间隙
left: margin + padding, // 第一张图片左侧留出外层间隙
}, },
...remainingImagesInfo.map((imgInfo, index) => { ...remainingImagesInfo.map(({ data, info }, index) => {
const row = Math.floor(index / num); const currentRow = Math.floor(index / row);
const col = index % num; const currentCol = index % row;
return { return {
input: imgInfo.data, input: data,
top: firstImageHeight + gap + row * (imgInfo.height + gap), // 计算纵向位置 top: margin + padding + firstImageHeight + 2 * padding + currentRow * (info.height + padding * 2), // 计算纵向位置
left: gap + Math.floor(col * (width / num) + col * gap), // 计算横向位置并取整 left: margin + padding + currentCol * padding * 2 + currentCol * info.width, // 计算横向位置并取整
}; };
}), }),
]) ])
.toFile('output.png'); .toFile(outputName);
console.log('拼接完成,输出文件为:', outputImage); console.log('拼接完成,输出文件为:', outputName);
} }
// 示例使用 const stitchPromises = []; // 存储所有拼图任务的 Promise
const num = 2; // 每行显示的图片数量 // 读取输入目录下所有文件夹,将每个文件夹内的图片拼图
const bgColor = 'red'; // 背景颜色 fs.readdirSync(merageImgDir, { withFileTypes: true }).forEach((imgDir) => {
const width = 1000; // 拼接后的宽度 if (imgDir.isDirectory()) {
const gap = 10; // 图片之间的间隙 const inputPath = path.join(merageImgDir, imgDir.name);
const imagePaths = [];
fs.readdirSync(inputPath).forEach((file) => {
const ext = file.split('.').pop().toLowerCase();
if (cover.imgFormat.has(ext)) {
const imgPath = path.join(inputPath, file);
imagePaths.push(imgPath);
}
});
const sortImagePaths = imagePaths.sort((a, b) => {
// 提取数字部分
const numA = parseInt(a.match(/slide_(\d+)\.png/)[1], 10);
const numB = parseInt(b.match(/slide_(\d+)\.png/)[1], 10);
stitchImages(imagePaths, num, bgColor, width, gap).catch((err) => console.error('发生错误:', err)); return numA - numB; // 按数字排序
});
const outputName = path.join(previewDir, `${imgDir.name}.png`);
stitchPromises.push(stitchImages(sortImagePaths, merge, outputName));
}
});
// 等待所有拼图任务完成
Promise.all(stitchPromises)
.then(() => {
console.log('所有拼图任务完成');
fs.rmSync(merageImgDir, { recursive: true, force: true });
fs.rmSync(pdfDir, { recursive: true, force: true });
console.log('删除img和pdf文件夹任务完成');
})
.catch((err) => {
console.error('发生错误:', err);
});

@ -14,7 +14,6 @@ if (!inputDir) {
//创建pdf输出文件夹 //创建pdf输出文件夹
const pdfDir = `${inputDir}/pdf`; const pdfDir = `${inputDir}/pdf`;
console.log(pdfDir);
if (!fs.existsSync(pdfDir)) { if (!fs.existsSync(pdfDir)) {
fs.mkdirSync(pdfDir); fs.mkdirSync(pdfDir);
} }

Loading…
Cancel
Save