You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C# Open XML SDK生成的PPT损坏空白问题排查修复

解决Open XML SDK生成PPT报错且内容为空的问题

一、版本兼容性说明

你使用的DocumentFormat.OpenXml 2.20.0版本完全兼容.NET 6和Office 365,版本本身无问题,报错并非版本导致。

二、代码中的核心问题及修复

你的代码存在3个关键问题,导致PowerPoint无法正常解析:

1. SlidePart未关联SlideLayoutPart

每个幻灯片必须绑定对应的版式,代码中创建了母版和版式,但未建立SlidePart与SlideLayoutPart的关联关系,PowerPoint无法识别幻灯片结构。

2. GraphicFrame尺寸设置为0

Transform中的Cx(宽度)和Cy(高度)设为0L,导致表格实际尺寸为0,PowerPoint会判定为无效内容并删除。

3. 母版和版式创建顺序错误且内容缺失

应先创建SlideMaster和SlideLayout,再创建SlidePart;同时空的母版和版式缺少必要的默认占位符元素,易引发兼容性问题。

修复后的完整核心代码

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using D = DocumentFormat.OpenXml.Drawing;

namespace OpenXMLBuilder
{
    class Test3
    {
        public void Doit(string[] args)
        {
            string filepath = "test3.pptx";
            CreatePresentation(filepath);
        }

        public static void CreatePresentation(string filepath)
        {
            using (PresentationDocument presentationDocument = PresentationDocument.Create(filepath, PresentationDocumentType.Presentation))
            {
                PresentationPart presentationPart = presentationDocument.AddPresentationPart();
                presentationPart.Presentation = new Presentation();

                // 先创建幻灯片母版和版式
                SlideMasterPart slideMasterPart = presentationPart.AddNewPart<SlideMasterPart>();
                InitializeSlideMaster(slideMasterPart);

                SlideLayoutPart slideLayoutPart = slideMasterPart.AddNewPart<SlideLayoutPart>();
                InitializeSlideLayout(slideLayoutPart);

                // 创建幻灯片并关联版式
                SlidePart slidePart = presentationPart.AddNewPart<SlidePart>(slideLayoutPart);
                CreateSlideContent(slidePart);

                // 配置幻灯片ID和尺寸
                presentationPart.Presentation.SlideIdList = new SlideIdList(
                    new SlideId()
                    {
                        Id = 256U,
                        RelationshipId = presentationPart.GetIdOfPart(slidePart)
                    });
                presentationPart.Presentation.SlideSize = new SlideSize() { Cx = 9144000, Cy = 6858000 };
                presentationPart.Presentation.Save();
            }
        }

        private static void InitializeSlideMaster(SlideMasterPart slideMasterPart)
        {
            var slideMaster = new SlideMaster(
                new CommonSlideData(
                    new ShapeTree(
                        new D.NonVisualGroupShapeProperties(
                            new D.NonVisualDrawingProperties() { Id = 1, Name = "" },
                            new D.NonVisualGroupShapeDrawingProperties(),
                            new D.ApplicationNonVisualDrawingProperties()),
                        new D.GroupShapeProperties(),
                        new D.Shape(
                            new D.NonVisualShapeProperties(
                                new D.NonVisualDrawingProperties() { Id = 2, Name = "Title Placeholder 1" },
                                new D.NonVisualShapeDrawingProperties(new D.ShapeLocks() { NoGrouping = true }),
                                new D.ApplicationNonVisualDrawingProperties(new D.PlaceholderShape() { Type = D.PlaceholderValues.Title })),
                            new D.ShapeProperties(),
                            new D.TextBody(
                                new D.BodyProperties(),
                                new D.ListStyle(),
                                new D.Paragraph())))),
                new ColorMapOverride(new D.MasterColorMapping()));
            slideMasterPart.SlideMaster = slideMaster;
            slideMasterPart.SlideMaster.Save();
        }

        private static void InitializeSlideLayout(SlideLayoutPart slideLayoutPart)
        {
            var slideLayout = new SlideLayout(
                new CommonSlideData(
                    new ShapeTree(
                        new D.NonVisualGroupShapeProperties(
                            new D.NonVisualDrawingProperties() { Id = 1, Name = "" },
                            new D.NonVisualGroupShapeDrawingProperties(),
                            new D.ApplicationNonVisualDrawingProperties()),
                        new D.GroupShapeProperties(),
                        new D.Shape(
                            new D.NonVisualShapeProperties(
                                new D.NonVisualDrawingProperties() { Id = 2, Name = "Title Placeholder 1" },
                                new D.NonVisualShapeDrawingProperties(new D.ShapeLocks() { NoGrouping = true }),
                                new D.ApplicationNonVisualDrawingProperties(new D.PlaceholderShape() { Type = D.PlaceholderValues.Title, MasterId = 2 })),
                            new D.ShapeProperties(),
                            new D.TextBody(
                                new D.BodyProperties(),
                                new D.ListStyle(),
                                new D.Paragraph())))),
                new SlideLayoutType() { Type = SlideLayoutValues.Title });
            slideLayoutPart.SlideLayout = slideLayout;
            slideLayoutPart.SlideLayout.Save();
        }

        private static void CreateSlideContent(SlidePart slidePart)
        {
            slidePart.Slide = new Slide(new CommonSlideData(new ShapeTree()));

            // 创建表格
            D.Table table = new D.Table();
            D.TableGrid tableGrid = new D.TableGrid();
            tableGrid.Append(new D.GridColumn() { Width = 3124200 });
            tableGrid.Append(new D.GridColumn() { Width = 3124200 });
            table.Append(tableGrid);

            // 生成3行2列的单元格
            for (int i = 0; i < 3; i++)
            {
                D.TableRow row = new D.TableRow() { Height = 370840 };
                for (int j = 0; j < 2; j++)
                {
                    D.TableCell cell = new D.TableCell();
                    D.TextBody body = new D.TextBody(
                        new D.BodyProperties(),
                        new D.ListStyle(),
                        new D.Paragraph(new D.Run(new D.Text($"Cell {i + 1},{j + 1}"))));
                    cell.Append(body);
                    cell.Append(new D.TableCellProperties());
                    row.Append(cell);
                }
                table.Append(row);
            }

            // 创建GraphicFrame并设置正确尺寸
            GraphicFrame graphicFrame = new GraphicFrame();
            graphicFrame.NonVisualGraphicFrameProperties = new NonVisualGraphicFrameProperties(
                new NonVisualDrawingProperties() { Id = 1026, Name = "Table" },
                new NonVisualGraphicFrameDrawingProperties(),
                new ApplicationNonVisualDrawingProperties());
            // 设置表格位置和尺寸(总宽度为2列宽度之和,总高度为3行高度之和)
            graphicFrame.Transform = new Transform(
                new D.Offset() { X = 1000000L, Y = 1000000L },
                new D.Extents() { Cx = 6248400L, Cy = 1112520L });
            graphicFrame.Graphic = new D.Graphic(new D.GraphicData(table)
            {
                Uri = "http://schemas.openxmlformats.org/drawingml/2006/table"
            });

            slidePart.Slide.CommonSlideData.ShapeTree.AppendChild(graphicFrame);
            slidePart.Slide.Save();
        }
    }
}

三、排查错误的实用工具

  • Open XML SDK Productivity Tool:微软官方工具,可打开PPTX验证结构,对比正常PPT与生成PPT的XML差异,还能将手动创建的PPT反编译为代码,直接参考正确元素结构。
  • 解压PPTX文件:将生成的.pptx改为.zip解压,查看内部ppt/slides/slide1.xml等文件,与正常PPT的对应XML对比,定位缺失或错误的节点。
  • PowerPoint修复日志:修复PPT后,PowerPoint会生成包含错误详情的日志文件,可查看具体被删除的内容,辅助定位问题。

四、其他解决方向

  • 手动创建包含目标表格的PPT,用Open XML SDK Productivity Tool反编译代码,对比自身代码找出差异,这是最直接的排查方法。
  • 严格遵循Open XML规范,确保每个元素都包含必填属性和子元素,避免省略必要节点(如幻灯片与版式的关联、元素尺寸属性等)。

内容的提问来源于stack exchange,提问作者GoWiser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 19:42:34