Skip to main content
This scenario is available for Windows only.
In this scenario, ABBYY FineReader Engine is used on a “scanning computer,” which scans images and saves them as files. This scenario may be used as part of other scenarios in the preliminary stage of document processing, i.e., for obtaining electronic versions of documents for further processing. Usage examples include scanning documents for archiving purposes, getting editable versions of documents, and extracting specific data from documents. Paper documents are scanned and the images are saved in an electronic format, producing high-quality electronic versions of your printed documents. Documents may go through the following processing stages:
  1. Scanning
Documents may be scanned via one of the two available scanning interfaces provided by scanners (TWAIN or WIA), by using ABBYY’s own scanning interface, or without a scanning interface.
  1. Preprocessing of scanned images
Once scanned, the images may be preprocessed. Preprocessing includes despeckling, correction of distorted text lines, color inversion, removal of black margins, and correction of image orientation or resolution. Facing pages may be split into two separate images. Processed images may be saved in various image formats such as JPEG, TIFF, BMP.

Scenario implementation

Below follows a detailed description of the recommended method of using ABBYY FineReader Engine 12 in this scenario. Under the proposed implementation of the scenario, the image preparation phase is omitted. Please see Additional optimization below for tips on implementing image preparation.
To start your work with ABBYY FineReader Engine, you need to create the Engine object. The Engine object is the top object in the hierarchy of the ABBYY FineReader Engine objects and provides various global settings, some processing methods, and methods for creating the other objects.To create the Engine object, you can use the InitializeEngine function. See also other ways to load Engine object (Win).

C#

public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // Initialize these variables with the full path to FREngine.dll, your Customer Project ID,
        // and, if applicable, the path to your Online License token file and the Online License password
        string enginePath = "";
        string customerProjectId = "";
        string licensePath = "";
        string licensePassword = "";
        // Load the FREngine.dll library
        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");
            }
            // Convert pointers to delegates
            initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer(
                initializeEnginePtr, typeof(InitializeEngine));
            deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer(
                deinitializeEnginePtr, typeof(DeinitializeEngine));
            dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer(
                dllCanUnloadNowPtr, typeof(DllCanUnloadNow));
            // Call the InitializeEngine function 
            // passing the path to the Online License file and the Online License password
            int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, 
                "", "", false, ref engine);
            Marshal.ThrowExceptionForHR(hresult);
        }
        catch (Exception)
        {
            // Free the FREngine.dll library
            engine = null;
            // Deleting all objects before FreeLibrary call
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            FreeLibrary(dllHandle);
            dllHandle = IntPtr.Zero;
            initializeEngine = null;
            deinitializeEngine = null;
            dllCanUnloadNow = null;
            throw;
        }
    }
    // Kernel32.dll functions
    [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 functions
    [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 variables
    private FREngine.IEngine engine = null;
    // Handle to FREngine.dll
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}
ABBYY FineReader Engine offers a ScanManager object for managing the scanning sources. The ScanSources property of this object provides access to the list of all available scanners, while the FindScanSources method allows you to select the scanners by API type they provide and the user interface type you wish to use to set scanning options.To scan and save the files to disk, you can use either of these two methods of the ScanSource object: Scan method, which does not return until the scanning is complete, and BeginScan method, which starts the asynchronous scanning operation and returns immediately.You can implement the IScanCallback interface and use it to get notifications about the progress of scanning.The following parameters are accessible via the ABBYY FineReader Engine 12 API: brightness, color, resolution, image compression type, image rotation angle, the size of the scanning area, duplex scanning mode, automatic feeder mode, a pause between pages, and some more. The scanning parameters are set by using the ScanSettings property of the ScanSource object. This property is required to get access to the ScanSourceSettings object, which, in its turn, provides access to the scanning settings of a source.To scan the images synchronously:
  1. Create a ScanManager object. You can specify if the scanning logs are to be written by the input parameter of the CreateScanManager method.
  2. Select the scanning source using the FindScanSources method of the ScanManager object, specifying the API and UI type that should be supported by the scanner.
  3. If you choose to display no dialog box for the user to set scanning options him- or herself, tune the scanning options using the ScanSettings property of the chosen ScanSource. Select the appropriate values for brightness, resolution, and the other parameters in the corresponding properties of the ScanSourceSettings object. You can check which settings are available for this scanner using the Capabilities property of the ScanSource.
  4. Specify the folder name in which scanned pages will be stored. The folder name should be a BSTR variable, for example, ScanFolder.
  5. Run the Scan method of the ScanSource object, providing as the parameter the type of dialog box to be shown to the user (pass SSUIT_None constant to display no box), and the ScanFolder path to the folder with the results.
  6. The image file names will be returned by this method as a StringsCollection object. You can get the image file names from this StringsCollection object and then process the files as usual image files.
To scan the images asynchronously:
  1. Create an object implementing the IScanCallback interface. In the case of the asynchronous scanning operation, notifications from the callback interface are very useful.
  2. Create a ScanManager object. You can specify if the scanning logs are to be written by the input parameter of the CreateScanManager method.
  3. Select the scanning source using the FindScanSources method of the ScanManager object, specifying the API and UI type that should be supported by the scanner.
  4. If you choose to display no dialog box for the user to set scanning options him- or herself, tune the scanning options using the ScanSettings property of the chosen ScanSource. Select the appropriate values for brightness, resolution, and the other parameters in the corresponding properties of the ScanSourceSettings object. You can check which settings are available for this scanner using the Capabilities property of the ScanSource.
  5. Specify the folder name in which scanned pages will be stored. The folder name should be a BSTR variable, for example, ScanFolder.
  6. Run the BeginScan method of the ScanSource object, providing as the parameter the type of dialog box to be shown to the user (pass SSUIT_None constant to display no box), and the ScanFolder path to the folder with the results. You also need to pass the pointer to the callback object you created.
  7. The path to the image file is returned with OnImageScanned notification of the IScanCallback interface, and the completion of the operation is signaled by OnScanComplete notification. As you are providing the implementation for these methods, you can choose what to do in each of these situations. For example, on receiving the path to an image file you can work with it as with any other file from disk, loading it for processing with FineReader Engine in the usual way.
Until the scanning is completed and the OnScanComplete notification received, you cannot run BeginScan or Scan again, even for some other scanner. The advantage of asynchronous scanning is not that you can perform several scanning operations at once, but that you can process the images you already received while the new images are being scanned.
Here is sample code for the asynchronous scanning scenario:

C#

// Implement the IScanCallback interface
class ScanningCallback :FREngine.IScanCallback
{
  // constructor
  public ScanningCallback() {}
  ...
  // provide the implementation of IScanCallback methods
  public void OnError(string sourceName, string message) { // report or handle the error here }
  public void OnImageScanned(string sourceName, string Path, ref bool cancel) { // insert here any action you need to take on scanning an image }
  public void OnScanComplete() { // insert here an action you wish to be performed after the scanning is complete }
  // private variables
  ...
}
// Create scan manager, with the logs turned off
scanManager = engineLoader.Engine.CreateScanManager(false);
// Create a list of scanning sources filtered by API and UI type
FREngine.IScanSources sources = scanManager.FindScanSources(UIType, APIType);
// Just for example, choose the first scanning source from the collection
FREngine.IScanSource selectedSource = sources[0];
// Access scan source settings and capabilities
FREngine.IScanSourceSettings settings = selectedSource.ScanSettings;
FREngine.IScanSourceCapabilities capabilities = selectedSource.Capabilities;
// Set the scanning options to the duplex mode if the scanner has it
settings.DuplexMode = capabilities.HasDuplexMode;
// Set options to multi-page scanning and the 10-second delay between pages
settings.MultipleImagesEnabled = true;
settings.PauseBetweenPagesMode = FREngine.ScanPauseModeEnum.SPM_PresetDelay;
settings.Delay = 10;
// Set the path to folder with results
string scanFolder = "D:\\SampleImages";
// Create a callback object
IScanningCallback callback = new ScanningCallback();
// Start scanning
selectedSource.BeginScan(SSUIT_None, scanFolder, callback);
After finishing your work with ABBYY FineReader Engine, you need to unload the Engine object. To do this, use the DeinitializeEngine exported function.

C#

public class EngineLoader : IDisposable
{
    // Unload FineReader Engine
    public void Dispose()
    {
        if (engine == null)
        {
            // Engine was not loaded
            return;
        }
        engine = null;
        // Deleting all objects before FreeLibrary call
        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;
        // throwing exception after cleaning up
        Marshal.ThrowExceptionForHR(hresult);
    }
    // Kernel32.dll functions
    [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 functions
    [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 variables
    private FREngine.IEngine engine = null;
    // Handle to FREngine.dll
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}

Required resources

You can use the FREngineDistribution.csv file to automatically create a list of files required for your application to function. For processing with this scenario, select in the column 5 (RequiredByModule) the following values: Core Core.Resources Opening Opening, Processing Opening.Scanning If you modify the standard scenario, change the required modules accordingly. You also need to specify the interface languages, recognition languages and any additional features which your application uses (such as, e.g., Processing.OCR.CJK if you need to recognize texts in CJK languages). See Working with the FREngineDistribution.csv File for further details.

Additional optimization

These are the sections of the Help file where you can find additional information about setting up the parameters for the various processing stages:
  • Document separation
    • In this scenario, you may need to group the incoming flow of images into documents. For example, you may know the number of pages in each document, or ensure there are separator pages with barcodes that come between the last page of the first document and the first page of the next document. Consult the barcode recognition scenario.

See also

Basic Usage Scenarios Implementation