跳转到主要内容
此场景用于处理纸质文档,并将其保存到数字档案中,尤其适合建立合同、项目文档、发票、证书等的电子档案。 在此处理场景中,纸质文档会被转换为不可编辑的数字副本,并以可检索的格式保留文档中的全部信息。经过此类处理后,可通过全文检索在电子档案中轻松找到文档的数字副本,也可以复制文档中的文本片段,并通过电子邮件发送或打印文档。 要创建数字副本,文档首先需要经过多个处理阶段,每个阶段都有其自身的特点:
  1. 扫描图像预处理
扫描图像在识别前可能需要进行预处理,例如扫描文档中存在背景噪点、文本倾斜、颜色反转、黑边、方向错误或分辨率不正确等问题时。
  1. 大批量文档的并行识别
要从文档中提取文本数据,必须先对其进行识别。在处理大批量文档时,并行处理多个文档会很有帮助。在这种情况下,分析和识别任务可以分配到处理器的多个核心上,从而加快处理速度。
  1. 导出为归档格式
识别后的文档会保存为适合存储的格式。最适合用于文档存储的格式包括 PDF、PDF/A,以及启用 MRC 的 PDF 和 PDF/A。保存为这些格式时,可以使用一种模式,将文本置于文档图像下方——这样既能完整保留文档版式,又能实现全文检索。MRC 设置可以在不损失视觉质量的情况下显著减小文件大小。此外,保存为 PDF 格式时,还可以自定义文档的安全设置,以防止未经授权的查看和打印。

场景实现

本主题中提供的代码示例仅适用于 Windows。
下面将详细介绍使用 ABBYY FineReader Engine 12 创建用于归档的文档数字副本的推荐方法。该方法采用了最适合此用途的处理设置。在此实现中,文档扫描阶段被省略。如需了解有关实现扫描的提示,请参阅下方的特定任务的附加优化
要开始使用 ABBYY FineReader Engine,您需要创建 Engine 对象。Engine 对象是 ABBYY FineReader Engine 对象层次结构中的顶层对象,提供各种全局设置、部分处理方法以及用于创建其他对象的方法。要创建 Engine 对象,可以使用 InitializeEngine 函数。另请参阅加载 Engine 对象的其他方式 (Win) 。

C#

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("无法加载 " + enginePath);
            }
            IntPtr initializeEnginePtr = GetProcAddress(dllHandle, "InitializeEngine");
            if (initializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("找不到 InitializeEngine 函数");
            }
            IntPtr deinitializeEnginePtr = GetProcAddress(dllHandle, "DeinitializeEngine");
            if (deinitializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("找不到 DeinitializeEngine 函数");
            }
            IntPtr dllCanUnloadNowPtr = GetProcAddress(dllHandle, "DllCanUnloadNow");
            if (dllCanUnloadNowPtr == IntPtr.Zero)
            {
                throw new Exception("找不到 DllCanUnloadNow 函数");
            }
            // 将指针转换为委托
            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;
}

C++ (COM)

// 请将以下变量初始化为 FREngine.dll 的路径、FineReader Engine Customer Project ID,
// 以及(如适用)Online License 令牌路径和 Online License 密码
wchar_t* FreDllPath;
wchar_t* CustomerProjectId;
wchar_t* LicensePath;  // 如果不使用 Online License,请将这些变量赋值为空字符串
wchar_t* LicensePassword;
// FREngine.dll 的句柄
static HMODULE libraryHandle = 0;
// 全局 FineReader Engine 对象
FREngine::IEnginePtr Engine;
void LoadFREngine()
{
    if( Engine != 0 ) {
    // 已加载
    return;
    }
    // 第一步:加载 FREngine.dll
    if( libraryHandle == 0 ) {
        libraryHandle = LoadLibraryEx( FreDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
        if( libraryHandle == 0 ) {
            throw L"加载 ABBYY FineReader Engine 时出错";
        }
    }
    // 第二步:获取 Engine 对象
    typedef HRESULT ( STDAPICALLTYPE* InitializeEngineFunc )( BSTR, BSTR, BSTR, BSTR, 
        BSTR, VARIANT_BOOL, FREngine::IEngine** );
    InitializeEngineFunc pInitializeEngine =
    ( InitializeEngineFunc )GetProcAddress( libraryHandle, "InitializeEngine" );
    if( pInitializeEngine == 0 || pInitializeEngine( CustomerProjectId, LicensePath, 
        LicensePassword, L"", L"", VARIANT_FALSE, &Engine ) != S_OK ) {
    UnloadFREngine();
    throw L"加载 ABBYY FineReader Engine 时出错";
    }
}
ABBYY FineReader Engine 可通过 Engine 对象的 LoadPredefinedProfile 方法,加载最适合此场景的全部处理设置。该方法接收配置文件名称作为输入参数。更多信息,请参见使用配置文件ABBYY FineReader Engine 针对此场景支持 2 种设置变体:

配置文件名称

说明

DocumentArchiving_Accuracy

这些设置已针对准确性进行了优化:

  • 可检测图像中的尽可能多的文本,包括嵌入在图像中的文本。
  • 不执行文档逻辑结构的完整合成。
此配置文件不适用于将文档转换为 RTF、DOCX 或纯文本 PDF。为此,请使用文档转换配置文件。

DocumentArchiving_Speed

这些设置已针对处理速度进行了优化:

  • 可检测图像中的尽可能多的文本,包括嵌入在图像中的文本。
  • 不执行倾斜校正。
  • 不执行文档逻辑结构的完整合成。
  • 文档分析和识别过程会加快。
此配置文件不适用于将文档转换为 RTF、DOCX 或纯文本 PDF。为此,请使用文档转换配置文件。

C#

// 加载预定义配置文件
engine.LoadPredefinedProfile("DocumentArchiving_Accuracy");

C++ (COM)

// 加载预定义配置文件
Engine->LoadPredefinedProfile( L"DocumentArchiving_Accuracy" );
如果您想更改处理设置,请使用相应的 Parameter 对象。更多信息,请参见针对特定任务的附加优化
ABBYY FineReader Engine 提供 FRDocument 对象,可用于处理多页文档。使用该对象可以保留文档的逻辑组织结构。要加载单个文档的图像并进行预处理,您应创建 FRDocument 对象并向其中添加图像。您可以采用以下任一方式:

C#

// 从图像文件创建 FRDocument 对象
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );

C++ (COM)

// 从图像文件创建 FRDocument 对象
FREngine::IFRDocumentPtr frDocument = Engine->CreateFRDocumentFromImage( L"C:\\MyImage.tif", 0 );
对于文档识别,建议使用 FRDocument 对象的分析和识别方法。该对象提供了一整套用于文档分析、识别和合成的方法。其中,最方便的是 Process 方法,只需调用这一个方法即可完成文档分析、识别和合成。它还能以最高效的方式利用多处理器和多核系统的并行处理能力。不过,您也可以通过 PreprocessAnalyzeRecognizeSynthesize 方法,按顺序执行预处理、分析、识别和合成。

C#

// 分析、识别并合成文档
// 无需额外参数,因为这些参数已由处理配置文件设置
frDocument.Process( null );

C++ (COM)

// 分析、识别并合成文档
// 无需额外参数,因为这些参数已由处理配置文件设置
frDocument->Process( 0 );
要保存已识别的文档,您可以使用 FRDocument 对象的 Export 方法,并将 FileExportFormatEnum 常量作为参数之一。在这种情况下,例如,您可以使用 MRC,并通过 PEM_ImageOnText 导出模式将文档保存为 PDF 格式 (PDFExportParams 对象的 TextExportMode 属性) 。您可以使用相应的导出对象修改默认导出参数。更多信息,请参见下文的 针对特定任务的附加优化完成对 FRDocument 对象的使用后,请释放该对象占用的所有资源。请使用 IFRDocument::Close 方法。

C#

// 将已识别的文档保存为归档格式(例如 PDF)
// 创建一个 PDFExportParams 对象
FREngine.PDFExportParams exportParams = engine.CreatePDFExportParams();
// 设置所需参数
exportParams.MRCMode = FREngine.PDFMRCModeEnum.MRC_Auto;
exportParams.TextExportMode = FREngine.PDFExportModeEnum.PEM_ImageOnText;
// 在导出时使用这些参数
frDocument.Export( "C:\\MyText.pdf", FREngine.FileExportFormatEnum.FEF_PDF, exportParams );
// 释放 FRDocument 对象
frDocument.Close();

C++ (COM)

// 将已识别的文档保存为归档格式(例如 PDF)
// 创建一个 PDFExportParams 对象
FREngine::IPDFExportParamsPtr params = Engine->CreatePDFExportParams();
// 设置所需参数
params->MRCMode = FREngine::MRC_Auto;
params->TextExportMode = FREngine::PEM_ImageOnText;
// 在导出时使用这些参数
frDocument->Export(L"C:\\MyText.pdf", FREngine::FEF_PDF, params);
// 释放 FRDocument 对象
frDocument->Close();
结束对 ABBYY FineReader Engine 的使用后,您需要卸载 Engine 对象。为此,请使用导出的 DeinitializeEngine 函数。

C#

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;
}

C++ (COM)

void UnloadFREngine()
{
 if( libraryHandle == 0 ) {
  return;
 }
 // 释放 Engine 对象
 Engine = 0;
 // 取消初始化 FineReader Engine
 typedef HRESULT ( STDAPICALLTYPE* DeinitializeEngineFunc )();
 DeinitializeEngineFunc pDeinitializeEngine =
  ( DeinitializeEngineFunc )GetProcAddress( libraryHandle, "DeinitializeEngine" );
 if( pDeinitializeEngine == 0 || pDeinitializeEngine() != S_OK ) {
  throw L"Error while unloading ABBYY FineReader Engine";
 }
 // 现在可以安全释放 FREngine.dll 库
 FreeLibrary( libraryHandle );
 libraryHandle = 0;
}

所需资源

您可以使用 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 Export.Pdf Export.Pdf, Opening.Pdf 如果您修改了标准场景,请相应调整所需模块。您还需要指定应用程序使用的界面语言、识别语言以及其他附加功能 (例如,需要打开 PDF 文件时指定 Opening.PDF;需要识别 CJK 语言文本时指定 Processing.OCR.CJK) 。有关更多详细信息,请参见 Working with the FREngineDistribution.csv File

特定任务的附加优化

以下概述了帮助主题,其中包含有关在文档处理不同阶段自定义设置的更多信息:
  • 扫描 - 仅适用于 Windows
    • 扫描
      ABBYY FineReader Engine 中文档扫描场景的说明。
  • 识别
  • 识别手写文本
    DocumentArchiving_*** 配置文件不包含手写体或手写印刷体文本识别。如果您需要识别手写文本,请将 PageAnalysisParams 对象的 DetectHandwritten 属性设置为 TRUE。
  • PageProcessingParams 对象
    该对象可用于自定义分析和识别参数。使用该对象,您可以指定需要检测的图像和文本特征 (反相图像、方向、条形码、识别语言、识别误差容限) 。
  • SynthesisParamsForPage 对象
    此对象包含在合成过程中负责恢复页面版面格式的参数。
  • SynthesisParamsForDocument 对象
    该对象可用于自定义文档合成:恢复文档的结构和格式。
  • MultiProcessingParams 对象 - 已在 Linux 和 Windows 上实现
    处理大量图像时,并行处理会很有帮助。在这种情况下,在图像打开和预处理、版面分析、识别和导出期间,处理负载会分散到各个处理器核心上,从而提高处理速度。
    读取模式 (并行或连续) 通过 MultiProcessingMode 属性设置,RecognitionProcessesCount 属性则用于控制可启动的进程数量。
  • 导出
    • 调整导出参数
      使用导出参数对象自定义文档导出。
    • PDFExportParams 对象
      此对象只需几个参数即可调整 PDF (PDF/A) 导出。
    • 要自定义 PDF (PDF/A) 格式的导出模式,请使用 PDFExportParams 对象的 TextExportMode 属性;要自定义 MRC 设置,请使用 MRCMode 属性。
    • 此外,您还可以自定义图像导出设置,以加快处理速度、进一步减小文件大小等。例如,如果适合您的使用场景,可以将彩色图像保存为灰度图像或黑白图像 (使用 PDFExportParams 对象的 Colority 属性) 。
    • 您可以更改图像分辨率,使生成的电子副本能够打印到打印机上或在计算机屏幕上查看;也可以选择较低的分辨率,这种分辨率仅适合阅读文本,图形质量会很差 (使用 PDFExportParams 对象的 ResolutionResolutionType 属性) 。
  • 按文档拆分
    • 在这种情况下,这批图像可能需要拆分为多个文档。ABBYY FineReader Engine 12 不支持自动文档拆分。不过,您可以使用 ABBYY FlexiCapture Engine 来实现自动拆分。例如,可以根据文档的页数,或根据带有分隔条码的页面来拆分文档。实现条码分隔时,您可以使用仅从文档中提取条码值的方案

另请参见

基本使用场景实现