前言 OFD是国家标准版式文档格式,于2016年生效。OFD文档国家标准参见《电子文件存储与交换格式版式文档》。既然是国家标准,OFD随后肯定会首先在政务系统使用,并逐步推向社会各个方面。OFD是在研究当下各类文件格式后,推出的标准,有如下优点:

1 产权属于自主产权

2 具有便携性:文件小,可压缩比率大。测试显示生成的文件体量比PDF还要小。

3 具有开放性:易于入门,对于使用者来说更具开放性。

4 具有扩展性:预留了可扩展入口和自定义标引,设置了非接触式引用机制,为特性化提供支持。

5 呈现效果与设备无关,在各种设备上阅读、打印或印刷时,版面固定、不跑版。

6 应用广泛:无论是电子商务、电子公务,还是信息发布、文件交换,档案管理等都需要版式文档的技术支持。

  关于标准,我也要吐槽一下。OFD标准是国内几家专业的电子文档处理公司参与起草的;标准文档(注:以下用”标准”特指OFD标准)只有126页,在我看来,标准对技术细节的描述过于简单,没有一定的技术背景很难看懂。与此形成鲜明对比的是pdf标准,有1000多页。我在网上也没找到文字版的标准,特别不利于阅读和参考。

  我最近一直研究ofd标准,试图写一款阅读器,已初有成果,界面如下:

阅读器下载地址: https://download.csdn.net/download/qq_29939347/11799156

 

 本文就把我开发的过程做简单介绍。

OFD标准简介

  简而言之,OFD存储是采用压缩技术,描述采用XML格式。这一点与微软的word文档(docx)格式很类似。标准可能参考了微软的处理方式;在技术上也要实事求是,国标这种格式不是独创和领先的。将OFD格式文件解压后,会看到如下目录和文件:

 

文件中会包括资源文件(图片、字体库等)。XML会对资源存放,图元(文字、图像等)显示做描述,阅读软件会根据这些描述呈现出一致的显示效果。

 

开发OFD阅读软件步骤

  国内流行的ofd阅读软件应该是福昕和数科开发的,这两款我都用过。我还要吐槽一下:

  1)福昕阅读器帮助文档是ofd格式,但是无法用数科的阅读器打开。

  2)有些ofd文档中xml标记,在标准中找不到,是某些公司独创的?

  这些软件都是用C++开发的,用到了QT。同样情况下,相比于C#,C++开发软件难度肯定会大增。在windows平台开发界面,WPF应该是最好的库了。WPF虽然出现十几年了,大家好像对此还很陌生。主要现在是BS的天下;不是WPF不够好,是生不逢时。

1 对OFD文件解压缩

  OFD文件其实就是压缩文件,解压后的文件也有目录结构。该模块的功能是获取每个文件的路径和数据。

复制代码
using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq;  namespace WpfOfdReader.OfdFileType {     class OfdFileReader     {         ZipArchive _zipArchive;         public void ReadZipFile(string fileName)         {             _zipArchive = ZipFile.OpenRead(fileName);         }          public void Close()         {             if (_zipArchive != null)                 _zipArchive.Dispose();         }          public List<OfdFileItemInfo> AllFileItem         {             get             {                 return _zipArchive.Entries.Select(o => new OfdFileItemInfo(o)).ToList();             }         }          private ZipArchiveEntry GetArchiveEntry(ZipFilePath path)         {             foreach (ZipArchiveEntry entry in _zipArchive.Entries)             {                 if (entry.FullName == path.FulleName)                 {                     return entry;                 }             }             return null;         }          public static byte[] GetFileBuffer(ZipArchiveEntry entry)         {             List<byte[]> listBuffer = new List<byte[]>();             using (Stream s = entry.Open())             {                 while (true)                 {                     byte[] buffer = new byte[10];                     int n = s.Read(buffer, 0, buffer.Length);                     if (n <= 0)                         break;                      if (n == buffer.Length)                     {                         listBuffer.Add(buffer);                     }                     else                     {                         Array.Resize(ref buffer, n);                         listBuffer.Add(buffer);                         break;                     }                 }             }              int totalLen =