c#实现ofd文件转图片功能 (附执行程序)

前言 ofd文件的作用就是保证信息能如实的存储、传递、显示。保证ofd文件的真实性靠的是签名;ofd 的显示需要专用软件。ofd标准是新的国家标准,应用范围远不如pdf;现有浏览器不能解析ofd、支持ofd显示的软件也寥寥无几。ofd转图片程序下载。

    专用软件读取ofd过程包括对ofd文件解压缩、分析每页的文字和图元、关联对应的资源、解析签章等复杂操作。将ofd文件转成图片,可以避免这些重复的操作;ofd转成图片后,就可以方便的在浏览器、各类app中显示。所以,ofd转图片是ofd系统中必不可少的一个功能。

ofd转图片实现思路

  ofd转图片没有捷径可走。实现ofd转图片,就是在图片上输出文字、图元、各类曲线等,这些操作和输出到屏幕上并没有多大区别。ofd转图片和ofd阅读器在技术上是有很大重合的。要完成ofd转图片,需要你对ofd文件有充分的理解。参见我的文章《采用WPF技术,开发OFD电子文档阅读器》。

  本文ofd转图片功能没用到wpf相关类,而是使用了System.Drawing暨GDI+。.net core 3.0 已经实现了System.Drawing;理论上,本文所涉及的代码可以很方便的移植到.net core下,在linux下实现ofd转图只有一步之遥。

实现ofd转图片包括以下几个步骤:

1 创建ofd页面信息模型

ofd页面由文本、图片、曲线等组成。首先将页面解析成各类object,它们的父类为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;
        }

    }

从此类派生出 PageObjectText、PageObjectPath、PageObjectImage等,代表ofd页面文本、曲线、图片等类型信息。

2 由信息模型PageObject 创建显示模型OfdVisual;

信息模型包含了显示需要的各类信息,显示模型就是利用这类信息显示。显示模型的父类为OfdVisual:

  public class OfdVisual
    {
        public OfdVisual()
        {
        }

        public virtual void Show(bool visiable, bool even = false)
        {

        }

        public virtual void ShowSelect(bool visiable, Rectangle selectRegion, bool even = false)
        {

        }

        public PointF BoundaryLocation { get; set; }
        public SizeF BoundarySize { get; set; }

        public Matrix ObjectTransform { get; protected set; }

        public Graphics VisualGraphics { get; set; }

        public PageObject PageObject { get; protected set; }
        public string PageItemId
        {
            get
            {
                if (PageObject == null)
                    return string.Empty;
                return PageObject.ID;
            }
        }public PointF ToPageLocation(PointF pt)
        {
            return new PointF(pt.X + BoundaryLocation.X, pt.Y + BoundaryLocation.Y);
        }

        protected void PutBoundary()
        {
            VisualGraphics.TranslateTransform(BoundaryLocation.X, BoundaryLocation.Y);
            VisualGraphics.SetClip(ClipRect);
        }

        GraphicsState graphicsState;

        protected void DrawSave()
        {
            graphicsState = VisualGraphics.Save();
        }

        protected void DrawRestore()
        {
            VisualGraphics.Restore(graphicsState);
        }

        protected void PutTransform()
        {
            if (ObjectTransform != null)
            {
                VisualGraphics.MultiplyTransform(ObjectTransform);
            }
        }

        public double XZoomRate
        {
            get
            {
                if (ObjectTransform == null)
                    return 1;

                float result = ObjectTransform.Elements[0];
                return result;
            }
        }

        public double YZoomRate
        {
            get
            {
                if (ObjectTransform == null)
                    return 1;

                float result = ObjectTransform.Elements[4];
                return result;
            }
        }

    }

有三类显示模型OfdVisualText、OfdVisualImage、OfdVisualPath等。

3 创建bitmap

根据页面大小创建bitmap,由bitmap获取Graphics。后面的显示操作就是利用Graphics各类函数处理。

_ofdBitmap = new Bitmap((int)(width* scale), (int)(height* scale));

Graphics = Graphics.FromImage(_ofdBitmap);

 ofd转图片程序功能说明

   操作步骤:选择生成图片的缩放比例,点击“ofd转图片”按钮,选择ofd文件。转成图片后,ofd文件在左侧列表显示,点击列表中文件,右侧显示对应的图片。程序底部为日志,显示ofd文件的页数、转换耗时等信息。

为了方便别的程序调用,程序可以做成web 服务形式,对外接口为web api。客户端传入ofd文件,输出为图片。

后记 对于ofd转图片,网上有一种方法是采用虚拟打印。这是一种捷径,也是没有办法的办法。但是采用虚拟打印,必须依赖第三方ofd阅读器,使用不方便,输出效果也增加了不确定性。要实现ofd转图片,必须对ofd标准吃透,建立相应显示模型,按部就班的实现转图功能;只有这样,程序的功能才是自主可控、效率采有保证。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用第三方库iTextSharp来将OFD文件换成PDF文件。首先需要将OFD文件解压缩,然后将解压缩后的XML文件换成PDF文件。 以下是一个示例代码: ```csharp using iTextSharp.text; using iTextSharp.text.pdf; using System.IO; using System.Xml; public static void ConvertOFDToPDF(string ofdFilePath, string pdfFilePath) { // 解压缩OFD文件 string tempFolderPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(tempFolderPath); ZipFile.ExtractToDirectory(ofdFilePath, tempFolderPath); // 获取OFD文档的页面尺寸 string documentXmlPath = Path.Combine(tempFolderPath, "Documents", "Document.xml"); XmlDocument documentXml = new XmlDocument(); documentXml.Load(documentXmlPath); XmlNamespaceManager nsManager = new XmlNamespaceManager(documentXml.NameTable); nsManager.AddNamespace("ofd", "http://www.ofdspec.org"); XmlNode pageAreaNode = documentXml.SelectSingleNode("/ofd:Document/ofd:Pages/ofd:PageArea", nsManager); float pageWidth = float.Parse(pageAreaNode.Attributes["PageWidth"].Value); float pageHeight = float.Parse(pageAreaNode.Attributes["PageHeight"].Value); // 创建PDF文档 using (FileStream pdfFileStream = new FileStream(pdfFilePath, FileMode.Create)) { using (Document pdfDocument = new Document(new Rectangle(pageWidth, pageHeight))) { using (PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, pdfFileStream)) { pdfDocument.Open(); // 遍历OFD文档的页面,将每个页面换成PDF页面 XmlNodeList pageNodes = documentXml.SelectNodes("/ofd:Document/ofd:Pages/ofd:Page", nsManager); foreach (XmlNode pageNode in pageNodes) { string pageFileNodeValue = pageNode.Attributes["BaseLoc"].Value; string pageFilePath = Path.Combine(tempFolderPath, pageFileNodeValue); using (FileStream pageFileStream = new FileStream(pageFilePath, FileMode.Open)) { using (MemoryStream pageMemoryStream = new MemoryStream()) { pageFileStream.CopyTo(pageMemoryStream); byte[] pageBytes = pageMemoryStream.ToArray(); // 将OFD页面换成PDF页面 using (MemoryStream pdfMemoryStream = new MemoryStream()) { using (Document pageDocument = new Document()) { using (PdfWriter pdfPageWriter = PdfWriter.GetInstance(pageDocument, pdfMemoryStream)) { pageDocument.Open(); using (MemoryStream pageXmlStream = new MemoryStream(pageBytes)) { XmlDocument pageXml = new XmlDocument(); pageXml.Load(pageXmlStream); XmlNode pageContentNode = pageXml.SelectSingleNode("/ofd:Page/ofd:Content", nsManager); string pageContent = pageContentNode.InnerXml; using (MemoryStream pageContentStream = new MemoryStream()) { using (StreamWriter pageContentWriter = new StreamWriter(pageContentStream)) { pageContentWriter.Write(pageContent); pageContentWriter.Flush(); pageContentStream.Position = 0; XmlParserContext xmlParserContext = new XmlParserContext(null, nsManager, null, XmlSpace.None); XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); xmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment; using (XmlReader xmlReader = XmlReader.Create(pageContentStream, xmlReaderSettings, xmlParserContext)) { while (xmlReader.Read()) { if (xmlReader.NodeType == XmlNodeType.Element) { string elementName = xmlReader.Name; if (elementName == "ofd:TextObject") { string fontId = xmlReader.GetAttribute("Font"); string fontSizeString = xmlReader.GetAttribute("Size"); float fontSize = float.Parse(fontSizeString); string fontFamily = null; XmlNode fontNode = documentXml.SelectSingleNode($"/ofd:Document/ofd:Fonts/ofd:Font[@ID='{fontId}']", nsManager); if (fontNode != null) { fontFamily = fontNode.Attributes["FontName"].Value; } if (string.IsNullOrEmpty(fontFamily)) { fontFamily = "宋体"; } BaseFont baseFont = BaseFont.CreateFont($"{fontFamily},Bold", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, fontSize); string text = xmlReader.ReadElementContentAsString(); pdfDocument.Add(new Paragraph(text, font)); } else if (elementName == "ofd:PathObject") { // 处理OFD路径对象 } else if (elementName == "ofd:ImageObject") { // 处理OFD图像对象 } } } } } } } pageDocument.Close(); } } byte[] pdfBytes = pdfMemoryStream.ToArray(); PdfReader pdfReader = new PdfReader(pdfBytes); pdfWriter.DirectContent.AddTemplate(pdfWriter.GetImportedPage(pdfReader, 1), 0, 0); } } } } pdfDocument.Close(); } } } Directory.Delete(tempFolderPath, true); } ``` 请注意,这段代码只是一个示例,可能需要根据你的具体情况进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值