首页 > 解决方案 > Openxml将docx与图像合并

问题描述

简而言之:我想在另一个 docx 中插入包含图像和项目符号的 docx 的内容。

我的问题:我使用了两种方法:

  1. 手动合并
  2. 替代块

结果,我得到了一个损坏的word文档。如果我从 docx 中删除要插入另一个图像的图像,则结果 docx 是可以的。

我的代码:

手动合并(感谢https://stackoverflow.com/a/48870385/10075827):

private static void ManualMerge(string firstPath, string secondPath, string resultPath)
  {
     if (!System.IO.Path.GetFileName(firstPath).StartsWith("~$"))
     {

        File.Copy(firstPath, resultPath, true);

        using (WordprocessingDocument result = WordprocessingDocument.Open(resultPath, true))
        {
           using (WordprocessingDocument secondDoc = WordprocessingDocument.Open(secondPath, false))
           {  
              OpenXmlElement p = result.MainDocumentPart.Document.Body.Descendants<Paragraph>().Last();

              foreach (var e in secondDoc.MainDocumentPart.Document.Body.Elements())
              {
                 var clonedElement = e.CloneNode(true);

                 clonedElement.Descendants<DocumentFormat.OpenXml.Drawing.Blip>().ToList().ForEach(blip =>
                 {
                    var newRelation = result.CopyImage(blip.Embed, secondDoc);
                    blip.Embed = newRelation;
                 });

                 clonedElement.Descendants<DocumentFormat.OpenXml.Vml.ImageData>().ToList().ForEach(imageData =>
                 {
                    var newRelation = result.CopyImage(imageData.RelationshipId, secondDoc);
                    imageData.RelationshipId = newRelation;
                 });


                 result.MainDocumentPart.Document.Body.Descendants<Paragraph>().Last();

                 if (clonedElement is Paragraph)
                 {
                    p.InsertAfterSelf(clonedElement);
                    p = clonedElement;
                 }
              }
           }
        }
     }
  }

public static string CopyImage(this WordprocessingDocument newDoc, string relId, WordprocessingDocument org)
  {
     var p = org.MainDocumentPart.GetPartById(relId) as ImagePart;
     var newPart = newDoc.MainDocumentPart.AddPart(p);
     newPart.FeedData(p.GetStream());
     return newDoc.MainDocumentPart.GetIdOfPart(newPart);
  }

Altchunk 合并(来自http://www.karthikscorner.com/sharepoint/use-altchunk-document-assembly/):

private static void AltchunkMerge(string firstPath, string secondPath, string resultPath)
  {
     WordprocessingDocument mainDocument = null;
     MainDocumentPart mainPart = null;
     var ms = new MemoryStream();


     #region Prepare - consuming application
     byte[] bytes = File.ReadAllBytes(firstPath);
     ms.Write(bytes, 0, bytes.Length);

     mainDocument = WordprocessingDocument.Open(ms, true);
     mainPart = mainDocument.MainDocumentPart;

     #endregion


     #region Document to be imported
     FileStream fileStream = new FileStream(secondPath, FileMode.Open);
     #endregion

     #region Merge
     AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, "AltChunkId101");
     chunk.FeedData(fileStream);
     var altChunk = new AltChunk(new AltChunkProperties() { MatchSource = new MatchSource() { Val = new OnOffValue(true) } });
     altChunk.Id = "AltChunkId101";      

     mainPart.Document.Body.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
     mainPart.Document.Save();
     #endregion

     #region Mark dirty
     var listOfFieldChar = mainPart.Document.Body.Descendants<FieldChar>();
     foreach (FieldChar current in listOfFieldChar)
     {
        if (string.Compare(current.FieldCharType, "begin", true) == 0)
        {
           current.Dirty = new OnOffValue(true);
        }
     }
     #endregion

     #region Save Merged Document
     mainPart.DocumentSettingsPart.Settings.PrependChild(new UpdateFieldsOnOpen() { Val = new OnOffValue(true) });
     mainDocument.Close();

     FileStream file = new FileStream(resultPath, FileMode.Create, FileAccess.Write);
     ms.WriteTo(file);
     file.Close();
     ms.Close();
     #endregion
  }

我花了几个小时寻找解决方案,我发现最常见的解决方案是使用 altchunk。那么为什么它在我的情况下不起作用?

标签: c#imagemergeopenxmldocx

解决方案


如果您能够使用Microsoft.Office.Interop.Word命名空间,并且能够在要合并的文件中放置书签,则可以采用以下方法:

using Microsoft.Office.Interop.Word;

...

// merge by putting second file into bookmark in first file
private static void NewMerge(string firstPath, string secondPath, string resultPath, string firstBookmark)
{
    var app = new Application();
    var firstDoc = app.Documents.Open(firstPath);
    var bookmarkRange = firstDoc.Bookmarks[firstBookmark];

    // Collapse the range to the end, as to not overwrite it. Unsure if you need this
    bookmarkRange.Collapse(WdCollapseDirection.wdCollapseEnd);

    // Insert into the selected range
    // use if relative path
    bookmarkRange.InsertFile(Environment.CurrentDirectory + secondPath);

    // use if absolute path
    //bookmarkRange.InsertFile(secondPath);
}

有关的:

C#:使用 Office 互操作库在 word 文档中的书签处插入和缩进项目符号点


推荐阅读