gpt4 book ai didi

c# - 如何使用 OpenXml 2.0 将任何文件类型嵌入到 Microsoft Word 中

转载 作者:太空狗 更新时间:2023-10-29 18:11:24 25 4
gpt4 key购买 nike

我花了很多时间试图找到一种使用 OpenXml 2.0 将任何文件嵌入 Microsoft Word 的好方法; Office 文档相当简单,但其他文件类型(如 PDF、TXT、GIF、JPG、HTML 等)呢......

在 C# 中,什么是让它适用于任何文件类型的好方法?

最佳答案

使用 OpenXml 2.0 将外部对象(PDF、TXT、GIF 等)嵌入 Microsoft Word(嗯,与 COM 合作)

我从这个网站得到了很多,所以在这里我提出并回答了我自己的问题,以回馈一个我很难找到答案的话题,希望它能帮助人们。

有几个示例展示了如何使用 OpenXml 2.0 将一个 Office 文档嵌入到另一个 Office 文档中,但不存在且易于理解的是如何将几乎任何文件嵌入到 Office 文档中。

我从别人的代码中学到了很多东西,所以这是我的贡献。由于我已经在使用 OpenXml 生成文档,并且需要将其他文件嵌入到 Word 中,因此我决定使用 OpenXml 和 COM(Microsoft Office 2007 dll)的协作来实现我的目标。如果您像我一样,“调用 OLE 服务器应用程序来创建 IStorage”对您来说意义不大。

在这个例子中,我想展示我如何使用 COM 以编程方式获取附件的 OLE 二进制数据信息,然后我如何在我的 OpenXml 文档中使用该信息。基本上,我以编程方式查看 OpenXml 2.0 Document Reflector 以获取我需要的信息。

我下面的代码被分解成几个类,但这里是我正在做的事情的大纲:

  1. 创建一个 OpenXml WordProcessingDocument,获取要嵌入的文件的 System.IO.FileInfo
  2. 创建自定义 OpenXmlEmbeddedObject 对象(这是保存所有二进制数据的对象)
  3. 使用上述步骤中的二进制数据创建数据流和图像流
  4. 将这些流用作 OpenXml 文档的文件对象和文件图像

我知道有很多代码,但解释不多......希望它很容易理解并能帮助人们 

要求:• DocumentFormat.OpenXml dll (OpenXml 2.0)• WindowsBase dll• Microsoft.Office.Interop.Word dll(Office 2007 – 版本 12)

• 这是开始一切的主类,打开一个 WordProcessingDocument 和类以附加文件

using DocumentFormat.OpenXml.Packaging;
using System.IO;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;

public class MyReport
{
private MainDocumentPart _mainDocumentPart;

public void CreateReport()
{
using (WordprocessingDocument wpDocument = WordprocessingDocument.Create(@"TempPath\MyReport.docx", WordprocessingDocumentType.Document))
{
_mainDocumentPart = wpDocument.AddMainDocumentPart();
_mainDocumentPart.Document = new Document(new Body());

AttachFile(@"MyFilePath\MyFile.pdf", true);
}
}

private void AttachFile(string filePathAndName, bool displayAsIcon)
{
FileInfo fileInfo = new FileInfo(filePathAndName);

OpenXmlHelper.AppendEmbeddedObject(_mainDocumentPart, fileInfo, displayAsIcon);
}
}

• OpenXml 帮助程序类中的此类包含将对象嵌入到 OpenXml 文件中的所有逻辑

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;
using DocumentFormat.OpenXml.Wordprocessing;
using OVML = DocumentFormat.OpenXml.Vml.Office;
using V = DocumentFormat.OpenXml.Vml;

public class OpenXmlHelper
{
/// <summary>
/// Appends an Embedded Object into the specified Main Document
/// </summary>
/// <param name="mainDocumentPart">The MainDocument Part of your OpenXml Word Doc</param>
/// <param name="fileInfo">The FileInfo object associated with the file being embedded</param>
/// <param name="displayAsIcon">Whether or not to display the embedded file as an Icon (Otherwise it will display a snapshot of the file)</param>
public static void AppendEmbeddedObject(MainDocumentPart mainDocumentPart, FileInfo fileInfo, bool displayAsIcon)
{
OpenXmlEmbeddedObject openXmlEmbeddedObject = new OpenXmlEmbeddedObject(fileInfo, displayAsIcon);

if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleObjectBinaryData))
{
using (Stream dataStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleObjectBinaryData)))
{
if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleImageBinaryData))
{
using (Stream emfStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleImageBinaryData)))
{
string imagePartId = GetUniqueXmlItemID();
ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Emf, imagePartId);

if (emfStream != null)
{
imagePart.FeedData(emfStream);
}

string embeddedPackagePartId = GetUniqueXmlItemID();

if (dataStream != null)
{
if (openXmlEmbeddedObject.ObjectIsOfficeDocument)
{
EmbeddedPackagePart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedPackagePart>(
openXmlEmbeddedObject.FileContentType, embeddedPackagePartId);
embeddedObjectPart.FeedData(dataStream);
}
else
{
EmbeddedObjectPart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedObjectPart>(
openXmlEmbeddedObject.FileContentType, embeddedPackagePartId);
embeddedObjectPart.FeedData(dataStream);
}
}

if (!displayAsIcon && !openXmlEmbeddedObject.ObjectIsPicture)
{
Paragraph attachmentHeader = CreateParagraph(String.Format("Attachment: {0} (Double-Click to Open)", fileInfo.Name));
mainDocumentPart.Document.Body.Append(attachmentHeader);
}

Paragraph embeddedObjectParagraph = GetEmbeededObjectParagraph(openXmlEmbeddedObject.FileType,
imagePartId, openXmlEmbeddedObject.OleImageStyle, embeddedPackagePartId);

mainDocumentPart.Document.Body.Append(embeddedObjectParagraph);
}
}
}
}
}

/// <summary>
/// Gets Paragraph that includes the embedded object
/// </summary>
private static Paragraph GetEmbeededObjectParagraph(string fileType, string imageID, string imageStyle, string embeddedPackageID)
{
EmbeddedObject embeddedObject = new EmbeddedObject();

string shapeID = GetUniqueXmlItemID();
V.Shape shape = new V.Shape() { Id = shapeID, Style = imageStyle };
V.ImageData imageData = new V.ImageData() { Title = "", RelationshipId = imageID };

shape.Append(imageData);
OVML.OleObject oleObject = new OVML.OleObject()
{
Type = OVML.OleValues.Embed,
ProgId = fileType,
ShapeId = shapeID,
DrawAspect = OVML.OleDrawAspectValues.Icon,
ObjectId = GetUniqueXmlItemID(),
Id = embeddedPackageID
};

embeddedObject.Append(shape);
embeddedObject.Append(oleObject);

Paragraph paragraphImage = new Paragraph();

Run runImage = new Run(embeddedObject);
paragraphImage.Append(runImage);

return paragraphImage;
}

/// <summary>
/// Gets a Unique ID for an XML Item, for reference purposes
/// </summary>
/// <returns>A GUID string with removed dashes</returns>
public static string GetUniqueXmlItemID()
{
return "r" + System.Guid.NewGuid().ToString().Replace("-", "");
}

private static Paragraph CreateParagraph(string paragraphText)
{
Paragraph paragraph = new Paragraph();
ParagraphProperties paragraphProperties = new ParagraphProperties();

paragraphProperties.Append(new Justification()
{
Val = JustificationValues.Left
});

paragraphProperties.Append(new SpacingBetweenLines()
{
After = Convert.ToString(100),
Line = Convert.ToString(100),
LineRule = LineSpacingRuleValues.AtLeast
});

Run run = new Run();
RunProperties runProperties = new RunProperties();

Text text = new Text();

if (!String.IsNullOrEmpty(paragraphText))
{
text.Text = paragraphText;
}

run.Append(runProperties);
run.Append(text);

paragraph.Append(paragraphProperties);
paragraph.Append(run);

return paragraph;
}

}

• 这是此过程中最重要的部分,它使用 Microsoft 的内部 OLE 服务器,为文件创建二进制数据和二进制 EMF 信息。您在这里所要做的就是调用 OpenXmlEmbeddedObject 构造函数,所有这些都将得到处理。它将模拟您手动将任何文件拖到 Word 中时发生的过程;执行此操作时会进行某种转换,将文件转换为 OLE 对象,以便 Microsoft 可以识别该文件。o 此类最重要的部分是 OleObjectBinaryData 和 OleImageBinaryData 属性;它们包含文件数据和“.emf”图像的 64 位字符串二进制信息。o 如果您选择不将文件显示为图标,则“.emf”图像数据将创建文件的快照,例如 pdf 文件的第一页,您仍然可以在其中双击打开o 如果您要嵌入图像并选择不将其显示为图标,则 OleObjectBinaryData 和 OleImageBinaryData 属性将相同

using System.Runtime.InteropServices;
using System.Xml;
using System.Diagnostics;
using System.IO;
using System.Drawing;
using Microsoft.Office.Interop.Word;

public class OpenXmlEmbeddedObject
{
#region Constants

private const string _defaultOleContentType = "application/vnd.openxmlformats-officedocument.oleObject";
private const string _oleObjectDataTag = "application/vnd";
private const string _oleImageDataTag = "image/x-emf";

#endregion Constants

#region Member Variables

private static FileInfo _fileInfo;
private static string _filePathAndName;
private static bool _displayAsIcon;
private static bool _objectIsPicture;

private object _objectMissing = System.Reflection.Missing.Value;
private object _objectFalse = false;
private object _objectTrue = true;

#endregion Member Variables

#region Properties

/// <summary>
/// The File Type, as stored in Registry (Ex: a GIF Image = 'giffile')
/// </summary>
public string FileType
{
get
{
if (String.IsNullOrEmpty(_fileType) && _fileInfo != null)
{
_fileType = GetFileType(_fileInfo, false);
}

return _fileType;
}
}
private string _fileType;

/// <summary>
/// The File Context Type, as storered in Registry (Ex: a GIF Image = 'image/gif')
/// * Is converted into the 'Default Office Context Type' for non-office files
/// </summary>
public string FileContentType
{
get
{
if (String.IsNullOrEmpty(_fileContentType) && _fileInfo != null)
{
_fileContentType = GetFileContentType(_fileInfo);

if (!_fileContentType.Contains("officedocument"))
{
_fileContentType = _defaultOleContentType;
}
}

return _fileContentType;
}
}
private string _fileContentType;

/// <summary>
/// Gets the ContentType Text for the file
/// </summary>
public static string GetFileContentType(FileInfo fileInfo)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}

string mime = "application/octetstream";

string ext = System.IO.Path.GetExtension(fileInfo.Name).ToLower();

Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);

if (rk != null && rk.GetValue("Content Type") != null)
{
mime = rk.GetValue("Content Type").ToString();
}

return mime;
}

public bool ObjectIsOfficeDocument
{
get { return FileContentType != _defaultOleContentType; }
}

public bool ObjectIsPicture
{
get { return _objectIsPicture; }
}

public string OleObjectBinaryData
{
get { return _oleObjectBinaryData; }
set { _oleObjectBinaryData = value; }
}
private string _oleObjectBinaryData;

public string OleImageBinaryData
{
get { return _oleImageBinaryData; }
set { _oleImageBinaryData = value; }
}
private string _oleImageBinaryData;

/// <summary>
/// The OpenXml information for the Word Application that is created (Make-Shoft Code Reflector)
/// </summary>
public string WordOpenXml
{
get { return _wordOpenXml; }
set { _wordOpenXml = value; }
}
private String _wordOpenXml;

/// <summary>
/// The XmlDocument that is created based on the OpenXml Data from WordOpenXml
/// </summary>
public XmlDocument OpenXmlDocument
{
get
{
if (_openXmlDocument == null && !String.IsNullOrEmpty(WordOpenXml))
{
_openXmlDocument = new XmlDocument();
_openXmlDocument.LoadXml(WordOpenXml);
}

return _openXmlDocument;
}
}
private XmlDocument _openXmlDocument;

/// <summary>
/// The XmlNodeList, for all Nodes containing 'binaryData'
/// </summary>
public XmlNodeList BinaryDataXmlNodesList
{
get
{
if (_binaryDataXmlNodesList == null && OpenXmlDocument != null)
{
_binaryDataXmlNodesList = OpenXmlDocument.GetElementsByTagName("pkg:binaryData");
}

return _binaryDataXmlNodesList;
}
}
private XmlNodeList _binaryDataXmlNodesList;

/// <summary>
/// Icon Object for the file
/// </summary>
public Icon ObjectIcon
{
get
{
if (_objectIcon == null)
{
_objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName);
}

return _objectIcon;
}
}
private Icon _objectIcon;

/// <summary>
/// File Name for the Icon being created
/// </summary>
public string ObjectIconFile
{
get
{
if (String.IsNullOrEmpty(_objectIconFile))
{
_objectIconFile = String.Format("{0}.ico", _filePathAndName.Replace(".", ""));
}

return _objectIconFile;
}
}
private string _objectIconFile;

/// <summary>
/// Gets the original height and width of the emf file being created
/// </summary>
public string OleImageStyle
{
get
{
if (String.IsNullOrEmpty(_oleImageStyle) && !String.IsNullOrEmpty(WordOpenXml))
{
XmlNodeList xmlNodeList = OpenXmlDocument.GetElementsByTagName("v:shape");
if (xmlNodeList != null && xmlNodeList.Count > 0)
{
foreach (XmlAttribute attribute in xmlNodeList[0].Attributes)
{
if (attribute.Name == "style")
{
_oleImageStyle = attribute.Value;
}
}
}
}

return _oleImageStyle;
}

set { _oleImageStyle = value; }
}
private string _oleImageStyle;

#endregion Properties

#region Constructor

/// <summary>
/// Generates binary information for the file being passed in
/// </summary>
/// <param name="fileInfo">The FileInfo object for the file to be embedded</param>
/// <param name="displayAsIcon">Whether or not to display the file as an Icon (Otherwise it will show a snapshot view of the file)</param>
public OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon)
{
_fileInfo = fileInfo;
_filePathAndName = fileInfo.ToString();
_displayAsIcon = displayAsIcon;

SetupOleFileInformation();
}

#endregion Constructor

#region Methods

/// <summary>
/// Creates a temporary Word App in order to add an OLE Object, get's the OpenXML data from the file (similar to the Code Reflector info)
/// </summary>
private void SetupOleFileInformation()
{
Microsoft.Office.Interop.Word.Application wordApplication = new Microsoft.Office.Interop.Word.Application();

Microsoft.Office.Interop.Word.Document wordDocument = wordApplication.Documents.Add(ref _objectMissing, ref _objectMissing,
ref _objectMissing, ref _objectMissing);

object iconObjectFileName = _objectMissing;
object objectClassType = FileType;
object objectFilename = _fileInfo.ToString();

Microsoft.Office.Interop.Word.InlineShape inlineShape = null;

if (_displayAsIcon)
{
if (ObjectIcon != null)
{
using (FileStream iconStream = new FileStream(ObjectIconFile, FileMode.Create))
{
ObjectIcon.Save(iconStream);
iconObjectFileName = ObjectIconFile;
}
}

object objectIconLabel = _fileInfo.Name;

inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType,
ref objectFilename, ref _objectFalse, ref _objectTrue, ref iconObjectFileName,
ref _objectMissing, ref objectIconLabel, ref _objectMissing);
}
else
{
try
{
Image image = Image.FromFile(_fileInfo.ToString());
_objectIsPicture = true;
OleImageStyle = String.Format("height:{0}pt;width:{1}pt", image.Height, image.Width);

wordDocument.InlineShapes.AddPicture(_fileInfo.ToString(), ref _objectMissing, ref _objectTrue, ref _objectMissing);
}
catch
{
inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType,
ref objectFilename, ref _objectFalse, ref _objectFalse, ref _objectMissing, ref _objectMissing,
ref _objectMissing, ref _objectMissing);
}
}

WordOpenXml = wordDocument.Range(ref _objectMissing, ref _objectMissing).WordOpenXML;

if (_objectIsPicture)
{
OleObjectBinaryData = GetPictureBinaryData();
OleImageBinaryData = GetPictureBinaryData();
}
else
{
OleObjectBinaryData = GetOleBinaryData(_oleObjectDataTag);
OleImageBinaryData = GetOleBinaryData(_oleImageDataTag);
}

// Not sure why, but Excel seems to hang in the processes if you attach an Excel file…
// This kills the excel process that has been started < 15 seconds ago (so not to kill the user's other Excel processes that may be open)
if (FileType.StartsWith("Excel"))
{
Process[] processes = Process.GetProcessesByName("EXCEL");
foreach (Process process in processes)
{
if (DateTime.Now.Subtract(process.StartTime).Seconds <= 15)
{
process.Kill();
break;
}
}
}

wordDocument.Close(ref _objectFalse, ref _objectMissing, ref _objectMissing);
wordApplication.Quit(ref _objectMissing, ref _objectMissing, ref _objectMissing);
}

/// <summary>
/// Gets the binary data from the Xml File that is associated with the Tag passed in
/// </summary>
/// <param name="binaryDataXmlTag">the Tag to look for in the OpenXml</param>
/// <returns></returns>
private string GetOleBinaryData(string binaryDataXmlTag)
{
string binaryData = null;
if (BinaryDataXmlNodesList != null)
{
foreach (XmlNode xmlNode in BinaryDataXmlNodesList)
{
if (xmlNode.ParentNode != null)
{
foreach (XmlAttribute attr in xmlNode.ParentNode.Attributes)
{
if (String.IsNullOrEmpty(binaryData) && attr.Value.Contains(binaryDataXmlTag))
{
binaryData = xmlNode.InnerText;
break;
}
}
}
}
}

return binaryData;
}

/// <summary>
/// Gets the image Binary data, if the file is an image
/// </summary>
/// <returns></returns>
private string GetPictureBinaryData()
{
string binaryData = null;
if (BinaryDataXmlNodesList != null)
{
foreach (XmlNode xmlNode in BinaryDataXmlNodesList)
{
binaryData = xmlNode.InnerText;
break;
}
}

return binaryData;
}

/// <summary>
/// Gets the file type description ("Application", "Text Document", etc.) for the file.
/// </summary>
/// <param name="fileInfo">FileInfo containing extention</param>
/// <returns>Type Description</returns>
public static string GetFileType(FileInfo fileInfo, bool returnDescription)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}

string description = "File";
if (string.IsNullOrEmpty(fileInfo.Extension))
{
return description;
}
description = string.Format("{0} File", fileInfo.Extension.Substring(1).ToUpper());
RegistryKey typeKey = Registry.ClassesRoot.OpenSubKey(fileInfo.Extension);
if (typeKey == null)
{
return description;
}
string type = Convert.ToString(typeKey.GetValue(string.Empty));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(type);
if (key == null)
{
return description;
}

if (returnDescription)
{
description = Convert.ToString(key.GetValue(string.Empty));
return description;
}
else
{
return type;
}
}

#endregion Methods
}

关于c# - 如何使用 OpenXml 2.0 将任何文件类型嵌入到 Microsoft Word 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3322247/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com