【问题标题】:replace image in header, OpenXML替换标题中的图像,OpenXML
【发布时间】:2020-03-23 22:24:36
【问题描述】:

我希望有人可以帮助解决这个问题。我正在使用 OpenXMl 搜索和替换使用 Open XML 的 word 文档的页眉、正文和页脚中的文本。文本工作正常。但是图像并没有像我期望的那样被替换。图像 (@"C:\temp\pic\Logo.gif") 确实存在于源中。但从未正确显示在 word 文档中。您可以在下面的区域中看到(#region "Modify Header Logo") 有人可以帮忙吗?谢谢!

Word Error

       public void SearchAndReplace(string templateFileNameTemplate, string targetFileName, ProjectModel project)
    {

        //copy template file
        if (File.Exists(targetFileName) == true)
        {
            File.Delete(targetFileName);
        }

        File.Copy(templateFileNameTemplate, targetFileName);

        string searchText = "", replaceText = "", headerLogo = "", headerText = "";
        bool replace = false;

        //open file
        using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(targetFileName, true))
        {

            //Gets all the headers
            foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
            {
                //Gets the text in headers
                foreach (var currentText in headerPart.RootElement.Descendants<Text>())
                {
                    replace = false;

                    switch (currentText.Text)
                    {
                        case "<COMPANY NAME>":
                            replace = true;
                            replaceText = project.ClientName;
                            searchText = currentText.Text;
                            break;
                        **case "<INSERT YOUR LOGO HERE>":
                            headerLogo = @"C:\temp\pic\Logo.gif";//project.ClientLogo;**
                            headerText = currentText.Text;
                            break;
                        case "<ISSUE DATE>":
                            replace = true;
                            replaceText = project.AssignedDate.ToShortDateString();
                            searchText = currentText.Text;
                            break;
                        case "<REVIEW DATE>":
                            replace = true;
                            replaceText = project.ClientDueDate.ToShortDateString();
                            searchText = currentText.Text;
                            break;
                        default:
                            break;
                    }
                    if(searchText.Length>0 && replace==true)
                        currentText.Text = currentText.Text.Replace(searchText, replaceText);
                }
            }
            //Gets all the footers
            foreach (var footerPart in wordDoc.MainDocumentPart.FooterParts)
            {
                //Gets the text in headers
                foreach (var currentText in footerPart.RootElement.Descendants<Text>())
                {
                    replace = false;
                    switch (currentText.Text)
                    {
                        case "<COMPANY NAME>":
                            replace = true;
                            replaceText = project.ClientName;
                            searchText = currentText.Text;
                            break;
                        default:
                            break;
                    }

                    if (searchText.Length > 0 && replace == true)
                        currentText.Text = currentText.Text.Replace(searchText, replaceText);
                }
            }
            #region "Modify Header Logo"
            if(headerLogo != string.Empty)
            {
                ImagePart imagePart = wordDoc.MainDocumentPart.AddImagePart(ImagePartType.Png);
                using (FileStream stream = new FileStream(headerLogo, FileMode.Open))
                {
                    imagePart.FeedData(stream);
                }
                searchText = headerText;
                Text textPlaceHolder = null;
                // Insert image (the image created with your function) after text place holder.        
                // Search for text holder
                //Gets all the headers
                foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
                {
                    //Gets the text in headers
                    foreach (var currentText in headerPart.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
                    {
                        textPlaceHolder = headerPart.RootElement.Descendants<Text>()
                            .Where((x) => x.Text == searchText).First();
                    }
                }


                if (textPlaceHolder != null)
                {
                    var parent = textPlaceHolder.Parent;

                    if (parent is Run)  // Parent should be a run element.
                    {
                        //add image
                        Drawing imageElement = GetImageElement(
                            wordDoc.MainDocumentPart.GetIdOfPart(imagePart),
                            headerLogo,
                            "my image",
                            475,
                            245);
                        // Insert image (the image created with your function) after text place holder.        
                        textPlaceHolder.Parent.InsertAfter<Drawing>(imageElement, textPlaceHolder);
                        // Remove text place holder.
                        textPlaceHolder.Remove();
                    }
                }
            }

            #endregion
            string docText = null;
            using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
            {
                docText = sr.ReadToEnd();
            }

            Regex regexText = new Regex("&lt;COMPANY NAME&gt;");
            docText = regexText.Replace(docText, project.ClientName);

            //regexText = new Regex("&lt;COMPANY NAME&gt;");
            //docText = regexText.Replace(docText, project.ClientName);

            using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
            {
                sw.Write(docText);
            }

            //wordDoc.SaveAs(targetFileName).Close();
        }
    }

        private static Drawing GetImageElement(
        string imagePartId,
        string fileName,
        string pictureName,
        double width,
        double height)
    {
        double englishMetricUnitsPerInch = 914400;
        double pixelsPerInch = 96;

        //calculate size in emu
        double emuWidth = width * englishMetricUnitsPerInch / pixelsPerInch;
        double emuHeight = height * englishMetricUnitsPerInch / pixelsPerInch;

        var element = new Drawing(
            new A.Wordprocessing.Inline(
                new A.Wordprocessing.Extent { Cx = (Int64Value)emuWidth, Cy = (Int64Value)emuHeight },
                new A.Wordprocessing.EffectExtent { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
                new A.Wordprocessing.DocProperties { Id = (UInt32Value)1U, Name = pictureName },
                new A.Wordprocessing.NonVisualGraphicFrameDrawingProperties(
                new A.GraphicFrameLocks { NoChangeAspect = true }),
                new A.Graphic(
                    new A.GraphicData(
                        new A.Pictures.Picture(
                            new A.Pictures.NonVisualPictureProperties(
                                new A.Pictures.NonVisualDrawingProperties { Id = (UInt32Value)0U, Name = fileName },
                                new A.Pictures.NonVisualPictureDrawingProperties()),
                            new A.Pictures.BlipFill(
                                new A.Blip(
                                    new A.BlipExtensionList(
                                        new A.BlipExtension { Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}" }))
                                {
                                    Embed = imagePartId,
                                    CompressionState = A.BlipCompressionValues.Print
                                },
                                        new A.Stretch(new A.FillRectangle())),
                            new A.Pictures.ShapeProperties(
                                new A.Transform2D(
                                    new A.Offset { X = 0L, Y = 0L },
                                    new A.Extents { Cx = (Int64Value)emuWidth, Cy = (Int64Value)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"
            });
        return element;
    }

【问题讨论】:

    标签: c# replace openxml


    【解决方案1】:

    首先,这是我在 Word 文档中手动插入的图像 (Picture.png) 的标记。手动插入相同图像时,您是否检查了代码创建的标记与 Microsoft Word 创建的标记?这通常有助于发现标记中的错误(但并非总是如此,因为有多种“通向罗马的方式”,而且同一事物通常可以用多种方式表达)。例如,您可以使用 Open XML Productivity Tool 来比较这两个文档,并查看标记的差异以及创建正确标记所需的代码。

        <w:r>
          <w:rPr>
            <w:noProof/>
          </w:rPr>
          <w:drawing>
            <wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="787F9556" wp14:editId="6F9F029A">
              <wp:extent cx="4026107" cy="4019757"/>
              <wp:effectExtent l="0" t="0" r="0" b="0"/>
              <wp:docPr id="2" name="Picture 2" descr="A close up of a sign&#xA;&#xA;Description automatically generated"/>
              <wp:cNvGraphicFramePr>
                <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
              </wp:cNvGraphicFramePr>
              <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                  <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                    <pic:nvPicPr>
                      <pic:cNvPr id="2" name="Picture.png"/>
                      <pic:cNvPicPr/>
                    </pic:nvPicPr>
                    <pic:blipFill>
                      <a:blip r:embed="rId1">
                        <a:extLst>
                          <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
                            <a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
                          </a:ext>
                        </a:extLst>
                      </a:blip>
                      <a:stretch>
                        <a:fillRect/>
                      </a:stretch>
                    </pic:blipFill>
                    <pic:spPr>
                      <a:xfrm>
                        <a:off x="0" y="0"/>
                        <a:ext cx="4026107" cy="4019757"/>
                      </a:xfrm>
                      <a:prstGeom prst="rect">
                        <a:avLst/>
                      </a:prstGeom>
                    </pic:spPr>
                  </pic:pic>
                </a:graphicData>
              </a:graphic>
            </wp:inline>
          </w:drawing>
        </w:r>
    

    其次,下面的代码没有多大意义,因为您不需要foreach 循环。该循环获取w:hdr 的所有w:t 后代,但从不在循环主体中使用currentText

    foreach (var currentText in headerPart.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
    {
        textPlaceHolder = headerPart.RootElement.Descendants<Text>()
           .Where((x) => x.Text == searchText).First();
    }
    

    循环体就足够了。我只会使用 FirstOrDefault 并检查 null,除非您 100% 确定文本将存在于所有 (!) 标题中。

    【讨论】:

    • 我按照您的建议检查了数据,发现对图像的引用具有图像的完整路径(C:\Users\MyUser\Projects\MyProject\API\wwwroot\images\ImageName. gif),而我手动输入的只有图像名称本身......我将从那里开始工作,但有什么线索可以解释为什么会这样吗?
    • @HAC 检查原始文件:徽标是否链接回其原始文件? Word 可以将图形完全存储在文件中,或链接到文件,或两者兼而有之。当有文件链接时,如果文件内容发生变化(相同的文件路径和名称,但图片不同),则文档中显示的图片会发生变化。据我所知,那时将在文档中存储完整路径。
    • 这是问题所在... ImagePart imagePart = wordDoc.MainDocumentPart.AddImagePart(ImagePartType.Png);此行指定 MainDocumentPart,而我试图在标题中更改它...愚蠢的错误
    • 您是否按照建议使用生产力工具来识别这一点?我的回答有帮助吗?
    • 您的回答很有帮助,因为它向我展示了一个新工具。它无助于确定问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    相关资源
    最近更新 更多