简体   繁体   English

OpenXML将DOCX与图像合并

[英]Openxml merging docx with images

In short: I would like to insert the content of a docx that contains images and bullets in another docx. 简而言之:我想在另一个docx中插入包含图像和项目符号的docx的内容。

My problem: I used two approaches: 我的问题:我使用了两种方法:

  1. Manual merge 手动合并
  2. Altchunk Altchunk

With both of them I got a corrupted word document as result. 有了它们,我得到了损坏的Word文档。 If I remove the images from the docx that I would like to insert in another one, the result docx is OK. 如果我要从docx中删除要插入另一张图像的图像,则结果docx可以。

My code: 我的代码:

Manual merge (thanks to https://stackoverflow.com/a/48870385/10075827 ): 手动合并(由于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 merge (from http://www.karthikscorner.com/sharepoint/use-altchunk-document-assembly/ ): 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
  }

I spent hours searching for a solution and the most common one I found was to use altchunk. 我花了几个小时寻找解决方案,而最常见的解决方案是使用altchunk。 So why is it not working in my case? 那为什么在我的情况下不起作用?

If you are able to use the Microsoft.Office.Interop.Word namespace, and able to put a bookmark in the file you want to merge into, you can take this approach: 如果您能够使用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);
}

Related: 有关:

C#: Insert and indent bullet points at bookmark in word document using Office Interop libraries C#:使用Office Interop库在Word文档中的书签处插入并缩进项目符号点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM