메인 콘텐츠로 건너뛰기
종이 문서를 다룰 때는 실수나 의도적으로 이루어진 변경 사항을 찾아 수정해야 합니다. 이러한 변경 사항을 빠르고 효율적으로 찾으려면 문서 비교 API를 사용하세요. 이 시나리오는 계약서나 은행 문서처럼 특히 중요한 문서와 그 사본을 비교하는 데 사용됩니다. 비교 결과에는 콘텐츠 유형(텍스트만), 수정 유형(삭제, 삽입 또는 수정), 그리고 원본과 사본에서의 위치 정보가 포함됩니다. 감지된 차이점 목록이나 개별 변경 영역 정보를 가져올 수 있으며, 후속 처리나 장기 보관을 위해 비교 결과를 외부 파일에 저장할 수도 있습니다. 문서나 페이지를 비교할 때는 스캔하거나 전자 형식으로 저장한 파일이 일반적으로 여러 처리 단계를 거치며, 각 단계에는 고유한 특성이 있습니다.
  1. 스캔한 파일 또는 이미지 전처리
파일과 사본에 서명이나 스탬프처럼 결함이나 의도적으로 추가된 표기가 포함된 경우, 인식 전에 전처리가 필요합니다.
  1. 문서 구조와 서식을 완전히 복원하는 인식
문서를 인식할 때는 문서의 다양한 레이아웃 요소(텍스트, 표, 이미지, 구분선 등)를 식별합니다. 문서 합성 과정에서는 문서의 논리 구조가 복원되고, 페이지 합성을 통해 문서 서식(글꼴, 스타일 등)도 완전히 복원할 수 있습니다.
  1. 문서 또는 페이지 비교
문서나 페이지를 사본과 비교하려면 ABBYY FineReader Engine으로 인식한 파일을 사용하세요. 서로 다른 형식의 동일 문서 두 버전을 비교할 수 있습니다. 비교 후 변경 사항 목록이 포함된 결과를 얻으면 이를 사용해 변경 사항의 위치 정보를 가져올 수 있습니다. 수동 검증을 사용하는 경우에는 이 정보를 활용해 텍스트에서 변경 사항을 강조 표시할 수 있으므로 작업자의 업무를 더 수월하게 할 수 있습니다.
  1. 외부 형식으로 내보내기
비교 결과를 XML 및 DOCX 형식으로 저장할 수도 있습니다. 아래에 설명된 절차는 Linux 및 macOS용 문서 비교 샘플과 Windows용 문서 비교 데모 도구에서도 확인할 수 있습니다.

시나리오 구현

이 항목에서 제공하는 코드 샘플은 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는 여러 페이지로 구성된 문서를 처리할 수 있는 FRDocument 객체를 제공합니다. 이 객체를 사용하면 원본 텍스트, 단, 글꼴, 스타일 등을 유지하면서 문서의 논리적 구조를 보존할 수 있습니다. 페이지를 비교하려면 FRPage 객체를 사용합니다.단일 문서의 이미지를 로드하고 전처리하려면 FRDocument 객체를 만들고 여기에 이미지를 추가해야 합니다. 다음 방법 중 하나를 사용할 수 있습니다.

C#

// 이미지 파일에서 FRDocument 객체 생성
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );
문서를 인식하려면 FRDocument 객체의 분석 및 인식 메서드를 사용하는 것이 좋습니다. 이 객체는 문서 분석, 인식, 합성을 위한 다양한 메서드를 제공합니다. 문서 분석, 인식, 합성을 한 번에 수행할 수 있는 가장 편리한 메서드는 Process 메서드입니다. 또한 이 메서드는 다중 프로세서 및 멀티코어 시스템의 동시 처리 기능을 가장 효율적으로 활용합니다. 하지만 Preprocess, Analyze, Recognize, Synthesize 메서드를 사용해 전처리, 분석, 인식, 합성을 순차적으로 수행할 수도 있습니다.
적절한 사전 정의 profile을 로드하여 문서 인식 매개변수를 설정할 수 있습니다(자세한 내용은 Working with Profiles 참조).

C#

// 기본 매개변수로 문서 처리
// 필요한 경우 예를 들어 미리 profile을 로드하여 변경할 수 있음
frDocument.Process( null );
문서 또는 페이지를 해당 사본과 비교하려면 다음 단계를 수행합니다.
  1. ABBYY FineReader Engine 라이선스에서 Compare Documents 모듈을 지원하는지 확인합니다.
  2. Engine 객체의 CreateComparator 메서드를 사용해 Comparator 객체를 생성합니다.
  3. [선택 사항] ComparisonParams 객체를 사용해 속성을 원하는 값으로 설정합니다.
  4. Comparator 객체의 CompareDocuments 메서드를 호출하여 원본 문서를 사본과 비교합니다. 그러면 감지된 변경 사항 정보가 포함된 ComparisonResult 객체가 반환됩니다.

C#

// 문서 비교 수행 
FREngine.IComparator comparator = engine.CreateComparator();
FREngine.IComparisonResult comparatorResult = 
    comparator.CompareDocuments( referenceFRDocument, userFRDocument, null, null );
ComparisonResult 객체에는 차이점의 전체 목록이 포함되어 있으며, 개별 페이지의 차이점을 가져오는 메서드도 제공됩니다. 원본 문서와 그 사본의 변경 사항은 GetChangesForReferencePageGetChangesForUserPage 메서드로 가져올 수 있습니다. 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 변수
    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 전용
    • 스캔
      문서 스캔을 위한 ABBYY FineReader Engine 시나리오를 설명합니다.
  • 인식
    • 전처리, 분석, 인식 및 합성 매개변수 조정
      분석, 인식 및 합성 매개변수 객체를 사용해 문서 처리를 사용자 지정하는 방법입니다.
    • PageProcessingParams 객체
      이 객체를 사용하면 분석 및 인식 매개변수를 사용자 지정할 수 있습니다. 또한 감지해야 하는 이미지 및 텍스트 특성(반전 이미지, 방향, 바코드, 인식 언어, 인식 오류 허용 범위)을 지정할 수 있습니다.
    • SynthesisParamsForPage 객체
      이 객체에는 합성 중 페이지 서식을 복원하는 데 필요한 매개변수가 포함되어 있습니다.
    • SynthesisParamsForDocument 객체
      이 객체를 사용하면 문서의 구조와 서식 복원을 위한 합성 방식을 사용자 지정할 수 있습니다.
    • MultiProcessingParams 객체 - Linux 및 Windows에서 구현됨
      많은 수의 이미지를 처리할 때는 동시 처리가 유용할 수 있습니다. 이 경우 이미지 열기 및 전처리, 레이아웃 분석, 인식, 내보내기 과정에서 처리 부하가 프로세서 코어에 분산되므로 처리 속도를 높일 수 있습니다.
      읽기 모드(동시 또는 순차)는 MultiProcessingMode 속성으로 설정합니다. RecognitionProcessesCount 속성은 시작할 수 있는 프로세스 수를 제어합니다.

참고 항목

기본 사용 시나리오 구현