c# - Openxml将docx与图像合并
问题描述
简而言之:我想在另一个 docx 中插入包含图像和项目符号的 docx 的内容。
我的问题:我使用了两种方法:
- 手动合并
- 替代块
结果,我得到了一个损坏的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。那么为什么它在我的情况下不起作用?
解决方案
如果您能够使用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);
}
有关的:
推荐阅读
- php - 如何在本地安装ubuntu下的adminer?
- reactjs - TypeScript 中 react-router-dom 的匹配类型
- scroll - Adobe Analytics - 滚动深度跟踪
- c# - 使用 c# 自动化测试 Selenium
- r - 是否有函数可以找到一组行的累积总和/滚动总和
- python-3.x - 将点连接到 matplotlib 散点图中的中心
- flutter - 覆盖抽象类 Dart 中的最终属性
- python - 根据条件关闭 Python 中的任务
- python - 使用python从Web应用程序标准化json输出分析的最佳方法是什么?
- python - Sample_weights Keras 模型 - IndexError:数组索引过多