處理紙本文件時,您需要找出並更正錯誤或刻意做出的變更。使用 Document Comparison API 可快速且有效地找出這些變更。
此情境用於比較特別重要的文件 (例如合約和銀行文件) 及其副本。比較結果包含內容類型 (僅文字) 、修改類型 (刪除、插入或修改) ,以及它們在原件和副本中的位置資訊。您可以取得偵測到的差異清單,或任何變更所在的區域,並將比較結果儲存至外部檔案,以便後續處理或長期保存。
若要比較文件或頁面,透過掃描取得或以電子格式儲存的檔案通常會經過數個處理階段,而每個階段都有各自的特性:
已掃描檔案或影像的預處理
如果檔案及其副本包含某些瑕疵或刻意加入的標記,例如簽名或印章,則在辨識前需要先進行一些預處理。
透過完整還原文件結構與格式進行辨識
辨識文件時,會識別文件中的各種版面元素 (文字、表格、影像、分隔線等) 。在文件合成過程中,會還原文件的邏輯結構,而頁面合成則可完整還原文件格式 (字型、樣式等) 。
文件或頁面比較
若要將文件或頁面與其副本進行比較,請使用經 ABBYY FineReader Engine 辨識的檔案。您可以使用同一份文件的兩個不同格式版本。比較完成後,您會取得包含變更清單的結果,並可利用該結果擷取變更位置資訊。若您使用人工驗證,可利用這些資訊在文字中標示變更,讓操作員更容易完成工作。
匯出為外部格式
您也可以將比較結果儲存為 XML 和 DOCX 格式。
下方所述程序也可參考 Linux 與 macOS 的 Document Comparison 範例,以及 Windows 的 Document Comparison 示範工具。
本主題中提供的程式碼範例僅適用於 Windows。
以下將詳細介紹在此情境中使用 ABBYY FineReader Engine 的建議方式。
步驟 1. 載入 ABBYY FineReader Engine
若要開始使用 ABBYY FineReader Engine,您需要建立 Engine 物件。Engine 物件是 ABBYY FineReader Engine 物件階層中的最上層物件,可提供各種全域設定、部分處理方法,以及建立其他物件的方法。 若要建立 Engine 物件,您可以使用 InitializeEngine 函式。另請參閱 載入 Engine 物件的其他方式 (Win) 。 public class EngineLoader : IDisposable
{
public EngineLoader ()
{
// 使用 FREngine.dll 的完整路徑、您的 Customer Project ID,
// 以及(如適用)線上授權權杖檔案的路徑和線上授權密碼來初始化這些變數
string enginePath = "" ;
string customerProjectId = "" ;
string licensePath = "" ;
string licensePassword = "" ;
// 載入 FREngine.dll 程式庫
dllHandle = LoadLibraryEx ( enginePath , IntPtr . Zero , LOAD_WITH_ALTERED_SEARCH_PATH );
try
{
if ( dllHandle == IntPtr . Zero )
{
throw new Exception ( "Can't load " + enginePath );
}
IntPtr initializeEnginePtr = GetProcAddress ( dllHandle , "InitializeEngine" );
if ( initializeEnginePtr == IntPtr . Zero )
{
throw new Exception ( "Can't find InitializeEngine function" );
}
IntPtr deinitializeEnginePtr = GetProcAddress ( dllHandle , "DeinitializeEngine" );
if ( deinitializeEnginePtr == IntPtr . Zero )
{
throw new Exception ( "Can't find DeinitializeEngine function" );
}
IntPtr dllCanUnloadNowPtr = GetProcAddress ( dllHandle , "DllCanUnloadNow" );
if ( dllCanUnloadNowPtr == IntPtr . Zero )
{
throw new Exception ( "Can't find DllCanUnloadNow function" );
}
// 將指標轉換為委派
initializeEngine = ( InitializeEngine ) Marshal . GetDelegateForFunctionPointer (
initializeEnginePtr , typeof ( InitializeEngine ));
deinitializeEngine = ( DeinitializeEngine ) Marshal . GetDelegateForFunctionPointer (
deinitializeEnginePtr , typeof ( DeinitializeEngine ));
dllCanUnloadNow = ( DllCanUnloadNow ) Marshal . GetDelegateForFunctionPointer (
dllCanUnloadNowPtr , typeof ( DllCanUnloadNow ));
// 呼叫 InitializeEngine 函式
// 並傳入線上授權檔案路徑和線上授權密碼
int hresult = initializeEngine ( customerProjectId , licensePath , licensePassword ,
"" , "" , false , ref engine );
Marshal . ThrowExceptionForHR ( hresult );
}
catch ( Exception )
{
// 釋放 FREngine.dll 程式庫
engine = null ;
// 在呼叫 FreeLibrary 前刪除所有物件
GC . Collect ();
GC . WaitForPendingFinalizers ();
GC . Collect ();
FreeLibrary ( dllHandle );
dllHandle = IntPtr . Zero ;
initializeEngine = null ;
deinitializeEngine = null ;
dllCanUnloadNow = null ;
throw ;
}
}
// Kernel32.dll 函式
[ DllImport ( "kernel32.dll" )]
private static extern IntPtr LoadLibraryEx ( string dllToLoad , IntPtr reserved , uint flags );
private const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 ;
[ DllImport ( "kernel32.dll" )]
private static extern IntPtr GetProcAddress ( IntPtr hModule , string procedureName );
[ DllImport ( "kernel32.dll" )]
private static extern bool FreeLibrary ( IntPtr hModule );
// FREngine.dll 函式
[ UnmanagedFunctionPointer ( CallingConvention . StdCall , CharSet = CharSet . Unicode )]
private delegate int InitializeEngine ( string customerProjectId , string licensePath ,
string licensePassword , string tempFolder , string dataFolder , bool isSharedCPUCoresMode ,
ref FREngine . IEngine engine );
[ UnmanagedFunctionPointer ( CallingConvention . StdCall )]
private delegate int DeinitializeEngine ();
[ UnmanagedFunctionPointer ( CallingConvention . StdCall )]
private delegate int DllCanUnloadNow ();
// 私有變數
private FREngine . IEngine engine = null ;
// FREngine.dll 的控制代碼
private IntPtr dllHandle = IntPtr . Zero ;
private InitializeEngine initializeEngine = null ;
private DeinitializeEngine deinitializeEngine = null ;
private DllCanUnloadNow dllCanUnloadNow = null ;
}
ABBYY FineReader Engine 提供 FRDocument 物件,可用來處理多頁文件。使用此物件可保留文件的邏輯結構,並維持原始文字、欄位、字型、樣式等內容。若您想比較頁面,請使用 FRPage 物件。 若要載入單一文件的影像並進行預處理,您應建立 FRDocument 物件,並將影像加入其中。您可以採用下列任一方式: // 從影像檔建立 FRDocument 物件
FREngine . IFRDocument frDocument = engine . CreateFRDocumentFromImage ( "C: \\ MyImage.tif" , null );
若要辨識文件,我們建議您使用 FRDocument 物件的分析與辨識方法。此物件提供一整套方法,可用於文件分析、辨識與合成。最方便的方法是 Process 方法,可一次完成文件分析、辨識與合成。它也能以最高效率運用多處理器與多核心系統的平行處理功能。不過,您也可以使用 Preprocess 、Analyze 、Recognize 與 Synthesize 方法,依序執行預處理、分析、辨識與合成。 您可以載入適合的預先定義設定檔,為文件設定辨識參數 (如需更多資訊,請參閱 Working with Profiles ) 。 // 使用預設參數處理文件
// 如有需要,您可以變更這些參數,例如先載入設定檔
frDocument . Process ( null );
ComparisonResult 物件包含完整的差異清單,並提供取得個別頁面差異的方法。您可以使用 GetChangesForReferencePage 和 GetChangesForUserPage 方法,取得原始文件及其副本中的變更。使用 ChangeLocation 物件可取得變更位置的資訊,並使用其 RegionForPage 屬性取得指定頁面上的變更區域。// 取得偵測到的修改及其在原始文件中的位置資訊
FREngine . IChanges changes = comparatorResult . Changes ;
foreach ( FREngine . IChange change in changes ) {
FREngine . ModificationTypeEnum modificationType = change . ModificationType ;
FREngine . IChangeLocation referenceLocation = change . ReferenceLocation ;
// 現在您可以在頁面上標示這些變更,供人工審核人員檢查
.. .
}
若要匯出比較結果,請呼叫 ComparisonResult 物件的 Export 方法,並將檔案路徑作為輸入參數傳入。資料可儲存為 XML,或儲存為含有追蹤修訂的 DOCX 檔案。 C# // 儲存為 XML 格式
comparisonResult . Export ( "C: \\ ComparisonResult.xml" , FREngine . ComparatorExportFormatEnum . CEF_Xml , null );
步驟 7. 解除載入 ABBYY FineReader Engine
完成 ABBYY FineReader Engine 的工作後,您需要解除載入 Engine 物件。若要這麼做,請使用匯出的 DeinitializeEngine 函式。 public class EngineLoader : IDisposable
{
// 解除載入 FineReader Engine
public void Dispose ()
{
if ( engine == null )
{
// 尚未載入 Engine
return ;
}
engine = null ;
// 在呼叫 FreeLibrary 前刪除所有物件
GC . Collect ();
GC . WaitForPendingFinalizers ();
GC . Collect ();
int hresult = deinitializeEngine ();
hresult = dllCanUnloadNow ();
if ( hresult == 0 )
{
FreeLibrary ( dllHandle );
}
dllHandle = IntPtr . Zero ;
initializeEngine = null ;
deinitializeEngine = null ;
dllCanUnloadNow = null ;
// 清理後擲回例外狀況
Marshal . ThrowExceptionForHR ( hresult );
}
// Kernel32.dll 函式
[ DllImport ( "kernel32.dll" )]
private static extern IntPtr LoadLibraryEx ( string dllToLoad , IntPtr reserved , uint flags );
private const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 ;
[ DllImport ( "kernel32.dll" )]
private static extern IntPtr GetProcAddress ( IntPtr hModule , string procedureName );
[ DllImport ( "kernel32.dll" )]
private static extern bool FreeLibrary ( IntPtr hModule );
// FREngine.dll 函式
[ UnmanagedFunctionPointer ( CallingConvention . StdCall , CharSet = CharSet . Unicode )]
private delegate int InitializeEngine ( string customerProjectId , string LicensePath , string LicensePassword , , , , ref FREngine . IEngine engine );
[ UnmanagedFunctionPointer ( CallingConvention . StdCall )]
private delegate int DeinitializeEngine ();
[ UnmanagedFunctionPointer ( CallingConvention . StdCall )]
private delegate int DllCanUnloadNow ();
// 私有變數
private FREngine . IEngine engine = null ;
// FREngine.dll 的控制代碼
private IntPtr dllHandle = IntPtr . Zero ;
private InitializeEngine initializeEngine = null ;
private DeinitializeEngine deinitializeEngine = null ;
private DllCanUnloadNow dllCanUnloadNow = null ;
}
您可以使用 FREngineDistribution.csv 檔案,自動建立應用程式執行所需的檔案清單。若要使用此情境進行處理,請在第 5 欄 (RequiredByModule) 中選取下列值:
Core
Core.Resources
Opening
Opening, Processing
Processing
Processing.OCR
Processing.OCR, Processing.ICR
Processing.OCR.NaturalLanguages
Processing.OCR.NaturalLanguages, Processing.ICR.NaturalLanguages
Export
Export, Processing
如果您修改了標準情境,請相應調整所需模組。您也需要指定應用程式所使用的介面語言、辨識語言,以及任何其他附加功能 (例如,如果您需要開啟 PDF 檔案,則為 Opening.PDF;如果您需要辨識 CJK 語言 的文字,則為 Processing.OCR.CJK) 。如需更多資訊,請參閱 Working with the FREngineDistribution.csv File 。
以下概述說明主題,其中包含在不同處理階段自訂設定的其他資訊:
掃描 - 僅限 Windows
掃描 說明 ABBYY FineReader Engine 的文件掃描情境。
辨識
基本使用案例實作