libharu 原始碼解析-SRC

Ding-yixia發表於2024-06-06

libharu 原始碼解析-SRC

t4.h

提供的程式碼片段是CCITT T.4一維霍夫曼遊程編碼處理的C/C++實現的一部分,這種編碼在傳真傳輸和影像壓縮中常見,尤其是在TIFF(標記影像檔案格式)檔案中。這段程式碼定義了兩個陣列(`HPDF_TIFFFaxWhiteCodes` 和 `HPDF_TIFFFaxBlackCodes`),它們包含了白色和黑色遊程的霍夫曼碼及其長度和對應的遊程長度。

以下是關鍵元件的分解:

### 前處理器指令和宏

- `#ifndef _T4_` 和 `#define _T4_`:這些是防止在多個原始檔中多次包含此檔案時使用的前處理器指令,作為包含保護。
- `#ifdef G3CODES`:這個條件編譯指令檢查`G3CODES`是否被定義。如果定義了,則將編譯霍夫曼碼錶的實際程式碼;否則,它將使用對錶的外部引用。

### 資料結構和常量

- `tableentry`:一個結構體,定義霍夫曼碼條目的組成部分:
  - `length`:程式碼的位長度。
  - `code`:霍夫曼碼本身。
  - `runlen`:該程式碼代表的遊程長度(以位元為單位)。

- `EOL`:表示行結束碼值的常量。
- 狀態值如`G3CODE_EOL`、`G3CODE_INVALID`、`G3CODE_EOF`和`G3CODE_INCOMP`被定義來表示解碼過程中的特殊情形或錯誤。

### 霍夫曼碼錶

- `HPDF_TIFFFaxWhiteCodes` 和 `HPDF_TIFFFaxBlackCodes`:這兩個是`tableentry`結構的陣列,定義了白色和黑色遊程的霍夫曼碼。每個條目對應一個特定的遊程長度,片段中顯示了前幾個示例條目。

### 條件編譯

- 根據`G3CODES`是否定義,霍夫曼表的實際程式碼將被包含在編譯中,或者將使用對這些表的外部引用。

這段程式碼片段對於任何處理使用CCITT T.4壓縮的TIFF影像或傳真資料的軟體來說都是至關重要的部分,提供了將壓縮資料解碼回其原始形式所需的資料結構和常量。

### 附加說明

- 這些霍夫曼碼錶按照特定順序排列,使得可以透過遊程長度或(遊程長度除以64)加上固定偏移量直接索引到表中。
- 表格中的`G3CODE_INVALID`條目僅在狀態生成期間使用(參見mkg3states.c)。

總之,這段程式碼是TIFF影像或傳真資料中CCITT T.4壓縮資料解碼的關鍵部分,確保可以正確地從壓縮流中恢復原始影像資訊。

這段程式碼涉及到的是CCITT T.4標準下的一維霍夫曼編碼(Huffman coding),它是TIFF檔案格式中用於黑白影像壓縮的一種方法。讓我們更深入地理解一下這段程式碼是如何幫助解碼壓縮的TIFF影像資料的:

1. 霍夫曼編碼原理

霍夫曼編碼是一種可變長度的字首編碼技術,它的核心思想是給出現頻率高的符號較短的編碼,而給出現頻率低的符號較長的編碼。這樣可以有效地減少資料的總編碼長度,從而實現壓縮。

在CCITT T.4標準中,霍夫曼編碼被用於表示連續的黑色或白色畫素的“遊程”(run)。例如,連續的16個白色畫素會被編碼成一個特定的二進位制序列,而不是分別編碼每一個畫素。

2. 程式碼中的霍夫曼碼錶

在程式碼片段中,HPDF_TIFFFaxWhiteCodesHPDF_TIFFFaxBlackCodes 是霍夫曼碼錶,它們儲存了每個遊程對應的霍夫曼碼、碼長和遊程長度。例如,HPDF_TIFFFaxWhiteCodes[0]runlen 是 2,表示這個碼代表的是長度為2的白色遊程;length 是 3,表示這個霍夫曼碼由3位組成;code 是 0,即這個霍夫曼碼是 000

3. 解碼過程

當解碼一個使用CCITT T.4標準壓縮的TIFF影像時,解碼器會讀取壓縮流中的霍夫曼碼,並查詢相應的遊程長度。解碼器通常會維護一個當前讀取到的位的位置,並且會嘗試匹配霍夫曼碼錶中的碼字。

  • 解碼器從流中讀取位元,並構建一個臨時的碼字。
  • 它將這個碼字與霍夫曼碼錶中的碼字比較,直到找到一個匹配。
  • 當找到匹配時,解碼器就會知道這個碼字所代表的遊程長度,並在影像中放置相應數量的黑色或白色畫素。
  • 解碼器然後更新讀取位置,繼續解碼下一個霍夫曼碼。

4. EOL 和 EOF

除了遊程編碼之外,EOLEOF 是特殊的碼字,分別表示“行結束”和“檔案結束”。這些碼字幫助解碼器管理影像的邊界和壓縮流的結束。

總結

透過使用霍夫曼編碼和精心設計的碼錶,TIFF影像中的連續畫素遊程可以被高效地編碼和解碼,從而實現資料的壓縮和恢復。這段程式碼正是實現這一功能的關鍵所在,它確保了壓縮流可以被正確解析,恢復出原始影像的資訊。


hpdf_array.c

這段程式碼是Haru Free PDF Library的一部分,專門用於處理PDF中的陣列物件。以下是對主要函式的解釋:

1. `HPDF_Array_New`: 建立一個新的PDF陣列物件。函式首先分配記憶體空間用於儲存`HPDF_Array`結構體,初始化結構體成員,建立一個連結串列用於存放陣列元素,最後返回新建立的陣列物件指標。

2. `HPDF_Box_Array_New`: 建立一個用於儲存矩形框(四個浮點數:左、底、右、頂座標)的PDF陣列物件。首先呼叫`HPDF_Array_New`建立陣列物件,然後向陣列中新增四個`HPDF_Real`型別的物件,分別表示矩形的四個座標。

3. `HPDF_Array_Free`: 釋放一個PDF陣列物件。函式先清除陣列中的所有元素,釋放連結串列,再釋放陣列物件自身佔用的記憶體。

4. `HPDF_Array_Write`: 將PDF陣列物件寫入到PDF流中。遍歷陣列中的所有元素,將它們轉換為PDF文字格式並寫入流中,最後寫入結束標誌`']'`。

5. `HPDF_Array_AddNumber`, `HPDF_Array_AddReal`, `HPDF_Array_AddNull`, `HPDF_Array_AddName`: 向PDF陣列中新增不同型別的物件。首先建立指定型別的新物件,然後呼叫`HPDF_Array_Add`將物件加入陣列。

6. `HPDF_Array_Add`: 新增任意物件到PDF陣列中。檢查物件有效性,判斷物件型別是否允許直接擁有,以及陣列容量是否已滿。如果物件是間接物件,建立代理物件並加入陣列。否則,直接加入陣列。

7. `HPDF_Array_Items`: 返回陣列中的元素個數。

8. `HPDF_Array_Insert`: 在陣列中插入一個物件在指定目標物件之前。如果找不到目標物件,則不執行插入操作。

9. `HPDF_Array_GetItem`: 獲取陣列中指定索引處的物件,同時檢查物件的類是否符合預期。

10. `HPDF_Array_Clear`: 清空陣列中的所有元素。遍歷陣列,釋放每個元素佔用的記憶體,清空連結串列。

這些函式共同實現了PDF陣列物件的建立、操作和銷燬,是PDF檔案生成和處理的重要元件。

hpdf_binary

`hpdf_binary.c` 是 Haru Free PDF Library 中的一部分,用於處理 PDF 檔案中的二進位制資料。以下是該檔案中關鍵函式的解釋:

1. `HPDF_Binary_New`: 這個函式用於建立一個新的二進位制物件。它接收一個記憶體管理器 (`mmgr`) 和指向二進位制資料的指標 (`value`) 及其長度 (`len`)。首先,它分配記憶體來儲存 `HPDF_Binary_Rec` 結構體,並初始化結構體的成員。接著,它使用 `HPDF_Binary_SetValue` 函式設定二進位制資料的值。如果設定失敗,它會釋放先前分配的記憶體並返回 `NULL`。

2. `HPDF_Binary_Write`: 這個函式用於將二進位制物件寫入到 PDF 流中。如果二進位制資料長度為0,它將寫入 `<>` 到流中;否則,它先寫入 `<` 字元,然後透過 `HPDF_Stream_WriteBinary` 寫入二進位制資料,最後寫入 `>` 字元。如果提供了加密物件 `e`,則資料在寫入前會被加密。

3. `HPDF_Binary_SetValue`: 用於設定或更新二進位制物件的資料。它首先檢查資料長度是否超過限制,如果是,則返回錯誤。如果當前有資料,它會釋放這些資料。然後,它分配新的記憶體來儲存傳入的二進位制資料,並複製資料。如果記憶體分配失敗,返回錯誤程式碼。

4. `HPDF_Binary_Free`: 用於釋放二進位制物件。它首先檢查物件是否存在,然後釋放與物件關聯的二進位制資料,最後釋放二進位制物件本身佔用的記憶體。

5. `HPDF_Binary_GetLen` 和 `HPDF_Binary_GetValue`: 這兩個函式分別用於獲取二進位制物件的長度和值。

整體而言,`hpdf_binary.c` 提供了建立、寫入、讀取、更新和釋放 PDF 文件中的二進位制資料的能力,這是生成和操作 PDF 檔案時處理影像、字型或其他二進位制資源的關鍵部分。

hpdf_boolean

`hpdf_boolean.c` 檔案是 Haru Free PDF Library 的一部分,主要負責 PDF 檔案中布林型別資料的處理。下面是這個檔案中兩個關鍵函式的解析:

1. `HPDF_Boolean_New`: 這個函式用於建立一個新的布林物件。它接收一個記憶體管理器 (`mmgr`) 和一個布林值 (`value`) 作為引數。首先,它嘗試從記憶體管理器分配足夠的記憶體來儲存一個 `HPDF_Boolean_Rec` 結構體。如果分配成功,它初始化這個結構體的物件頭(`header`),將其物件類設定為 `HPDF_OCLASS_BOOLEAN` 並將傳入的布林值賦給 `value` 成員。如果分配失敗,函式將返回 `NULL`。

2. `HPDF_Boolean_Write`: 這個函式用於將布林物件寫入 PDF 流中。它接收一個布林物件 (`obj`) 和一個流物件 (`stream`)。根據布林物件的值,它呼叫 `HPDF_Stream_WriteStr` 函式向流中寫入 `"true"` 或 `"false"`。函式返回寫入操作的狀態碼。

這兩個函式一起提供了建立和寫入 PDF 檔案中布林型別的機制。布林值在 PDF 中可以用於控制文件的各種屬性或狀態,例如頁面的顯示模式、註解的可見性等。透過 `HPDF_Boolean_New` 建立布林物件後,可以使用 `HPDF_Boolean_Write` 將其寫入 PDF 文件的相應位置。

需要注意的是,Haru Library 使用內部的記憶體管理機制,這在 `HPDF_Boolean_New` 中透過 `HPDF_GetMem` 函式呼叫來體現。同時,錯誤處理和資源管理(如記憶體釋放)通常由更高層次的函式或庫使用者負責。

hpdf_catalog.c

`hpdf_catalog.c` 檔案是 Haru Free PDF Library 的一部分,用於處理 PDF 文件中的目錄(Catalog)物件。目錄物件是 PDF 檔案的根物件,包含文件的所有高階屬性和結構。下面是對關鍵函式的解釋:

1. **HPDF_Catalog_New**: 建立一個新的目錄物件。它接收一個記憶體管理器 (`mmgr`) 和一個交叉引用表 (`xref`)。函式首先建立一個字典物件,設定其為目錄子類,然後將其新增到交叉引用表中。之後,它新增必要的元素,如型別(`Type`)和頁面樹(`Pages`)。

2. **HPDF_Catalog_GetRoot**: 獲取目錄中的頁面樹。它從目錄物件中提取 `Pages` 鍵的值,該值應為頁面樹物件。

3. **HPDF_Catalog_GetNames / HPDF_Catalog_SetNames**: 分別用於獲取和設定目錄中的名稱字典,該字典用於儲存文件中的命名專案。

4. **HPDF_Catalog_GetPageLayout / HPDF_Catalog_SetPageLayout**: 獲取和設定文件的頁面佈局。頁面佈局決定了文件在開啟時的預設顯示方式,如單頁、雙頁、連續或並排顯示。

5. **HPDF_Catalog_GetPageMode / HPDF_Catalog_SetPageMode**: 獲取和設定文件的頁面模式。頁面模式決定了文件在開啟時的初始檢視,如使用大綱、縮圖或全屏模式。

6. **HPDF_Catalog_SetOpenAction**: 設定文件的開啟動作。這可以是一個目的地,當文件開啟時,將自動跳轉到該目的地。

7. **HPDF_Catalog_Validate**: 檢查目錄物件的有效性,確保其物件類正確無誤。

8. **HPDF_Catalog_AddPageLabel**: 向目錄的頁面標籤陣列中新增一個頁面標籤。頁面標籤允許為文件中的頁面提供自定義標籤,如羅馬數字或字母。

9. **HPDF_Catalog_SetViewerPreference / HPDF_Catalog_GetViewerPreference**: 分別用於設定和獲取檢視器偏好設定,包括隱藏工具欄、選單欄、視窗UI,以及適應視窗大小、居中視窗和列印縮放選項。

這些函式協同工作,使開發者能夠控制和配置 PDF 文件的高階特性,如頁面佈局、開啟行為和檢視器設定,以滿足具體的應用需求。

相關文章