需要将 MS-WORD 2003 或更低版本中的 MathType 方程转换为 MathML,以便在网络上很好地呈现。 MathType 的内置函数“Publish to MathPage”可以很好地完成这项工作,但我想将方程转换过程集成到我的 C# 应用程序中。由于我找不到MathType SDK提供的MathPage导出接口的API参考,所以我需要自己想办法进行单独的方程转换。
当前程序是将MS-WORD 2003或以下版本的文档转换为Open XML格式(docx)。 docx转换后,我可以看到MathType嵌入的ole对象二进制字符串保存在打开的xml中,这就是docx。那么下一步就是从嵌入的对象二进制字符串中解码MTEF数据,因此我尝试参考MathType MTEF header的官方文档来提取MTEF。
The Base64 二进制字符串 https://dl.dropbox.com/u/4625393/Base64.txt,表示由 MathType 创建的嵌入对象,提取自MS-WORD 测试 DOCX 文件 https://dl.dropbox.com/u/4625393/t1.docx.
MTEF 标头定义:
MTEF 数据保存为对象的本机数据格式。每当将方程对象写入 OLE“流”时,都会写入 28 字节标头,后跟 MTEF 数据。该头文件的 C 结构体如下:
struct EQNOLEFILEHDR {
WORD cbHdr; // length of header, sizeof(EQNOLEFILEHDR) = 28 bytes
DWORD version; // hiword = 2, loword = 0
WORD cf; // clipboard format ("MathType EF")
DWORD cbObject; // length of MTEF data following this header in bytes
DWORD reserved1; // not used
DWORD reserved2; // not used
DWORD reserved3; // not used
DWORD reserved4; // not used
};
cf 成员是调用 Windows API 函数 RegisterClipboardFormat("MathType EF") 的返回值。
然后我尝试将其转换为C#版本:
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct EQNOLEFILEHDR
{
public UInt16 cbHdr;
public UInt32 version;
public UInt16 format;
public UInt32 size;
public UInt32 reserved1;
public UInt32 reserved2;
public UInt32 reserved3;
public UInt32 reserved4;
}
标头结构准备就绪后,以下代码尝试从嵌入的对象二进制字符串填充标头结构中的信息。
foreach (EmbeddedObjectPart eop in wordDoc.MainDocumentPart.EmbeddedObjectParts)
{
Stream stream = eop.GetStream();
byte[] buffer = new byte[int.Parse(stream.Length.ToString())];
using (BinaryReader reader = new BinaryReader(stream))
{
int res = reader.Read(buffer, 0, int.Parse(stream.Length.ToString()));
}
GCHandle hdl = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr intp = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, intp, Marshal.SizeOf(typeof(EQNOLEFILEHDR)));
EQNOLEFILEHDR header = (EQNOLEFILEHDR)Marshal.PtrToStructure(intp, typeof(EQNOLEFILEHDR));
Marshal.FreeHGlobal(intp);
}
但是,标头结构中填充的数据不正确,使我认为这不是从 DOCX 文件中的嵌入对象二进制字符串解析 MTEF 数据的正确方法。
我还查看了MathType SDK下载中的示例.NET代码,发现IDataObject用于包含MathType信息和转换程序。所以另一种方法是使用BinaryFormatter
使用以下代码查看是否可以将二进制字符串反序列化为 IDataObject 类型对象BinaryFormatter.Deserialize(stream)
。但也不起作用,提示异常Binary stream '0' does not contain a valid BinaryHeader
我尝试用来解析 MTEF 数据的方法有什么问题吗?