iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >c# 基于wpf,怎么开发OFD电子文档阅读器
  • 227
分享到

c# 基于wpf,怎么开发OFD电子文档阅读器

2023-06-07 23:06:18 227人浏览 泡泡鱼
摘要

本篇内容介绍了“C# 基于WPF,怎么开发OFD电子文档阅读器”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言 OFD是国家标准

本篇内容介绍了“C# 基于WPF,怎么开发OFD电子文档阅读器”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

前言 

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

1 产权属于自主产权

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

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

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

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

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

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

ofd阅读器程序(已集成了转图、转PDF功能)下载。

  我最近一直研究ofd标准,试图写一款阅读器,已初有成果。具有ofd转换为pdf、转为图片等特色功能。界面如下:

c# 基于wpf,怎么开发OFD电子文档阅读器

c# 基于wpf,怎么开发OFD电子文档阅读器

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

OFD标准简介

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

c# 基于wpf,怎么开发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 = 0;      listBuffer.ForEach(o => totalLen += o.Length);      byte[] result = new byte[totalLen];      int index = 0;      foreach (byte[] buffer in listBuffer)      {        Buffer.BlockCopy(buffer, 0, result, index, buffer.Length);        index += buffer.Length;      }      return result;    }  }}

2 找到需要展示的page

  顺着路线 OFD.xml --> Document.xml --> Pages,找到最终需要展示的page页。Page页包含三类节点:PathObject、ImageObject,暨对应标准中的三类图元。需要对这三类节点建模。这三个类共同继承父类PageObject。所有的图元都有绘制区域、坐标变换、裁剪等共性,所有这些由PageObject类处理。

  public class PageObject  {    public string ID { get; set; }    public PageLayer ParentLayer { get; set; }    public string PageFileLoc => ParentLayer.ParentPage.PageFileLoc;    Xmlnode _xmlNode;    public string Boundary { get; set; }    public string CTM { get; set; }    public OfdClipsGroup ClipsGroup { get; set; }    public void SetPageObject(PageLayer layer, XmlNode xmlNode)    {      _xmlNode = xmlNode;      ID = XmlHelper.GetXmlAttributeValue(xmlNode, "ID");      ParentLayer = layer;      Boundary = XmlHelper.GetXmlAttributeValue(xmlNode, "Boundary");      CTM = XmlHelper.GetXmlAttributeValue(xmlNode, "CTM");      foreach (XmlNode childNode in xmlNode.ChildNodes)      {        if (childNode.Name == OfdClipsGroup.XML_Name)        {          ClipsGroup = OfdClipsGroup.FromXml(childNode);          break;        }      }    }    public string GetAttributeValue(string name)    {      string result = XmlHelper.GetXmlAttributeValue(_xmlNode, name);      return result;    }  }

3 创建WPF显示模型

图像精确定位需要用到canvas控件作为容器。绘制大量图形需要用到轻量级绘制模型DrawingVisual。在此基础上,派生了绘制基础模型OfdVisual,此模型对应PageObject。 

  public class OfdVisual : DrawingVisual  {    public OfdVisual()    {    }    protected DrawinGCanvas _drawingCanvas;    public DrawingCanvas DrawingCanvas    {      get      {        return _drawingCanvas;      }    }    public bool IsAddToCanvas    {      get      {        return _drawingCanvas != null;      }    }    internal void AddToCanvas(DrawingCanvas drawingCanvas)    {      if (_drawingCanvas == drawingCanvas)        return;      _drawingCanvas = drawingCanvas;      _drawingCanvas.AddVisual(this);    }    public void ReomveFromCanvas()    {      if (_drawingCanvas != null)      {        _drawingCanvas.DeleteVisual(this);      }    }    public virtual void Show(bool visiable, bool even = false)    {    }    public Point BoundaryLocation { get; set; }    public Size BoundarySize { get; set; }    public MatrixTransfORM ObjectTransform { get; protected set; }    public VisualClipsGroup ObjectClipsGroup { get; protected set; }    public void SetPageObject(PageObject pageObject)    {      OfdHelper.ParseBoundary(pageObject.Boundary, out Point location, out Size size);      BoundaryLocation = location;      BoundarySize = size;      if (!string.IsNullOrEmpty(pageObject.CTM))      {        ObjectTransform = OfdHelper.OfdTextToTransform(pageObject.CTM);      }      if (pageObject.ClipsGroup != null)      {        ObjectClipsGroup = new VisualClipsGroup() { ClipsGroup = pageObject.ClipsGroup };      }    }    protected Rect ClipRect    {      get      {        return new Rect(0, 0, BoundarySize.Width, BoundarySize.Height);      }    }    protected RectangleGeometry ClipGeometry    {      get      {        RectangleGeometry geometry = new RectangleGeometry(ClipRect);        return geometry;      }    }    protected void PutBoundary(DrawingContext dc)    {      TranslateTransform translateBoundary = new TranslateTransform(BoundaryLocation.X, BoundaryLocation.Y);      dc.PushTransform(translateBoundary);      dc.PushClip(ClipGeometry);    }    protected void PopBoundary(DrawingContext dc)    {      dc.Pop();      dc.Pop();    }    protected void PutTransform(DrawingContext dc)    {      if (ObjectTransform != null)      {        dc.PushTransform(ObjectTransform);      }    }    protected void PopTransform(DrawingContext dc)    {      if (ObjectTransform != null)      {        dc.Pop();      }    }  }

有三种类型绘制对象OfdVisualText、OfdVisualPath、OfdVisualImage,派生自OfdVisual。分别处理三种图元数据。所有的绘制操作在函数

public override void Show(bool visiable, bool even = false);

对应文本,绘制函数如下:

 void DrawText()    {      using (DrawingContext dc = RenderOpen())      {        if (ObjectClipsGroup == null)        {          PutBoundary(dc);          PutTransform(dc);          DrawTextInner(dc);          PopTransform(dc);          PopBoundary(dc);        }        else        {          foreach (VisulClip visulClip in ObjectClipsGroup)          {            PutBoundary(dc);            visulClip.PutClip(dc);            PutTransform(dc);            DrawTextInner(dc);            PopTransform(dc);            visulClip.PopClip(dc);            PopBoundary(dc);          }        }      }    }    private void DrawTextInner(DrawingContext dc)    {      int i = -1;      double deltaXTotal = 0;      double deltaYTotal = 0;      Point pt = new Point();      foreach (FormattedText formattedText in FormattedTextCollection)      {        i++;        if (i != 0)        {          if (DeltaCollectionX != null)          {            double deltaX = DeltaCollectionX.GetValue(i - 1);            deltaXTotal += deltaX;          }          if (DeltaCollectionY != null)          {            double deltaY = DeltaCollectionY.GetValue(i - 1);            deltaYTotal += deltaY;          }        }        pt.X = TextLocation.X + deltaXTotal;        pt.Y = TextLocation.Y + deltaYTotal - FormattedTextCollection.FontBaseLine;        dc.DrawText(formattedText, pt);      }    }

 绘制前,需要对当前坐标做变换、旋转、剪切等操作。

最近又对程序完善了,增加缩略图和公文索引

c# 基于wpf,怎么开发OFD电子文档阅读器

c# 基于wpf,怎么开发OFD电子文档阅读器

c# 基于wpf,怎么开发OFD电子文档阅读器

后记

编写阅读器类软件的关键是建模。首先读懂标准,对标准中描述的图元做归类分析,并建立起相应的显示模型。本人做WPF开发很多年了,感觉用WPF开发这类软件并不是非常的难。相比于QT,采用wpf开发有很多优势。如果要完整实现OFD标准,还需要大量的开发,我会逐步完善该软件的功能。

特别说明

ofd阅读器开发语言为c#,具有完全自主产权,没有使用第三方ofd开发包。可以根据你的需求快速定制开发。

“c# 基于wpf,怎么开发OFD电子文档阅读器”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: c# 基于wpf,怎么开发OFD电子文档阅读器

本文链接: https://www.lsjlt.com/news/250407.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作