C#使用GemBoxPresentation向PPT添加图文时单文件生成问题解决
功能需求与问题说明
需要实现的目标:
- 读取指定文件夹内的所有PNG图片
- 每张图片单独占用一页幻灯片,图片下方标注对应文件名
- 在第1个母版幻灯片中添加全局标题
现有代码异常:运行后每张图片单独生成一个PPT文件,无法将所有图片汇总到同一个PPT内。
预期输出效果:所有图片汇总在同一个PPT文件内,每页幻灯片顶部显示统一的母版标题,页面居中位置展示对应图片,图片下方居中标注图片文件名。
当前存在问题的原代码如下:
//Create new powerpoint presentation var presentation = new PresentationDocument(); //change the path format string dir = txtPath.Text.Replace("/", "\\"); fontRootFolder = dir.Replace(Path.GetDirectoryName(dir) + Path.DirectorySeparatorChar, ""); string workingPath = Application.StartupPath + @"\Zip Extracts\" + fontRootFolder + "\\png"; if (Directory.Exists(workingPath)) { // Get the directory DirectoryInfo ImagePath = new DirectoryInfo(workingPath); // Using GetFiles() method to get list of all png files present in the png folder FileInfo[] Files = ImagePath.GetFiles(); foreach (FileInfo fi in Files) { for (int i = 0; i < fi.Length; i++) { Cursor = Cursors.WaitCursor; // Get slide size. var size = presentation.SlideSize; // Set slide size. size.SizedFor = SlideSizeType.OnscreenShow16X10; size.Orientation = GemBox.Presentation.Orientation.Landscape; size.NumberSlidesFrom = 1; // Create new presentation slide. var slide = presentation.Slides.AddNew(SlideLayoutType.Custom); // Create first picture from path. Picture picture = null; using (var stream = File.OpenRead(fi.FullName)) picture = slide.Content.AddPicture(PictureContentType.Png, stream, 1.45, 1.35, 1.45, 1.35, LengthUnit.Centimeter); var textBox = slide.Content.AddTextBox(ShapeGeometryType.Rectangle, 1.03, 1.03, 6, 6, LengthUnit.Centimeter); var paragraph = textBox.AddParagraph(); paragraph.Format.Alignment = GemBox.Presentation.HorizontalAlignment.Center; paragraph.AddRun(fi.Name); SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); sfd.Title = "Save PowerPoint Icons"; sfd.CheckFileExists = false; sfd.CheckPathExists = true; sfd.DefaultExt = "pptx"; sfd.Filter = "Powerpoint Files (*.pptx) | *.pptx"; sfd.FilterIndex = 1; sfd.RestoreDirectory = true; if (sfd.ShowDialog() == DialogResult.OK) { presentation.Save(sfd.FileName); Cursor = Cursors.Default; } Cursor = Cursors.Default; } } }
错误原因
- 存在无效循环:
for (int i = 0; i < fi.Length; i++)逻辑错误,fi.Length是当前图片文件的字节大小,不是遍历计数,会导致单张图片重复执行多次幻灯片创建逻辑 - 逻辑位置错误:幻灯片尺寸设置、保存文件弹窗、PPT保存逻辑全部写在了文件遍历循环内部,每处理一张图片就会触发一次保存操作
- 缺失需求逻辑:没有实现母版幻灯片添加标题的功能,同时图片和文件名文本框的位置、尺寸参数设置不合理,会出现内容重叠、偏移问题
- 文件过滤缺失:
GetFiles()会读取目标文件夹下所有类型的文件,没有过滤仅读取PNG图片
修正后可运行代码
// 初始化PPT文档,该操作仅需执行1次 var presentation = new PresentationDocument(); // 幻灯片尺寸设置仅需执行1次,放在循环外 var size = presentation.SlideSize; size.SizedFor = SlideSizeType.OnscreenShow16X10; size.Orientation = Orientation.Landscape; size.NumberSlidesFrom = 1; // 给第1个母版幻灯片添加全局标题 var masterSlide = presentation.MasterSlides[0]; var titleTextBox = masterSlide.Content.AddTextBox(ShapeGeometryType.Rectangle, 0, 0.5, 25.4, 2, LengthUnit.Centimeter); var titlePara = titleTextBox.AddParagraph(); titlePara.Format.Alignment = HorizontalAlignment.Center; var titleRun = titlePara.AddRun("图片批量导出PPT"); // 此处可替换为需要的母版标题文本 titleRun.Format.Bold = true; titleRun.Format.Size = 32; // 路径处理 string dir = txtPath.Text.Replace("/", "\\"); fontRootFolder = dir.Replace(Path.GetDirectoryName(dir) + Path.DirectorySeparatorChar, ""); string workingPath = Path.Combine(Application.StartupPath, "Zip Extracts", fontRootFolder, "png"); if (Directory.Exists(workingPath)) { DirectoryInfo imagePath = new DirectoryInfo(workingPath); // 仅过滤获取PNG格式文件 FileInfo[] files = imagePath.GetFiles("*.png"); Cursor = Cursors.WaitCursor; // 遍历所有图片文件 foreach (FileInfo fi in files) { // 新建单张幻灯片 var slide = presentation.Slides.AddNew(SlideLayoutType.Custom); // 添加图片:水平居中放置,宽18cm,高度按原图比例自动适配 Picture picture; using (var stream = File.OpenRead(fi.FullName)) picture = slide.Content.AddPicture(PictureContentType.Png, stream, 3.7, 3, 18, 0, LengthUnit.Centimeter); // 计算图片实际渲染高度,将文件名文本框放在图片正下方1cm位置 double picBottom = picture.Position.Top + picture.Layout.Height; var nameTextBox = slide.Content.AddTextBox(ShapeGeometryType.Rectangle, 3.7, picBottom + 1, 18, 1.5, LengthUnit.Centimeter); var namePara = nameTextBox.AddParagraph(); namePara.Format.Alignment = HorizontalAlignment.Center; namePara.AddRun(fi.Name); } // 所有幻灯片生成完成后,仅触发1次保存弹窗 using (SaveFileDialog sfd = new SaveFileDialog()) { sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); sfd.Title = "Save PowerPoint Icons"; sfd.CheckFileExists = false; sfd.CheckPathExists = true; sfd.DefaultExt = "pptx"; sfd.Filter = "Powerpoint Files (*.pptx) | *.pptx"; sfd.FilterIndex = 1; sfd.RestoreDirectory = true; if (sfd.ShowDialog() == DialogResult.OK) { presentation.Save(sfd.FileName); } } Cursor = Cursors.Default; }
修正说明
- 所有只需执行1次的初始化、配置、保存逻辑全部移到循环外部,避免重复执行
- 删除无效的字节长度for循环,避免重复创建幻灯片
- 新增母版标题添加逻辑,标题会自动应用到所有幻灯片页面顶部
- 新增PNG文件过滤,避免读取非图片文件
- 调整图片和文件名文本框的位置,自动适配图片高度避免内容重叠,所有内容居中显示
- 使用
Path.Combine拼接路径,避免不同系统下路径分隔符兼容问题 - 增加
using语句释放SaveFileDialog资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Kamweti C
相关产品推荐
相关产品推荐

