From fd21ca5e777cd2df77e3711fed6fcb6adf27b827 Mon Sep 17 00:00:00 2001 From: LCJ-MinYa <1049468118@qq.com> Date: Thu, 14 Nov 2024 18:33:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ppt=E5=B9=BF=E5=91=8A=E5=9B=BE=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/index.js | 4 ++ package.json | 1 + py-src/ad_ppt_to_img.py | 52 ++++++++++++++++++++++++++ py-src/config.py | 6 +++ src/ad_img_merge.js | 82 +++++++++++++++++++++++++++++++++++++++++ utils/index.js | 24 +++++++++++- 6 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 py-src/ad_ppt_to_img.py create mode 100644 src/ad_img_merge.js diff --git a/config/index.js b/config/index.js index a7a86b7..d962395 100644 --- a/config/index.js +++ b/config/index.js @@ -52,6 +52,10 @@ const config = { //图片间距 padding: 3, }, + exportAdImg: { + pptPath: '/Users/minya/Desktop/test/1.pptx', + column: 3, + }, }; module.exports = config; diff --git a/package.json b/package.json index cb0e6d2..c84d68c 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "water": "node ./src/water_market.js", "bg": "node ./src/product_main_img_bg.js", "reduce": "node ./src/reduce_img_size.js", + "ad": "node ./src/ad_img_merge.js", "pptToImg": "npm run ppt && npm run merge && npm run water && npm run cover && npm run bg", "pyToImg": "npm run merge && npm run water && npm run cover && npm run bg" }, diff --git a/py-src/ad_ppt_to_img.py b/py-src/ad_ppt_to_img.py new file mode 100644 index 0000000..7fd0b54 --- /dev/null +++ b/py-src/ad_ppt_to_img.py @@ -0,0 +1,52 @@ +import os +import win32com.client +from config import Config + + +# 初始化PPT +def init_powerpoint(): + powerpoint = win32com.client.Dispatch("PowerPoint.Application") + powerpoint.Visible = 1 + return powerpoint + + +# PPT转png +def ppt2png(pptFileName, downLoad_path, powerpoint): + try: + ppt_path = os.path.abspath(pptFileName) + ppt = powerpoint.Presentations.Open(ppt_path) + + # 保存为图片 + img_path = os.path.abspath(downLoad_path + ".png") + ppt.SaveAs(img_path, 18) # 18 为 PNG 格式 + + # 关闭打开的ppt文件 + ppt.Close() + except Exception as e: + print(f"PPT转png失败: {pptFileName}") + else: + print("PPT转png成功", pptFileName) + + +# 批量转换PPT文件 +def ppt_to_png(filename, ad_img_path): + powerpoint = init_powerpoint() + + if filename.endswith(".ppt") or filename.endswith(".pptx"): + downLoad_path = os.path.join(ad_img_path, os.path.splitext(os.path.basename(filename))[0]) + ppt2png(filename, downLoad_path, powerpoint) + + powerpoint.Quit() # 退出PowerPoint + + +# 示例用法 +if __name__ == "__main__": + filename = Config.EXPORT_AD_PPT_PATH + # 获取文件的目录 + directory = os.path.dirname(filename) + # 定义 adImg 文件夹的路径 + ad_img_path = os.path.join(directory, 'adImg') + # 创建输出文件夹 + os.makedirs(ad_img_path, exist_ok=True) + + ppt_to_png(filename, ad_img_path) diff --git a/py-src/config.py b/py-src/config.py index 7ee19db..b8929c2 100644 --- a/py-src/config.py +++ b/py-src/config.py @@ -6,6 +6,7 @@ class Config: RANGE_NUM: int = 0 WORK_PATH = "" INPUT_PATH = "" + EXPORT_AD_PPT_PATH = "" @staticmethod def load_config(): @@ -26,12 +27,17 @@ class Config: range_num_match = re.search( r'rangeNum:\s*["\']?(.*?)["\']?\s*,', uncommented_content ) + export_ad_ppt_path = re.search( + r'pptPath:\s*["\']?(.*?)["\']?\s*,', uncommented_content + ) if input_dir_match: Config.INPUT_PATH = input_dir_match.group(1) if directory_path_match: Config.WORK_PATH = directory_path_match.group(1) if range_num_match: Config.RANGE_NUM = int(range_num_match.group(1)) + if export_ad_ppt_path: + Config.EXPORT_AD_PPT_PATH = export_ad_ppt_path.group(1) @staticmethod def get_latest_folder(base_directory): diff --git a/src/ad_img_merge.js b/src/ad_img_merge.js new file mode 100644 index 0000000..27751e7 --- /dev/null +++ b/src/ad_img_merge.js @@ -0,0 +1,82 @@ +const sharp = require('sharp'); +const fs = require('fs'); +const path = require('path'); +const { exportAdImg, cover } = require('../config/index'); +const { getDesktopPath } = require('../utils/index'); + +if (!exportAdImg.pptPath) { + console.log('未执行广告图片拼图功能,文件路径不存在'); + return; +} + +async function stitchImages(imagePaths, outputName) { + // 处理剩余的图片 + const imagesInfo = await Promise.all( + imagePaths.map(async (imagePath) => { + const { data, info } = await sharp(imagePath).toBuffer({ resolveWithObject: true }); + return { data, info }; // 返回图片数据及其高度 + }) + ); + + const { width, height } = imagesInfo[0]?.info; + + // 创建拼接后的图片 + const outputImage = await sharp({ + create: { + width, + height: height * imagesInfo.length, + channels: 4, + background: { r: 255, g: 255, b: 255 }, + }, + }) + .composite([ + ...imagesInfo.map(({ data }, index) => { + return { + input: data, + top: index * height, + left: 0, + }; + }), + ]) + .toFile(outputName); + + console.log('广告图拼接完成,输出文件为:', outputName); +} + +async function handle_ad_img() { + // 获取文件的目录 + const directory = path.dirname(exportAdImg.pptPath); + // 定义 adImg 文件夹的路径 + const adImgPath = path.join(directory, 'adImg'); + const imagePaths = []; + fs.readdirSync(adImgPath).forEach((file) => { + const ext = file.split('.').pop().toLowerCase(); + if (cover.imgFormat.has(ext)) { + const imgPath = path.join(adImgPath, file); + imagePaths.push(imgPath); + } + }); + const sortImagePaths = imagePaths.sort((a, b) => { + // 提取数字部分 + const numA = parseInt(a.match(/幻灯片(\d+)\.png/)[1], 10); + const numB = parseInt(b.match(/幻灯片(\d+)\.png/)[1], 10); + + return numA - numB; // 按数字排序 + }); + + const desktopPath = getDesktopPath(); + for (let i = 0; i < sortImagePaths.length; i += exportAdImg.column) { + // 获取当前分组 + const chunkImagePaths = sortImagePaths.slice(i, i + exportAdImg.column); + // 计算当前分组的索引 + const groupIndex = Math.floor(i / exportAdImg.column); + const outputName = path.join(desktopPath, `${groupIndex + 1}.jpg`); + await stitchImages(chunkImagePaths, outputName); + } + + console.log('所有广告图拼接完毕'); + fs.rmSync(adImgPath, { recursive: true, force: true }); + console.log('删除adImg文件夹任务完成'); +} + +handle_ad_img(); diff --git a/utils/index.js b/utils/index.js index a1baa00..e3a3348 100644 --- a/utils/index.js +++ b/utils/index.js @@ -1,3 +1,4 @@ +const os = require('os'); const fs = require('fs'); const path = require('path'); const { base } = require('../config/index'); @@ -40,4 +41,25 @@ const getLatestFolder = (directory) => { return currentInputDir; }; -module.exports = { getInputDir, getLatestFolder }; +// 获取操作系统下面的桌面路径 +const getDesktopPath = () => { + const platform = os.platform(); + + let desktopPath; + if (platform === 'win32') { + // Windows + desktopPath = path.join(process.env.USERPROFILE, 'Desktop'); + } else if (platform === 'darwin') { + // macOS + desktopPath = path.join(process.env.HOME, 'Desktop'); + } else if (platform === 'linux') { + // Linux + desktopPath = path.join(process.env.HOME, 'Desktop'); + } else { + throw new Error('Unsupported platform: ' + platform); + } + + return desktopPath; +}; + +module.exports = { getInputDir, getLatestFolder, getDesktopPath };