每个用OpenXML制作的PPTX文件都会被PowerPoint提示需要修复

编程语言 2026-07-09

我正在尝试创建一个包含图片的单张幻灯片的新的演示文稿。使用OpenXml制作的每个 .pptx,在用PowerPoint打开时,都会出现以下提示:

PowerPoint在 file.pptx的内容中发现问题。PowerPoint可以尝试修复演示文稿

如果点击修复,它就会修复,图片也会正常显示。当然,我不想每次都看到这个提示。我已经尝试了我能找到的所有校验工具(OpenXml的生产力代码、代码内校验、OOXML等等),但没有一个显示错误。

部分代码在此展示:

private const long EmusPerPoint = 12700L;
private const long EmusPerInch = 914400L;
private const int Left = 100;
private const int Top = 100;

private const uint SlideMasterId = 2147483648U;
private const uint SlideLayoutId = 2147483649U;
private const uint SlideId = 256U;

public static void SendToPowerPoint(string imagePath)
{
    try
    {
        var outputPath = Path.Combine(
            Path.GetTempPath(),
            $"tempPresentation-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.pptx"
        );

        long cx;
        long cy;

        using (var bmp = System.Drawing.Image.FromFile(imagePath))
        {
            cx = (long)(bmp.Width / bmp.HorizontalResolution * EmusPerInch);
            cy = (long)(bmp.Height / bmp.VerticalResolution * EmusPerInch);
        }

        long leftEmu = Left * EmusPerPoint;
        long topEmu = Top * EmusPerPoint;

        using (var pptx = PresentationDocument.Create(outputPath, PresentationDocumentType.Presentation))
        {
            var presentationPart = pptx.AddPresentationPart();
            presentationPart.Presentation = new Presentation();

            var slideMasterPart = presentationPart.AddNewPart<SlideMasterPart>("rIdMaster");
            var slideLayoutPart = slideMasterPart.AddNewPart<SlideLayoutPart>("rIdLayout");

            slideLayoutPart.AddPart(slideMasterPart, "rIdMaster");

            BuildSlideLayout(slideLayoutPart);
            BuildSlideMaster(slideMasterPart, slideLayoutPart);

            var slidePart = presentationPart.AddNewPart<SlidePart>("rIdSlide");

            // reference the layout using SAME relationship ID
            slidePart.AddPart(slideLayoutPart, "rIdLayout");

            // add image
            var imagePart = slidePart.AddImagePart(GetImagePartType(imagePath), "rIdImage");
            using (var stream = File.OpenRead(imagePath))
                imagePart.FeedData(stream);

            var picture = BuildPicture("rIdImage", leftEmu, topEmu, cx, cy);

            BuildSlide(slidePart, picture);

            var pres = presentationPart.Presentation;

            pres.SlideMasterIdList =
                new SlideMasterIdList(
                    new SlideMasterId
                    {
                        Id = SlideMasterId,
                        RelationshipId = "rIdMaster"
                    });

            pres.SlideIdList =
                new SlideIdList(
                    new SlideId
                    {
                        Id = SlideId,
                        RelationshipId = "rIdSlide"
                    });

            pres.SlideSize = new SlideSize
            {
                Cx = 9144000,
                Cy = 6858000
            };

            pres.NotesSize = new NotesSize
            {
                Cx = 6858000,
                Cy = 9144000
            };

            pres.DefaultTextStyle = new DefaultTextStyle();
            pres.Save();
        }

        System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
        {
            FileName = outputPath,
            UseShellExecute = true
        });
    }
    catch (Exception ex)
    {
        MessageBox.Show($"PowerPoint integration failed: {ex.Message}");
    }
}

private static void BuildSlideLayout(SlideLayoutPart part)
{
    part.SlideLayout =
        new SlideLayout(
            new CommonSlideData(
                new ShapeTree(
                    new NonVisualGroupShapeProperties(
                        new NonVisualDrawingProperties { Id = 1, Name = "" },
                        new NonVisualGroupShapeDrawingProperties(),
                        new ApplicationNonVisualDrawingProperties()
                    ),
                    new GroupShapeProperties(new OpenXmlDrawing.TransformGroup()),

                    new Shape(
                        new NonVisualShapeProperties(
                            new NonVisualDrawingProperties { Id = 2, Name = "Title Placeholder" },
                            new NonVisualShapeDrawingProperties(new OpenXmlDrawing.ShapeLocks { NoGrouping = true }),
                            new ApplicationNonVisualDrawingProperties(new PlaceholderShape())
                        ),
                        new ShapeProperties()
                    )
                )
            ),
            new ColorMapOverride(new OpenXmlDrawing.MasterColorMapping())
        )
        {
            Type = SlideLayoutValues.Blank
        };

    part.SlideLayout.Save();
}

private static void BuildSlideMaster(SlideMasterPart masterPart, SlideLayoutPart layoutPart)
{
    masterPart.SlideMaster =
        new SlideMaster(
            new CommonSlideData(
                new ShapeTree(
                    new NonVisualGroupShapeProperties(
                        new NonVisualDrawingProperties { Id = 1, Name = "" },
                        new NonVisualGroupShapeDrawingProperties(),
                        new ApplicationNonVisualDrawingProperties()
                    ),
                    new GroupShapeProperties(new OpenXmlDrawing.TransformGroup())
                )
            ),
            new ColorMap
            {
                Background1 = OpenXmlDrawing.ColorSchemeIndexValues.Light1,
                Text1 = OpenXmlDrawing.ColorSchemeIndexValues.Dark1,
                Background2 = OpenXmlDrawing.ColorSchemeIndexValues.Light2,
                Text2 = OpenXmlDrawing.ColorSchemeIndexValues.Dark2,
                Accent1 = OpenXmlDrawing.ColorSchemeIndexValues.Accent1,
                Accent2 = OpenXmlDrawing.ColorSchemeIndexValues.Accent2,
                Accent3 = OpenXmlDrawing.ColorSchemeIndexValues.Accent3,
                Accent4 = OpenXmlDrawing.ColorSchemeIndexValues.Accent4,
                Accent5 = OpenXmlDrawing.ColorSchemeIndexValues.Accent5,
                Accent6 = OpenXmlDrawing.ColorSchemeIndexValues.Accent6,
                Hyperlink = OpenXmlDrawing.ColorSchemeIndexValues.Hyperlink,
                FollowedHyperlink = OpenXmlDrawing.ColorSchemeIndexValues.FollowedHyperlink
            },
            new SlideLayoutIdList(
                new SlideLayoutId
                {
                    Id = SlideLayoutId,
                    RelationshipId = "rIdLayout"
                }
            )
        );

    masterPart.SlideMaster.Save();
}

private static void BuildSlide(SlidePart part, Picture picture)
{
    part.Slide =
        new Slide(
            new CommonSlideData(
                new ShapeTree(
                    new NonVisualGroupShapeProperties(
                        new NonVisualDrawingProperties { Id = 1, Name = "" },
                        new NonVisualGroupShapeDrawingProperties(),
                        new ApplicationNonVisualDrawingProperties()
                    ),
                    new GroupShapeProperties(new OpenXmlDrawing.TransformGroup()),
                    picture
                )
            ),
            new ColorMapOverride(new OpenXmlDrawing.MasterColorMapping())
        );

    part.Slide.Save();
}

private static Picture BuildPicture(string relId, long left, long top, long cx, long cy)
{
    return new Picture(
        new NonVisualPictureProperties(
            new NonVisualDrawingProperties { Id = 2, Name = "Picture 1" },
            new NonVisualPictureDrawingProperties(new OpenXmlDrawing.PictureLocks { NoChangeAspect = true }),
            new ApplicationNonVisualDrawingProperties()
        ),
        new BlipFill(
            new OpenXmlDrawing.Blip { Embed = relId },
            new OpenXmlDrawing.Stretch(new OpenXmlDrawing.FillRectangle())
        ),
        new ShapeProperties(
            new OpenXmlDrawing.Transform2D(
                new OpenXmlDrawing.Offset { X = left, Y = top },
                new OpenXmlDrawing.Extents { Cx = cx, Cy = cy }
            ),
            new OpenXmlDrawing.PresetGeometry(new OpenXmlDrawing.AdjustValueList())
            { Preset = OpenXmlDrawing.ShapeTypeValues.Rectangle }
        )
    );
}

private static ImagePartType GetImagePartType(string path)
{
    switch (Path.GetExtension(path).ToLowerInvariant())
    {
        case ".jpg":
        case ".jpeg": return ImagePartType.Jpeg;
        case ".png": return ImagePartType.Png;
        case ".gif": return ImagePartType.Gif;
        case ".bmp": return ImagePartType.Bmp;
        case ".tif":
        case ".tiff": return ImagePartType.Tiff;
        default: return ImagePartType.Png;
    }
}

解决方案

我认为根本原因是两个结构性问题,OpenXML验证器只强制模式有效性、而非行业惯例,因此无法捕捉到。

1. SlideMaster 缺少 TextStyles(主要原因)

在每个 SlideMaster 中包含 TextStyles 是标准做法。微软自己的文档始终包含它(https://learn.microsoft.com/en-us/office/open-xml/presentation/working-with-slide-masters),而每个PowerPoint生成的 .pptx 都在 slideMaster1.xml 中包含它。省略它虽然仍然使XML架构保持有效,但PowerPoint打开时会修复该文件。

masterPart.SlideMaster =
    new SlideMaster(
        new CommonSlideData(...),
        new ColorMap { ... },
        new SlideLayoutIdList(
            new SlideLayoutId { Id = SlideLayoutId, RelationshipId = "rIdLayout" }
        ),
        new TextStyles(        // this was missing
            new TitleStyle(),
            new BodyStyle(),
            new OtherStyle()
        )
    );

2.空白布局包含一个占位形状(次要原因)

BuildSlideLayout 在其中添加了一个 Shape,里面包含一个 PlaceholderShape,但布局被声明为 SlideLayoutValues.Blank。空白布局不能包含占位形状,因此请从 ShapeTree 中将其完全移除:

private static void BuildSlideLayout(SlideLayoutPart part)
{
    part.SlideLayout =
        new SlideLayout(
            new CommonSlideData(
                new ShapeTree(
                    new NonVisualGroupShapeProperties(
                        new NonVisualDrawingProperties { Id = 1, Name = "" },
                        new NonVisualGroupShapeDrawingProperties(),
                        new ApplicationNonVisualDrawingProperties()
                    ),
                    new GroupShapeProperties(new OpenXmlDrawing.TransformGroup())
                    // No shape/placeholder for a blank layout
                )
            ),
            new ColorMapOverride(new OpenXmlDrawing.MasterColorMapping())
        )
        { Type = SlideLayoutValues.Blank };

    part.SlideLayout.Save();
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章