For the complete documentation index, see llms.txt. This page is also available as Markdown.
Extraction

Handwriting ICR - search PDFs and Extract Handwritten Text

Requirements

These packages are required to use these features in production. Trial keys have unlimited access to all features

Server SDKPackage: ICRModule: ICR

Sample code shows how to use the Apryse Server ICR module on scanned documents in multiple languages; provided in Python, C++, C# (.Net), Java, JavaScript, PHP, Ruby and VB. The ICR module can make searchable PDFs and extract scanned text for further indexing.

Implementation steps

To run this sample, you will need:

  1. Get started with Server SDK in your language/framework.

  2. Add the sample code provided below.

To use this feature in production, your license key will need the ICR Package. Trial keys already include this package.

//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.     
//---------------------------------------------------------------------------------------

using System;
using pdftron;
using pdftron.Common;
using pdftron.SDF;
using pdftron.PDF;

namespace HandwritingICRTestCS
{
    
    /// <summary>
    //---------------------------------------------------------------------------------------
    // The Handwriting ICR Module is an optional PDFNet add-on that can be used to extract
	// handwriting from image-based pages and apply them as hidden text.
	//
	// The Apryse SDK Handwriting ICR Module can be downloaded from https://dev.apryse.com/
    //---------------------------------------------------------------------------------------
    /// </summary>
    class Class1
    {
        private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
        static Class1() {}
        
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
        {
            // The first step in every application using PDFNet is to initialize the 
            // library and set the path to common PDF resources. The library is usually 
            // initialized only once, but calling Initialize() multiple times is also fine.
            PDFNet.Initialize(PDFTronLicense.Key);

			// The location of the Handwriting ICR Module
            PDFNet.AddResourceSearchPath("../../../../../Lib/");

            // Test if the add-on is installed
            if (!HandwritingICRModule.IsModuleAvailable())
            {
                Console.WriteLine("");
                Console.WriteLine("Unable to run HandwritingICRTest: Apryse SDK Handwriting ICR Module");
                Console.WriteLine("not available.");
                Console.WriteLine("---------------------------------------------------------------");
                Console.WriteLine("The Handwriting ICR Module is an optional add-on, available for download");
                Console.WriteLine("at https://dev.apryse.com/. If you have already downloaded this");
                Console.WriteLine("module, ensure that the SDK is able to find the required files");
                Console.WriteLine("using the PDFNet.AddResourceSearchPath() function.");
                Console.WriteLine("");
                return;
            }

            // Relative path to the folder containing test files.
            string input_path =  "../../../../TestFiles/HandwritingICR/";
            string output_path = "../../../../TestFiles/Output/";

            //--------------------------------------------------------------------------------
            // Example 1) Process a PDF without specifying options
            try
            {
				Console.WriteLine("Example 1: processing icr.pdf");

                // Open the .pdf document
                using (PDFDoc doc = new PDFDoc(input_path + "icr.pdf"))
                {
                    // Run ICR on the .pdf with the default options
                    HandwritingICRModule.ProcessPDF(doc);

                    // Save the result with hidden text applied
                    doc.Save(output_path + "icr-simple.pdf", SDFDoc.SaveOptions.e_linearized);
					doc.Close();
                }
            }
            catch (PDFNetException e)
            {
                Console.WriteLine(e.Message);
            }

            //--------------------------------------------------------------------------------
            // Example 2) Process a subset of PDF pages
            try
            {
				Console.WriteLine("Example 2: processing pages from icr.pdf");

                // Open the .pdf document
                using (PDFDoc doc = new PDFDoc(input_path + "icr.pdf"))
                {
					// Process handwriting with custom options
					HandwritingICROptions options = new HandwritingICROptions();

					// Optionally, process a subset of pages
					options.SetPages("2-3");

                    // Run ICR on the .pdf
                    HandwritingICRModule.ProcessPDF(doc, options);

                    // Save the result with hidden text applied
                    doc.Save(output_path + "icr-pages.pdf", SDFDoc.SaveOptions.e_linearized);
					doc.Close();
                }
            }
            catch (PDFNetException e)
            {
                Console.WriteLine(e.Message);
            }

            //--------------------------------------------------------------------------------
            // Example 3) Ignore zones specified for each page
            try
            {
				Console.WriteLine("Example 3: processing & ignoring zones");

                // Open the .pdf document
                using (PDFDoc doc = new PDFDoc(input_path + "icr.pdf"))
                {
					// Process handwriting with custom options
					HandwritingICROptions options = new HandwritingICROptions();

					// Process page 2 by ignoring the signature area on the bottom
					options.SetPages("2");
					RectCollection ignore_zones_page2 = new RectCollection();
					// These coordinates are in PDF user space, with the origin at the bottom left corner of the page.
					// Coordinates rotate with the page, if it has rotation applied.
					ignore_zones_page2.AddRect(78, 850.1 - 770, 340, 850.1 - 676);
					options.AddIgnoreZonesForPage(ignore_zones_page2, 2);

                    // Run ICR on the .pdf
                    HandwritingICRModule.ProcessPDF(doc, options);

                    // Save the result with hidden text applied
                    doc.Save(output_path + "icr-ignore.pdf", SDFDoc.SaveOptions.e_linearized);
					doc.Close();
                }
            }
            catch (PDFNetException e)
            {
                Console.WriteLine(e.Message);
            }

            //--------------------------------------------------------------------------------
            // Example 4) The postprocessing workflow has also an option of extracting ICR results
			// in JSON format, similar to the one used by the OCR Module
            try
            {
				Console.WriteLine("Example 4: extract & apply");

                // Open the .pdf document
                using (PDFDoc doc = new PDFDoc(input_path + "icr.pdf"))
                {
                    // Extract ICR results in JSON format
                    string json = HandwritingICRModule.GetICRJsonFromPDF(doc);
					System.IO.File.WriteAllText(output_path + "icr-get.json", json);

					// Insert your post-processing step (whatever it might be)
					// ...

					// Apply potentially modified ICR JSON to the PDF
					HandwritingICRModule.ApplyICRJsonToPDF(doc, json);

                    // Save the result with hidden text applied
                    doc.Save(output_path + "icr-get-apply.pdf", SDFDoc.SaveOptions.e_linearized);
					doc.Close();
                }
            }
            catch (PDFNetException e)
            {
                Console.WriteLine(e.Message);
            }

            Console.WriteLine("Done.");
            PDFNet.Terminate();
        }

    }
}