メインコンテンツへスキップ
紙のDocumentを扱う際には、誤りや意図的に加えられた変更を見つけて修正する必要があります。Document Comparison API を使用すると、こうした変更をすばやく効率的に検出できます。 このシナリオは、契約書や銀行関連Documentなど、特に重要なDocumentとそのコピーを比較する場合に使用されます。比較結果には、コンテンツの種類 (テキストのみ) 、変更の種別 (削除、挿入、変更) 、および原本とコピー内での位置に関する情報が含まれます。検出された差異の一覧や変更箇所の領域を取得でき、比較結果を外部ファイルに保存して、後続の処理や長期保存に利用することもできます。 Documentまたはページを比較する際は、通常、スキャンしたファイルや電子形式で保存されたファイルがいくつかの処理段階を経ます。各段階にはそれぞれ固有の特性があります。
  1. スキャンしたファイルまたは画像の前処理
ファイルやそのコピーに欠陥、または署名や印影などの意図的に付加された注記が含まれている場合は、認識前に前処理が必要です。
  1. Document構造と書式を完全に復元する認識
Documentを認識する際には、Document内のさまざまなレイアウト要素 (テキスト、表、画像、区切り線など) が識別されます。Document合成の過程ではDocumentの論理構造が復元され、ページ合成によってDocumentの書式 (フォント、スタイルなど) も完全に復元できます。
  1. Documentまたはページの比較
Documentまたはページをそのコピーと比較するには、ABBYY FineReader Engine で認識したファイルを使用します。形式が異なる 2 つの版のDocumentでも比較できます。比較後に変更一覧を含む結果が得られたら、それを使用して変更箇所の位置情報を取得します。手動検証を使用している場合は、この情報を使ってテキスト内の変更箇所を強調表示できるため、オペレーターの作業負荷を軽減できます。
  1. 外部形式へのエクスポート
比較結果は XML および DOCX 形式で保存することもできます。 以下で説明する手順は、Linux および macOS 向けのサンプル Document比較 と、Windows 向けのデモツール Document比較 でも示されています。

シナリオの実装

このトピックで提供するコード サンプルは、Windows 固有です。
以下では、このシナリオで ABBYY FineReader Engine を使用する推奨方法について詳しく説明します。
ABBYY FineReader Engine を使い始めるには、Engine オブジェクトを作成する必要があります。Engine オブジェクトは、ABBYY FineReader Engine のオブジェクト階層の最上位に位置するオブジェクトで、さまざまなグローバル設定、一部の処理メソッド、および他のオブジェクトを作成するためのメソッドを提供します。Engine オブジェクトを作成するには、InitializeEngine 関数を使用できます。あわせて Engine オブジェクトを読み込むその他の方法 (Win) も参照してください。

C#

public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // これらの変数を、FREngine.dll へのフルパス、Customer Project ID、
        // および該当する場合は Online License トークンファイルへのパスと Online License パスワードで初期化します
        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 関数を呼び出し、 
            // Online License ファイルへのパスと Online License パスワードを渡します
            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 変数
    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 には、複数ページのDocumentを処理できる FRDocument オブジェクトがあります。このオブジェクトを使用すると、元のテキスト、段組み、フォント、スタイルなどを保持したまま、Documentの論理的な構成を維持できます。ページ同士を比較する場合は、FRPage オブジェクトを使用してください。1 つのDocumentに含まれる画像を読み込んで前処理するには、FRDocument オブジェクトを作成し、それに画像を追加する必要があります。方法は次のいずれかです。
  • Engine オブジェクトの CreateFRDocumentFromImage メソッドを使用して FRDocument オブジェクトを作成します。このメソッドは FRDocument オブジェクトを作成し、指定したファイルから画像を読み込みます。
  • Engine オブジェクトの CreateFRDocument メソッドを使用して FRDocument オブジェクトを作成し、作成した FRDocument オブジェクトにファイルから画像を追加します (FRDocument オブジェクトの AddImageFileAddImageFileWithPassword、または AddImageFileWithPasswordCallback メソッドを使用します) 。

C#

// 画像ファイルから FRDocument オブジェクトを作成
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );
Documentを認識するには、FRDocument オブジェクトの解析メソッドと認識メソッドを使用することをお勧めします。このオブジェクトには、Documentの解析、認識、合成のための各種メソッドが用意されています。Documentの解析、認識、合成を一括で実行できる最も便利なメソッドは、Process メソッドです。また、このメソッドはマルチプロセッサおよびマルチコアシステムの同時処理機能を最も効率的に活用します。一方で、PreprocessAnalyzeRecognize、および Synthesize メソッドを使用して、前処理、解析、認識、合成を順番に実行することもできます。
適切な定義済みプロファイルを読み込むことで、Documentの認識パラメーターを設定できます (詳細は Working with Profiles を参照してください) 。

C#

// 既定のパラメーターで文書を処理
// 必要に応じて変更できます。たとえば、事前にプロファイルを読み込めます
frDocument.Process( null );
Documentまたはページをそのコピーと比較するには、次の手順を実行します。
  1. ご使用の ABBYY FineReader Engine ライセンスが Compare Documents モジュールをサポートしていることを確認します。
  2. Engine オブジェクトの CreateComparator メソッドを使用して、Comparator オブジェクトを作成します。
  3. [任意] ComparisonParams オブジェクトを使用して、プロパティを必要な値に設定します。
  4. Comparator オブジェクトの CompareDocuments メソッドを呼び出して、元のDocumentとコピーを比較します。すると、検出された変更に関する情報を含む ComparisonResult オブジェクトが返されます。

C#

// 文書の比較を実行します 
FREngine.IComparator comparator = engine.CreateComparator();
FREngine.IComparisonResult comparatorResult = 
    comparator.CompareDocuments( referenceFRDocument, userFRDocument, null, null );
ComparisonResult オブジェクトには差異の完全な一覧が含まれており、個々のページの差異を取得するためのメソッドも用意されています。GetChangesForReferencePage メソッドと GetChangesForUserPage メソッドを使用すると、元のDocumentとそのコピーにおける変更にアクセスできます。ChangeLocation オブジェクトを使用して変更位置に関する情報を取得し、その RegionForPage プロパティを使用して、指定したページ上の変更領域を取得します。

C#

// 検出された変更と元の文書内でのその位置に関する情報を取得します
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 );
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;
}

必要なリソース

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 languages のテキストを認識する必要がある場合は Processing.OCR.CJK を指定します) 。詳細については、Working with the FREngineDistribution.csv File を参照してください。

特定のタスク向けの追加の最適化

以下に、各処理段階での設定のカスタマイズに関する追加情報を含むヘルプトピックの概要を示します。
  • スキャン - Windows のみ
    • スキャン
      Documentをスキャンするための ABBYY FineReader Engine シナリオの説明です。
  • 認識
    • 前処理、解析、認識、および合成のパラメーターの調整
      解析、認識、合成のパラメーターオブジェクトを使用して、Document処理をカスタマイズします。
    • PageProcessingParams Object
      このオブジェクトを使用すると、解析および認識のパラメーターをカスタマイズできます。また、検出する画像やテキストの特性 (反転画像、向き、バーコード、認識言語、認識エラー許容範囲) を指定できます。
    • SynthesisParamsForPage Object
      このオブジェクトには、合成時にページの書式を復元するためのパラメーターが含まれています。
    • SynthesisParamsForDocument Object
      このオブジェクトを使用すると、Document合成 (構造と書式の復元) をカスタマイズできます。
    • MultiProcessingParams Object - Linux および Windows で実装
      大量の画像を処理する場合は、同時処理が役立つことがあります。この場合、画像のオープンと前処理、レイアウト解析、認識、エクスポートの際に処理負荷がプロセッサコア全体に分散されるため、処理を高速化できます。
      読み取りモード (同時または連続) は、MultiProcessingMode プロパティを使用して設定します。RecognitionProcessesCount プロパティは、起動可能なプロセス数を制御します。

関連項目

基本的な使用シナリオの実装方法