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

C#使用Open XML向Word页眉插入图片显示空白框问题

页眉插入图片显示空白框的修复方案

核心错误原因

现有页眉插入逻辑存在4个问题,直接导致图片无法正常渲染:

  • 图片部件挂载位置错误:页眉是独立于正文的HeaderPart部件,Open XML的部件关系是隔离的,代码将图片资源挂载到了MainDocumentPart下,页眉内的资源引用无法跨部件找到对应图片,只能渲染空白占位框。
  • 尺寸单位未做转换:正文插入逻辑里做了像素到EMU(Open XML绘图专用单位)的换算,页眉逻辑里直接把原始像素值填入尺寸属性,不符合格式规范导致渲染失败。
  • 页眉存在性判断逻辑写反:判断条件!mainDocPart.HeaderParts.Any()意味着只有文档完全没有页眉时才会执行插入逻辑,文档自带默认页眉的场景下插入代码完全不会运行。
  • 尺寸读取路径硬编码:GeneratePicHeader方法读取图片尺寸时用了写死的本地路径C:\Users\SAKS\HeaderPic.png,和实际传入的待插入图片路径不一致,既可能触发文件不存在的异常,也会导致尺寸和实际图片不匹配。

修复后代码

修正后的页眉插入入口方法

static void AddPicInHeader(string document, string imagePath)
{
    using(WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true))
    {
        var mainDocPart = wordprocessingDocument.MainDocumentPart;
        // 获取文档最后一个节的属性
        var sectionProps = mainDocPart.Document.Body.Elements<SectionProperties>().LastOrDefault();
        if (sectionProps == null)
        {
            sectionProps = new SectionProperties();
            mainDocPart.Document.Body.Append(sectionProps);
        }

        HeaderPart targetHeaderPart;
        // 优先复用已存在的页眉,不存在则新建
        var existingHeaderRef = sectionProps.GetFirstChild<HeaderReference>();
        if (existingHeaderRef != null)
        {
            targetHeaderPart = mainDocPart.GetPartById(existingHeaderRef.Id) as HeaderPart;
        }
        else
        {
            targetHeaderPart = mainDocPart.AddNewPart<HeaderPart>();
            var newHeaderRef = new HeaderReference() { Id = mainDocPart.GetIdOfPart(targetHeaderPart) };
            sectionProps.RemoveAllChildren<HeaderReference>();
            sectionProps.Append(newHeaderRef);
            targetHeaderPart.Header = new Header();
        }

        // 关键:图片资源必须挂载到当前HeaderPart下,不能挂在MainDocumentPart
        var imgPart = targetHeaderPart.AddImagePart(ImagePartType.Png);
        using(FileStream stream = new FileStream(imagePath, FileMode.Open))
        {
            imgPart.FeedData(stream);
        }
        var imagePartId = targetHeaderPart.GetIdOfPart(imgPart);

        // 生成图片元素追加到页眉
        var headerPic = GenerateHeaderPicElement(imagePartId, imagePath);
        targetHeaderPart.Header.AppendChild(new Paragraph(new Run(headerPic)));
        targetHeaderPart.Header.Save();
    }
}

修正后的图片元素生成方法

static Drawing GenerateHeaderPicElement(string relationshipId, string actualImagePath)
{
    long pixelWidth = 0;
    long pixelHeight = 0;
    // 读取实际插入图片的尺寸,不要硬编码路径
    using(System.Drawing.Bitmap bmp = new Bitmap(actualImagePath))
    {
        pixelHeight = bmp.Height;
        pixelWidth = bmp.Width;
    }
    // 像素转EMU单位,标准换算系数为9525(1像素=9525EMU)
    long emuWidth = pixelWidth * 9525;
    long emuHeight = pixelHeight * 9525;

    return new Drawing(
        new DW.Inline(
            new DW.Extent() { Cx = emuWidth, Cy = emuHeight },
            new DW.EffectExtent()
            {
                LeftEdge = 0L,
                TopEdge = 0L,
                RightEdge = 0L,
                BottomEdge = 0L
            },
            new DW.DocProperties()
            {
                Id = (UInt32Value)1U,
                Name = Path.GetFileName(actualImagePath)
            },
            new A.Graphic(
                new A.GraphicData(
                    new PIC.Picture(
                        new PIC.NonVisualPictureProperties(
                            new PIC.NonVisualDrawingProperties()
                            {
                                Id = (UInt32Value)0U,
                                Name = Path.GetFileName(actualImagePath)
                            },
                            new PIC.NonVisualPictureDrawingProperties()),
                        new PIC.BlipFill(
                            new A.Blip(
                                new A.BlipExtensionList(
                                    new A.BlipExtension()
                                    {
                                        Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}"
                                    })
                            )
                            {
                                Embed = relationshipId,
                                CompressionState = A.BlipCompressionValues.Print
                            },
                            new A.Stretch(new A.FillRectangle())),
                        new PIC.ShapeProperties(
                            new A.Transform2D(
                                new A.Offset() { X = 0L, Y = 0L },
                                new A.Extents() { Cx = emuWidth, Cy = emuHeight }),
                            new A.PresetGeometry(new A.AdjustValueList())
                            {
                                Preset = A.ShapeTypeValues.Rectangle
                            }))
                )
                {
                    Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"
                })
        )
        {
            DistanceFromTop = (UInt32Value)0U,
            DistanceFromBottom = (UInt32Value)0U,
            DistanceFromLeft = (UInt32Value)0U,
            DistanceFromRight = (UInt32Value)0U,
            EditId = "50D07946"
        });
}

开发注意事项

  • Open XML中所有独立部件(页眉、页脚、正文、批注、脚注等)都有独立的关系表,部件内引用的资源(图片、超链接等)必须挂载到当前部件或可访问的父级部件下,跨部件直接引用关系ID会出现资源找不到的问题。
  • 所有绘图相关的尺寸参数必须使用EMU单位,禁止直接传入像素值,否则会出现尺寸异常、图片不渲染的问题。
  • 如果文档存在多个分节,需要遍历所有节的SectionProperties分别处理页眉,否则仅最后一个节会显示插入的页眉图片。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:09:20