從PDF到OFD,國產化浪潮下多種文件格式匯出的完美解決方案

葡萄城技术团队發表於2024-07-03

前言

近年來,中國在資訊科技領域持續追求自主創新和供應鏈安全,伴隨信創上升為國家戰略,一些行業也開始明確要求檔案匯出的格式必須為 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:發展歷程與應用前景解析

相關文章