需要将 MS-WORD 2003 或更低版本中的 MathType 方程转换为 MathML,以便在 Web 上很好地呈现。MathType 的内置函数“Publish to MathPage”可以很好地完成这项工作,但我想将方程转换过程集成到我的 C# 应用程序中。因为我找不到任何关于 MathPage 导出接口是由 MathType SDK 提供的 API 引用,所以我需要自己想办法进行单独的方程转换。
当前的程序是将 MS-WORD 2003 或以下文档转换为 Open XML 格式(docx)。docx转换后可以看到打开的xml中保存了MathType嵌入的ole对象二进制字符串,也就是docx。然后下一步是从嵌入对象二进制字符串中解码MTEF数据,所以我尝试通过参考MathType MTEF标头的官方文档来提取MTEF。
代表 MathType 创建的嵌入对象的base64 二进制字符串是从MS-WORD 测试 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 数据的方法有什么问题吗?