diff --git a/config/index.js b/config/index.js index 61522ec..0a530c8 100644 --- a/config/index.js +++ b/config/index.js @@ -2,7 +2,7 @@ const config = { //基础公共配置 base: { // 指定要查找的目录 - directoryPath: '/Users/minya/Desktop/商品资料', + directoryPath: 'C:/Users/Administrator/Desktop/test', /** * 图片文件夹路径 * 1. 配置文件中inputDir为空 @@ -16,7 +16,7 @@ const config = { // 裁剪商品封面图 cover: { // 支持处理的常见图片格式 - format: new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'svg']), + imgFormat: new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'svg']), // 封面图裁剪比例 scaleArr: [ { @@ -32,8 +32,8 @@ const config = { ], }, ppt: { - // 支持处理的常见图片格式 - format: new Set(['ppt', 'pptx']), + pptFormat: new Set(['ppt', 'pptx']), + pdfFormat: new Set(['pdf']), }, }; diff --git a/output.png b/output.png new file mode 100644 index 0000000..4d504b6 Binary files /dev/null and b/output.png differ diff --git a/output_with_watermark.png b/output_with_watermark.png new file mode 100644 index 0000000..6d8607f Binary files /dev/null and b/output_with_watermark.png differ diff --git a/src/img_merge.js b/src/img_merge.js new file mode 100644 index 0000000..199d151 --- /dev/null +++ b/src/img_merge.js @@ -0,0 +1,85 @@ +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'); + +/** + * 拼接图片 + * @param {Array} imagePaths - 图片路径数组 + * @param {number} num - 每行显示的图片数量 + * @param {string} bgColor - 背景颜色(例如:'#ffffff') + * @param {number} width - 拼接后的宽度 + * @param {number} gap - 图片之间的间隙 + */ +async function stitchImages(imagePaths, num, bgColor, width, gap) { + // 获取第一张图片的信息 + const firstImageInfo = await sharp(imagePaths[0]).metadata(); + const firstImageHeight = Math.floor((firstImageInfo.height / firstImageInfo.width) * width); // 根据比例计算高度 + + // 处理剩余的图片 + const remainingImagesInfo = await Promise.all( + imagePaths.slice(1).map(async (imagePath) => { + const { data, info } = await sharp(imagePath) + .resize({ width: Math.floor((width - gap * (num - 1)) / num), fit: 'inside' }) + .toBuffer({ resolveWithObject: true }); + return { data, height: info.height }; // 返回图片数据及其高度 + }) + ); + + const rows = Math.ceil(remainingImagesInfo.length / num); // 计算剩余图片的行数 + const totalHeight = firstImageHeight + (remainingImagesInfo[0]?.height + gap) * rows + gap; // 总高度 + const totalWidth = width + 2 * gap; // 总宽度,包括外层间隙 + + // 创建拼接后的图片 + const outputImage = await sharp({ + create: { + width: totalWidth, + height: totalHeight, + channels: 3, + background: bgColor, + }, + }) + .composite([ + { + input: await sharp(imagePaths[0]).resize(width, firstImageHeight).toBuffer(), + top: gap, // 第一张图片顶部留出外层间隙 + left: gap, // 第一张图片左侧留出外层间隙 + }, + ...remainingImagesInfo.map((imgInfo, index) => { + const row = Math.floor(index / num); + const col = index % num; + return { + input: imgInfo.data, + top: firstImageHeight + gap + row * (imgInfo.height + gap), // 计算纵向位置 + left: gap + Math.floor(col * (width / num) + col * gap), // 计算横向位置并取整 + }; + }), + ]) + .toFile('output.png'); + + console.log('拼接完成,输出文件为:', outputImage); +} + +// 示例使用 +const num = 2; // 每行显示的图片数量 +const bgColor = 'red'; // 背景颜色 +const width = 1000; // 拼接后的宽度 +const gap = 10; // 图片之间的间隙 + +stitchImages(imagePaths, num, bgColor, width, gap).catch((err) => console.error('发生错误:', err)); diff --git a/src/ppt_to_img.js b/src/ppt_to_img.js index 87219d2..c09cd44 100644 --- a/src/ppt_to_img.js +++ b/src/ppt_to_img.js @@ -1,11 +1,11 @@ -const { exec } = require('child_process'); +const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const { getInputDir } = require('../utils/index'); const { ppt } = require('../config/index'); //工作目录文件夹路径 -const inputDir = getInputDir(); // 输入PPT文件路径 +const inputDir = getInputDir(); if (!inputDir) { console.log('未执行ppt转图片功能,工作目录不存在'); @@ -25,47 +25,41 @@ if (!fs.existsSync(imgDir)) { fs.mkdirSync(imgDir); } -const convertPptToImages = (inputDir, outputDir) => { - // 使用 LibreOffice 将 PPT 转换为 PDF - // const pdfFilePath = path.join(outputDir, '9.pdf'); - // console.log(pdfFilePath); - const convertCommand = `soffice --headless --invisible --convert-to pdf --outdir "${outputDir}" "${inputDir}"`; +// 使用 LibreOffice 将 PPT 转换为 PDF +const convertPptToPdf = (inputDir) => { + const pdfCmd = `soffice --headless --invisible --convert-to pdf --outdir "${pdfDir}" "${inputDir}" 2>NUL`; + console.log(pdfCmd); - return new Promise((resolve, reject) => { - exec(convertCommand, (error) => { - if (error) { - reject(error); - } else { - resolve(); - } + execSync(pdfCmd); +}; - // // 使用 ImageMagick 将 PDF 转换为图片 - // const imageOutputPath = path.join(outputDir, 'slide_%d.png'); - // const convertImageCommand = `convert -density 300 "${pdfFilePath}" "${imageOutputPath}"`; +// 使用 ImageMagick 将 PDF 转换为图片 +const convertPdfToImg = (inputDir, file) => { + const imgItemDir = path.join(imgDir, `${file.split('.')[0]}`); + if (!fs.existsSync(imgItemDir)) { + fs.mkdirSync(imgItemDir); + } - // exec(convertImageCommand, (error) => { - // if (error) { - // console.error(`转换为图片失败: ${error}`); - // return; - // } - // console.log('转换成功!输出目录:', outputDir); - // }); - }); - }); + const imageOutputPath = path.join(imgItemDir, 'slide_%d.png'); + const imgCmd = `magick -density 72 "${inputDir}" "${imageOutputPath}"`; + console.log(imgCmd); + execSync(imgCmd); }; -//读取输入目录下所有文件 -fs.readdirSync(inputDir).forEach(async (file) => { +// 读取输入目录下所有ppt文件 => 转换为pdf +fs.readdirSync(inputDir).forEach((file) => { const ext = file.split('.').pop().toLowerCase(); - if (ppt.format.has(ext)) { + if (ppt.pptFormat.has(ext)) { const inputPath = path.join(inputDir, file); - const outputPath = path.join(pdfDir, file); - convertPptToImages(inputPath, outputPath) - .then(() => { - console.log(`${file}的图片已生成`); - }) - .catch((err) => { - console.error(`${file}的图片生成失败`, err); - }); + convertPptToPdf(inputPath); + } +}); + +// 读取输入目录下所有pdf文件下所有pdf文件 => 转换为image +fs.readdirSync(pdfDir).forEach((file) => { + const ext = file.split('.').pop().toLowerCase(); + if (ppt.pdfFormat.has(ext)) { + const inputPath = path.join(pdfDir, file); + convertPdfToImg(inputPath, file); } }); diff --git a/src/product_cover_img.js b/src/product_cover_img.js index 5787a39..173db3e 100644 --- a/src/product_cover_img.js +++ b/src/product_cover_img.js @@ -47,7 +47,7 @@ async function resizeImage(imageDir, outputDir, scale) { //读取输入目录下所有文件 fs.readdirSync(inputDir).forEach(async (file) => { const ext = file.split('.').pop().toLowerCase(); - if (cover.format.has(ext)) { + if (cover.imgFormat.has(ext)) { const inputPath = path.join(inputDir, file); cover.scaleArr.forEach((item) => { const outputPath = path.join(item.dir, file);