前言

近年来,中国在信息技术领域持续追求自主创新和供应链安全,伴随信创上升为国家战略,一些行业也开始明确要求文件导出的格式必须为 OFD 格式。OFD 格式目前在政府、金融、税务、教育、医疗等需要文件开放、共享和长期保存的行业中广泛应用。这种趋势在未来几年内将进一步增强。

相较于 PDF,OFD 在以下方面展现了明显的优势,具体体现在:

  • 开放性

PDF 是 Adobe 公司开发的专有格式,虽然也被广泛应用,但受制于 Adobe 公司的软件和许可。OFD 则是基于国际开放标准制定的开放式文档格式,任何人或组织都可以自由使用和开发相关软件。

  • 功能特性

PDF 主要用于文档展示和打印,功能较为单一。OFD 在文档展示、打印、编辑等方面都有更强大的功能支持。

  • 文件大小

PDF 文件通常会略大于 OFD 文件,因为 PDF 包含更多的元数据和功能,OFD 文件在保持良好的视觉效果的前提下,通常体积更小。

  • 兼容性

PDF 虽然跨平台性强,但在不同软件和系统中的表现可能会有差异,OFD 则具有更好的跨平台一致性。

  • 安全性

PDF 文件可能包含隐藏的功能和潜在的安全隐患,OFD 则更加透明,安全性更高。

如何将 PDF 转化为 OFD?

既然导出 OFD 格式如此重要,然而目前市面上的报表工具,前端导出时通常只支持 PDF 格式。那么在这种情况下,如何实现一键在前端将报表导出为 OFD 格式呢?今天,小编将以葡萄城的嵌入式 BI 工具——Wyn 商业智能作为例子,向大家介绍如何将 PDF 转换为 OFD 格式。

首先小编先带大家一起了解下OFD文件解析的底层原理:

OFD 文件底层结构:

OFD 文件采用XML作为其基本结构,这意味着文件内容是以文本形式存储的,便于编辑和搜索。OFD 文件主要由以下几个部分组成:

  1. 文档头(Document Header):包含文档的基本信息,如标题、作者、创建日期等。
  2. 文档体(Document Body):包含文档的实际内容,如文字、图片、表格等。
  3. 资源文件(Resource Files):包括文档中使用到的图片、字体、样式等资源。
  4. 元数据(Metadata):提供有关文档内容的额外信息,如关键词、摘要等。

PDF 转换为 OFD 的流程:

首先,通过使用 Wyn 报表工具,可以轻松设计出符合需求的报表样式。这些报表样式可以包含各种元素,例如表格、图表、图片、文本、超链接等等。设计完成后,可以直接在 Web 端进行预览,同时还支持将报表导出为PDF 格式。这样的设计流程和功能使得报表的创建和预览变得更加便捷和直观。

前端支持 PDF 导出只是第一步,为了实现从 PDF 转换为 OFD,还需要前端提供导出 PDF 的 API 接口,以便前端能够获取到 PDF 文件的流数据。幸运的是,Wyn 提供了丰富的 API 接口,使得前端可以通过接口直接实现PDF 的导出功能。这样的设计使得 PDF 转换为 OFD 变得更加便捷和可行。

PDF 转 OFD 的实现步骤

前端导出PDF文件的API接口:

http://localhost:51980/api/v2/reporting/export-templates/{exportTemplateId}

后端进行PDF文件解析的方法

  1. 继承 PDFGraphicsStreamEngine 类,便于分析 PDF 数据图层和资源归类
public class OFDPageDrawer extends PDFGraphicsStreamEngine {

}
  1. 重写构造方法,分析 PDF 每页的资源,并初始化 OFD 生成器
/**
构造器,调用super(page),这个操作的目的是将page资源准备好,并且添加对应的操作符,
当下一次调用processPage或者processPageContentStream时执行对应的操作符对应的操作
@param idx
@param page
@param ofdCreator
@param scale
@throws IOException
*/
protected OFDPageDrawer(int idx, PDPage page, OFDCreator ofdCreator, float scale)
throws IOException {
super(page);
this.page = page;
this.ofdCreator = ofdCreator;
ctLayer = this.ofdCreator.createLayer();
this.scale = scale;
}
  1. 重写 drawImage 方法收集整理 PDF 中分析出来的图片资源
/**
作用:将 PDF 图像对象转换为 OFD 格式进行绘制。此方法包括:
*
将图像写入字节流并保存。
根据当前变换矩阵计算图像在页面上的位置和大小。
创建 OFD 图像对象并设置其相关属性,然后添加到当前层中。
*
@param pdImage
@throws IOException
*/
@Override
public void drawImage(PDImage pdImage) throws IOException {
ByteArrayOutputStream bosImage = new ByteArrayOutputStream();
String suffix = "png";
ImageIO.write(pdImage.getImage(), suffix, bosImage);
String name = String.format("%s.%s", bcMD5(bosImage.toByteArray()), suffix);
ofdCreator.putImage(name, bosImage.toByteArray(), suffix); // 根据当前变换矩阵计算图像在页面上的位置和大小,实际上就是将PDF中该图像的属性信息转换成OFD中的形式
Matrix ctmNew = this.getGraphicsState().getCurrentTransformationMatrix();
float imageXScale = ctmNew.getScalingFactorX();
float imageYScale = ctmNew.getScalingFactorY();
double x = ctmNew.getTranslateX() * scale;
double y = (page.getCropBox().getHeight() - ctmNew.getTranslateY() - imageYScale) * scale;
double w = imageXScale * scale;
double h = imageYScale * scale;
ImageObject imageObject = new ImageObject(ofdCreator.getNextRid());
imageObject.setBoundary(x, y, w, h);
imageObject.setResourceID(new ST_RefID(ST_ID.getInstance(ofdCreator.getImageMap().get(name))));
imageObject.setCTM(ST_Array.getInstance(String.format("%.0f 0 0 %.0f 0 0", w, h)));
setImageClip(imageObject, x, y, w, h);
ctLayer.add(imageObject);
}
  1. 通过继承 PDFGraphicsStreamEngine 类分析得到的文字内容重绘
public void addPageContent(int idx, CT_Layer ctLayer, float width, float height) {
PageDir pageDirInv = new PageDir();// 资源归类
pageDirInv.setIndex(idx);
org.ofdrw.core.basicStructure.pageObj.Page pageInv = new org.ofdrw.core.basicStructure.pageObj.Page();
CT_PageArea areaInv = new CT_PageArea();// ofd可视区域(PDF的裁剪区)
areaInv.setPhysicalBox(0, 0, width, height);
pageInv.setArea(areaInv);
Content contentInv = new Content();// 内容
contentInv.addLayer(ctLayer);
pageInv.setContent(contentInv);
pageDirInv.setContent(pageInv);
docDir.getPages().add(pageDirInv);
}
  1. 将收集到的资源进行打包生成 OFD 文件
/**
打包OFD文件包二进制数据
*
@param virtualFileMap
@return
@throws IOException
*/
public static void zip(Map<String, byte[]> virtualFileMap,OutputStream output) throws IOException {
ZipArchiveOutputStream zaos = new ZipArchiveOutputStream(output); for (Map.Entry<String, byte[]> entry : virtualFileMap.entrySet()) {
zaos.putArchiveEntry(new ZipArchiveEntry(entry.getKey()));
zaos.write(entry.getValue());
zaos.closeArchiveEntry();
} zaos.finish();
}

最终效果展示:

完整代码的链接:

GcExcelTestArea.rar

总结

在当今时代,对于国产化的支持,OFD(Office Open XML for Developers)变得越来越重要。本文首先介绍了OFD 文件的底层结构,并阐述了 OFD 相对于 PDF 的优势。接着,介绍如何通过葡萄城的嵌入式 BI 工具——Wyn 商业智能,进行报表设计和导出 PDF 。同时,还展示了如何使用 Wyn 商业智能的 API 接口将 PDF 转换为 OFD,除此之外,在企业级复杂系统中,除了 OFD 之外,Wyn还同时支持Word、Excel、图片、Text、JSON等多种格式的导出。

通过本文的介绍,我们可以清楚地看到,将 PDF 转换为 OFD 不再是一个困扰。借助 Wyn 强大的功能和丰富的 API 接口支持,能够轻松高效地实现文档格式转换。这一解决方案为用户提供了便捷、灵活的操作方式,满足了行业对 OFD 格式的要求。

扩展链接:

创意展示:打造数据大屏的炫酷天气预报插件

聊一聊数字孪生与3D可视化

探秘移动端BI:发展历程与应用前景解析

从PDF到OFD,国产化浪潮下多种文档格式导出的完美解决方案的更多相关文章

  1. 【原】中文Ubuntu主目录下的文档文件夹改回英文

    想把中文Ubuntu主目录下的文档文件夹改回英文,在Terminal下面操作的时候要输入中文特别不方便,于是便用了更改名字的想法 方法一: 首先把那几个中文名称修改成相应的英文,比如 Desktop. ...

  2. QJsonDocument实现Qt下JSON文档读写

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QJsonDocument实现Qt下JSON文档读写     本文地址:http://tech ...

  3. 教你用java统计目录下所有文档的词频

    本文是统计目录下所有文档的词频top10,非单个文档,包含中文和英文. 直接上代码: package com.huawei.wordcount; import java.io.BufferedRead ...

  4. 利用altium怎么生成PDF及怎么1:1打印文档

    画完板子之后,还要生成原理图PDF文档,供其他设计人员参考和指正. 上图红框标注的两个地方,分别用于打印预览设置和生成原理图PDF.那么若是生成原理图PDF文档,则选择smart PDF即可. 点击s ...

  5. Linux下实现文档在线浏览

    使用php实现百度文库功能,网上搜索到的方案,实现doc转pdf,pdf转swf,然后显示出来. 这里简单的记录下,[doc转pdf,pdf转swf]两个功能的搭建流程. doc转pdf 使用到下列程 ...

  6. vim下处理文档中的\r\n\t字符

    问题复现 拿到的文档中包含了大量的\r.\n.\t等字符,形如: \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\ ...

  7. ubuntu打开windows下txt文档乱码问题的解决

    昨天晚上安装了Ubuntu11.10,打开TXT文件的时候发现中文乱码问题,在网上查了一下,一些网友提供了下面的方法: “按Alt+F2,打开“运行应用程序”对话框,输入“gconf-editor”, ...

  8. EPICS Archiver Appliance在Debian11下安装文档

    本文很想标注转发,可是要转发链接,只好标注原创. 首先声明:本文档是合肥光源控制组孙晓康博士踩坑后整理的.我尝试过在Debian11和Rocky下安装,碰到坎过不去,这段时间各种事就没继续了,请教晓康 ...

  9. Jasperreports以及iReport4.5报表PDF导出字体完美解决方案

    在使用Jasperreports以及iReport设计报表时,导出PDF是一个常见的需求.网上解决PDF导出中文显示问题相关的文章很多,无非就是设置控件的pdf font name和pdf encod ...

  10. (转)Ctrl+H 浪潮Raid配置文档

    说明 本手册适用于LSI芯片Raid卡 包括但不限于Inspur 2008/2108 Raid卡.LSI 9240/9260/9261/9271 等Raid卡. 不同型号的Raid卡在某些功能上的支持 ...

随机推荐

  1. Competition Set - Codeforces

    这里记录的是这个账号的比赛情况. Codeforces Round 942 (Div. 1) Solved:6/8,AB1B2CDE1 2645-> A 题意:现有 \(a_i\) 张写有 \( ...

  2. 【动画进阶】巧用 CSS/SVG 实现复杂线条光效动画

    最近,群里在讨论一个很有意思的线条动画效果,效果大致如下: 简单而言,就是线条沿着不规则路径的行进动画,其中的线条动画可以理解为是特殊的光效. 本文,我们将一起探索,看看在不使用 JavaScript ...

  3. Swift实现判断目录下是否存在指定文件功能

    本文主要讲解以下这段名为 isDataJsonFilePathExists 的私有函数的 Swift 代码实现细节,该函数的作用是检查指定文件或文件夹是否存在,其返回值类型为 Bool 类型,如果存在 ...

  4. Golang 爬虫01

    目录 学习地址: 目录站: 爬虫概念: 工作流程: 百度贴吧爬虫实现: go实战代码 单进程 实现过程: 并发爬取 实现过程: 学习地址: https://www.bilibili.com/video ...

  5. C语言:实现数组的删除和增加

    /*      删除方法:     如:12  32  56  84  95     用覆盖的方法     若删除第三个,则第四个要覆盖第三个,第五个要覆盖第四个     覆盖完:12  32  84 ...

  6. 2022年官网下安装ActiveMQ最全版与官网查阅方法

    目录 一.环境整合 构建工具(参考工具部署方式) 二.下载安装 1.百度搜索ActiveMQ,双击进入.或访问官网https://activemq.apache.org/ 2.进入下载界面,两种方式, ...

  7. C 语言编程 — 变量与常量

    目录 文章目录 目录 前文列表 变量与常量 变量 变量的类型 变量的声明 变量的定义 变量的初始化与赋值 常量 整型常量 浮点型常量 字符型场景 字符串常量 符号常量 作用域 存储类 auto 修饰符 ...

  8. 国产系统UOS安装体验

    原文链接 https://www.giantliu.cn/2020/09/04/200904InstallUOS/ UOS简介 统信桌面操作系统(Uniontech OS)个人正式版是统信软件基于Li ...

  9. ShardingJDBC使用不当引发的线上事故

    本文讲述一个由 ShardingJDBC 使用不当引起的悲惨故事. 一. 问题重现 有一天运营反馈我们部分订单状态和第三方订单状态无法同步. 根据现象找到了不能同步订单状态是因为 order 表的 t ...

  10. golang kmp算法实现

    // 不多逼逼直接上代码.原理的话可以参考下面的链接.讲的非常清晰package main import "fmt" func genNext(s string) []int { ...