> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/core/get-started/samples/icrtest.md).

# Handwriting ICR - search PDFs and Extract Handwritten Text

Sample code shows how to use the Apryse Handwriting ICR module on scanned documents in multiple languages. The Handwriting ICR module can make searchable PDFs and extract scanned handwritten text for

{% hint style="info" %}
**Requirements**

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

<a href="/core/get-started/get-started.md" class="button primary">Server SDK</a><a href="https://apryse.com/capabilities#IntelligentCharacterRecognition(ICR)" class="button primary">Package: ICR</a><a href="/core/learn-more/modules.md#handwriting-icr-module" class="button primary">Module: ICR</a>
{% endhint %}

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](/core/get-started/get-started.md) in your language/framework.
2. [Download ICR Module](/core/learn-more/modules.md#handwriting-icr-module).
3. Add the sample code provided below.

To use this feature in production, your license key will need the [ICR Package](https://apryse.com/capabilities#IntelligentCharacterRecognition\(ICR\)). Trial keys already include this package.

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
//---------------------------------------------------------------------------------------
// 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();
        }

    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

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

package main
import (
	"fmt"
	"testing"
	"os"
	"flag"
	. "github.com/pdftron/pdftron-go/v2"
)

var licenseKey string
var modulePath string

func init() {
	flag.StringVar(&licenseKey, "license", "", "License key for Apryse SDK")
	flag.StringVar(&modulePath, "modulePath", "", "Path for downloaded modules")
}

// Relative path to the folder containing test files.
var inputPath = "../TestFiles/HandwritingICR/"
var outputPath = "../TestFiles/Output/"

func WriteTextToFile(outputFile string, text string) {
	f, err := os.Create(outputFile)
	if err != nil {
		fmt.Println(err)
	}

	defer f.Close()

	_, err2 := f.WriteString(text)
	if err2 != nil {
		fmt.Println(err2)
	}
}

// ---------------------------------------------------------------------------------------
// 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/
// --------------------------------------------------------------------------------------

func TestHandwritingICR(t *testing.T) {

	// 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.
	PDFNetInitialize(licenseKey)

	// The location of the Handwriting ICR Module
	PDFNetAddResourceSearchPath(modulePath)

	// Test if the add-on is installed
	if !HandwritingICRModuleIsModuleAvailable() {

		fmt.Println("Unable to run HandwritingICRTest: Apryse SDK Handwriting ICR Module\n" +
			"not available.\n" +
			"---------------------------------------------------------------\n" +
			"The Handwriting ICR Module is an optional add-on, available for download\n" +
			"at https://dev.apryse.com/. If you have already downloaded this\n" +
			"module, ensure that the SDK is able to find the required files\n" +
			"using the PDFNetAddResourceSearchPath() function.")

	} else {

		// --------------------------------------------------------------------------------
		// Example 1) Process a PDF without specifying options
		fmt.Println("Example 1: processing icr.pdf")

		// Open the .pdf document
		doc := NewPDFDoc(inputPath + "icr.pdf")

		// Run ICR on the .pdf with the default options
		HandwritingICRModuleProcessPDF(doc)

		// Save the result with hidden text applied
		doc.Save(outputPath + "icr-simple.pdf", uint(SDFDocE_linearized))
		doc.Close()

		// --------------------------------------------------------------------------------
		// Example 2) Process a subset of PDF pages
		fmt.Println("Example 2: processing pages from icr.pdf")

		// Open the .pdf document
		doc = NewPDFDoc(inputPath + "icr.pdf")
		
		// Process handwriting with custom options
		options := NewHandwritingICROptions()
		
		// Optionally, process a subset of pages
		options.SetPages("2-3")

		// Run ICR on the .pdf
		HandwritingICRModuleProcessPDF(doc, options)

		// Save the result with hidden text applied
		doc.Save(outputPath + "icr-pages.pdf", uint(SDFDocE_linearized))
		doc.Close()

		// --------------------------------------------------------------------------------
		// Example 3) Ignore zones specified for each page
		fmt.Println("Example 3: processing & ignoring zones")

		// Open the .pdf document
		doc = NewPDFDoc(inputPath + "icr.pdf")
		
		// Process handwriting with custom options
		options = NewHandwritingICROptions()
		
		// Process page 2 by ignoring the signature area on the bottom
		options.SetPages("2")
		ignoreZonesPage2 := NewRectCollection()
		// 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.
		ignoreZonesPage2.AddRect(NewRect(78.0, 850.1 - 770.0, 340.0, 850.1 - 676.0))
		options.AddIgnoreZonesForPage(ignoreZonesPage2, 2)

		// Run ICR on the .pdf
		HandwritingICRModuleProcessPDF(doc, options)

		// Save the result with hidden text applied
		doc.Save(outputPath + "icr-ignore.pdf", uint(SDFDocE_linearized))
		doc.Close()

		// --------------------------------------------------------------------------------
		// 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
		fmt.Println("Example 4: extract & apply")

		// Open the .pdf document
		doc = NewPDFDoc(inputPath + "icr.pdf")
		
		// Extract ICR results in JSON format
		json := HandwritingICRModuleGetICRJsonFromPDF(doc)
		WriteTextToFile(outputPath + "icr-get.json", json)

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

		// Apply potentially modified ICR JSON to the PDF
		HandwritingICRModuleApplyICRJsonToPDF(doc, json)

		// Save the result with hidden text applied
		doc.Save(outputPath + "icr-get-apply.pdf", uint(SDFDocE_linearized))
		doc.Close()

		fmt.Println("Done.")

		PDFNetTerminate()
	}
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------
#include <PDF/PDFNet.h>
#include <PDF/PDFDoc.h>
#include <PDF/HandwritingICRModule.h>
#include <PDF/HandwritingICROptions.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include "../../LicenseKey/CPP/LicenseKey.h"

using namespace std;
using namespace pdftron;
using namespace PDF;
using namespace SDF;

static void WriteTextToFile(const std::string& filename, const UString& text)
{
	ofstream out_file(filename.c_str(), ofstream::binary);
	string out_buf = text.ConvertToUtf8();
	out_file.write(out_buf.c_str(), out_buf.size());
	out_file.close();
}

//---------------------------------------------------------------------------------------
// 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/
//---------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
	try 
	{
		// 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(LicenseKey);

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

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

		// 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
		{
			cout << "Example 1: processing icr.pdf" << endl;

			// Open the .pdf document
			PDFDoc doc(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::e_linearized);
		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}

		//--------------------------------------------------------------------------------
		// Example 2) Process a subset of PDF pages
		try
		{
			cout << "Example 2: processing pages from icr.pdf" << endl;

			// Open the .pdf document
			PDFDoc doc(input_path + "icr.pdf");

			// Process handwriting with custom options
			HandwritingICROptions options;

			// 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::e_linearized);
		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}

		//--------------------------------------------------------------------------------
		// Example 3) Ignore zones specified for each page
		try
		{
			cout << "Example 3: processing & ignoring zones" << endl;

			// Open the .pdf document
			PDFDoc doc(input_path + "icr.pdf");

			// Process handwriting with custom options
			HandwritingICROptions options;

			// Process page 2 by ignoring the signature area on the bottom
			options.SetPages("2");
			RectCollection ignore_zones_page2;
			// 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::e_linearized);
		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}

		//--------------------------------------------------------------------------------
		// 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
		{
			cout << "Example 4: extract & apply" << endl;

			// Open the .pdf document
			PDFDoc doc(input_path + "icr.pdf");

			// Extract ICR results in JSON format
			UString json = HandwritingICRModule::GetICRJsonFromPDF(doc);
			WriteTextToFile(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::e_linearized);
		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}

		cout << "Done." << endl;

		PDFNet::Terminate();
	}
	catch (Common::Exception& e)	
	{
		cout << e << endl;
	}
	catch (...)
	{
		cout << "Unknown Exception" << endl;
	}

	return 0;	
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

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

import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;

import com.pdftron.common.PDFNetException;
import com.pdftron.pdf.*;
import com.pdftron.sdf.SDFDoc;

//---------------------------------------------------------------------------------------
// 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/
//---------------------------------------------------------------------------------------
public class HandwritingICRTest {

	static void writeTextToFile(String filename, String text) throws IOException
	{
		BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
		writer.write(text);
		writer.close();
	}

	public static void main(String[] args) {
		try {
			// 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())
			{
				System.out.println("");
				System.out.println("Unable to run HandwritingICRTest: Apryse SDK Handwriting ICR Module");
				System.out.println("not available.");
				System.out.println("---------------------------------------------------------------");
				System.out.println("The Handwriting ICR Module is an optional add-on, available for download");
				System.out.println("at https://dev.apryse.com/. If you have already downloaded this");
				System.out.println("module, ensure that the SDK is able to find the required files");
				System.out.println("using the PDFNet.addResourceSearchPath() function.");
				System.out.println("");
				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
			System.out.println("Example 1: processing icr.pdf");
				
			// Open the .pdf document
			try (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.SaveMode.LINEARIZED, null);
				doc.close();
			} catch (PDFNetException e) {
				e.printStackTrace();
			}

			//--------------------------------------------------------------------------------
			// Example 2) Process a subset of PDF pages
			System.out.println("Example 2: processing pages from icr.pdf");
				
			// Open the .pdf document
			try (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.SaveMode.LINEARIZED, null);
				doc.close();
			} catch (PDFNetException e) {
				e.printStackTrace();
			}

			//--------------------------------------------------------------------------------
			// Example 3) Ignore zones specified for each page
			System.out.println("Example 3: processing & ignoring zones");
				
			// Open the .pdf document
			try (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.SaveMode.LINEARIZED, null);
				doc.close();
			} catch (PDFNetException e) {
				e.printStackTrace();
			}

			//--------------------------------------------------------------------------------
			// 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
			System.out.println("Example 4: extract & apply");
				
			// Open the .pdf document
			try (PDFDoc doc = new PDFDoc(input_path + "icr.pdf"))
			{
				// Extract ICR results in JSON format
				String json = HandwritingICRModule.getICRJsonFromPDF(doc);
				writeTextToFile(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.SaveMode.LINEARIZED, null);
				doc.close();
			} catch (PDFNetException e) {
				e.printStackTrace();
			}
			catch (IOException e) {
				System.out.println(e);
			}
			System.out.println("Done.");
			PDFNet.terminate();
		} catch (PDFNetException e) {
			e.printStackTrace();
		}
	}
}
```

{% endcode %}
{% endtab %}

{% tab title="HTML" %}
{% code lineNumbers="true" %}

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

const fs = require('fs');
const { PDFNet } = require('../../lib/pdfnet.js');
const PDFTronLicense = require('../../LicenseKey/NODEJS/LicenseKey');

((exports) => {
  'use strict';

  //---------------------------------------------------------------------------------------
  // 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/
  //---------------------------------------------------------------------------------------
  exports.runHandwritingICRTest = () => {
    const main = async () => {
      try {
        // The location of the Handwriting ICR Module
        PDFNet.addResourceSearchPath('../../lib/');

        if (!(await PDFNet.HandwritingICRModule.isModuleAvailable())) {
          console.log('\nUnable to run HandwritingICRTest: Apryse SDK Handwriting ICR Module');
          console.log('not available.');
          console.log('---------------------------------------------------------------');
          console.log('The Handwriting ICR Module is an optional add-on, available for download');
          console.log('at https://dev.apryse.com/. If you have already downloaded this');
          console.log('module, ensure that the SDK is able to find the required files');
          console.log('using the PDFNet.addResourceSearchPath() function.\n');

          return;
        }

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

        //--------------------------------------------------------------------------------
        // Example 1) Process a PDF without specifying options
        try {
          console.log('Example 1: processing icr.pdf');

          // Open the .pdf document
          const doc = await PDFNet.PDFDoc.createFromFilePath(input_path + 'icr.pdf');

          // Run ICR on the .pdf with the default options
          await PDFNet.HandwritingICRModule.processPDF(doc);

          // Save the result with hidden text applied
          await doc.save(output_path + 'icr-simple.pdf', PDFNet.SDFDoc.SaveOptions.e_linearized);
        } catch (err) {
          console.log(err);
        }

        //--------------------------------------------------------------------------------
        // Example 2) Process a subset of PDF pages
        try {
          console.log('Example 2: processing pages from icr.pdf');

          // Open the .pdf document
          const doc = await PDFNet.PDFDoc.createFromFilePath(input_path + 'icr.pdf');

          // Process handwriting with custom options
          const options = await PDFNet.HandwritingICRModule.createHandwritingICROptions();

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

          // Run ICR on the .pdf
          await PDFNet.HandwritingICRModule.processPDF(doc, options);

          // Save the result with hidden text applied
          await doc.save(output_path + 'icr-pages.pdf', PDFNet.SDFDoc.SaveOptions.e_linearized);
        } catch (err) {
          console.log(err);
        }

        //--------------------------------------------------------------------------------
        // Example 3) Ignore zones specified for each page
        try {
          console.log('Example 3: processing & ignoring zones');

          // Open the .pdf document
          const doc = await PDFNet.PDFDoc.createFromFilePath(input_path + 'icr.pdf');

          // Process handwriting with custom options
          const options = await PDFNet.HandwritingICRModule.createHandwritingICROptions();

          // Process page 2 by ignoring the signature area on the bottom
          options.setPages("2");
          const ignore_zones_page2 = [];
          // 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.push(new PDFNet.Rect(78, 850.1 - 770, 340, 850.1 - 676));
          options.addIgnoreZonesForPage(ignore_zones_page2, 2);

          // Run ICR on the .pdf
          await PDFNet.HandwritingICRModule.processPDF(doc, options);

          // Save the result with hidden text applied
          await doc.save(output_path + 'icr-ignore.pdf', PDFNet.SDFDoc.SaveOptions.e_linearized);
        } catch (err) {
          console.log(err);
        }

        //--------------------------------------------------------------------------------
        // 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.log('Example 4: extract & apply');

          // Open the .pdf document
          const doc = await PDFNet.PDFDoc.createFromFilePath(input_path + 'icr.pdf');

          // Extract ICR results in JSON format
          const json = PDFNet.HandwritingICRModule.getICRJsonFromPDF(doc);
          fs.writeFileSync(output_path + "icr-get.json", json);

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

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

          // Save the result with hidden text applied
          await doc.save(output_path + 'icr-get-apply.pdf', PDFNet.SDFDoc.SaveOptions.e_linearized);
        } catch (err) {
          console.log(err);
        }

        console.log('Done.');

      } catch (err) {
        console.log(err);
      }
    };
    PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function(error) {
      console.log('Error: ' + JSON.stringify(error));
    }).then(function(){ return PDFNet.shutdown(); });
  };
  exports.runHandwritingICRTest();
})(exports);
// eslint-disable-next-line spaced-comment
//# sourceURL=HandwritingICRTest.js
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
<?php
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------
if(file_exists("../../../PDFNetC/Lib/PDFNetPHP.php"))
include("../../../PDFNetC/Lib/PDFNetPHP.php");
include("../../LicenseKey/PHP/LicenseKey.php");

// Relative path to the folder containing the test files.
$input_path = getcwd()."/../../TestFiles/HandwritingICR/";
$output_path = getcwd()."/../../TestFiles/Output/";

function WriteTextToFile($outputFile, $text)
{
	$outfile = fopen($outputFile, "w");
	fwrite($outfile, $text);
	fclose($outfile);
}

//---------------------------------------------------------------------------------------
// 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/
//---------------------------------------------------------------------------------------
	
	// 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($LicenseKey);
	PDFNet::GetSystemFontList();    // Wait for fonts to be loaded if they haven't already. This is done because PHP can run into errors when shutting down if font loading is still in progress.

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

	// Test if the add-on is installed
	if(!HandwritingICRModule::IsModuleAvailable()) {
		echo "Unable to run HandwritingICRTest: PDFTron SDK Handwriting ICR Module\n
			not available.\n
			---------------------------------------------------------------\n
			The Handwriting ICR Module is an optional add-on, available for download\n
			at https://dev.apryse.com/. If you have already downloaded this\n
			module, ensure that the SDK is able to find the required files\n
			using the PDFNet::AddResourceSearchPath() function.\n";
	} else
	{
		//--------------------------------------------------------------------------------
		// Example 1) Process a PDF without specifying options
		echo "Example 1: processing icr.pdf\n";
	 
		// Open the .pdf document
		$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::e_linearized);
		$doc->Close();

		//--------------------------------------------------------------------------------
		// Example 2) Process a subset of PDF pages
		echo "Example 2: processing pages from icr.pdf\n";
	 
		// Open the .pdf document
		$doc = new PDFDoc($input_path."icr.pdf");

		// Process handwriting with custom options
		$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::e_linearized);
		$doc->Close();

		//--------------------------------------------------------------------------------
		// Example 3) Ignore zones specified for each page
		echo "Example 3: processing & ignoring zones\n";
	 
		// Open the .pdf document
		$doc = new PDFDoc($input_path."icr.pdf");

		// Process handwriting with custom options
		$options = new HandwritingICROptions();
		
		// Process page 2 by ignoring the signature area on the bottom
		$options->SetPages("2");
		$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.
		$rect = new Rect(78.0, 850.1 - 770.0, 340.0, 850.1 - 676.0);
		$ignore_zones_page2->AddRect($rect);
		$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::e_linearized);
		$doc->Close();

		//--------------------------------------------------------------------------------
		// 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
		echo "Example 4: extract & apply\n";
	 
		// Open the .pdf document
		$doc = new PDFDoc($input_path."icr.pdf");
		
		// Extract ICR results in JSON format
		$json = HandwritingICRModule::GetICRJsonFromPDF($doc);
		WriteTextToFile($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::e_linearized);
		$doc->Close();

		echo "Done.\n";
	}
	PDFNet::Terminate();

?>
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

import site
site.addsitedir("../../../PDFNetC/Lib")
import sys
from PDFNetPython import *

sys.path.append("../../LicenseKey/PYTHON")
from LicenseKey import *

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

def WriteTextToFile(outputFile, text):
    # Write the contents of text to the disk
    f = open(outputFile, "w")
    try:
        f.write(text)
    finally:
        f.close()

# ---------------------------------------------------------------------------------------
# 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/
# --------------------------------------------------------------------------------------

def main():

    # 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(LicenseKey)

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

    # Test if the add-on is installed
    if not HandwritingICRModule.IsModuleAvailable():

        print("""
        Unable to run HandwritingICRTest: Apryse SDK Handwriting ICR Module
        not available.
        ---------------------------------------------------------------
        The Handwriting ICR Module is an optional add-on, available for download
        at https://dev.apryse.com/. If you have already downloaded this
        module, ensure that the SDK is able to find the required files
        using the PDFNet.AddResourceSearchPath() function.""")

    else:

        # --------------------------------------------------------------------------------
        # Example 1) Process a PDF without specifying options
        print("Example 1: processing icr.pdf")

        # Open the .pdf document
        doc = 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.e_linearized)
        doc.Close()

        # --------------------------------------------------------------------------------
        # Example 2) Process a subset of PDF pages
        print("Example 2: processing pages from icr.pdf")

        # Open the .pdf document
        doc = PDFDoc(input_path + "icr.pdf")

        # Process handwriting with custom options
        options = 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.e_linearized)
        doc.Close()

        # --------------------------------------------------------------------------------
        # Example 3) Ignore zones specified for each page
        print("Example 3: processing & ignoring zones")

        # Open the .pdf document
        doc = PDFDoc(input_path + "icr.pdf")

        # Process handwriting with custom options
        options = HandwritingICROptions()
        
        # Process page 2 by ignoring the signature area on the bottom
        options.SetPages("2")
        ignore_zones_page2 = 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(Rect(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.e_linearized)
        doc.Close()

        # --------------------------------------------------------------------------------
        # 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
        print("Example 4: extract & apply")

        # Open the .pdf document
        doc = PDFDoc(input_path + "icr.pdf")

        # Extract ICR results in JSON format
        json = HandwritingICRModule.GetICRJsonFromPDF(doc)
        WriteTextToFile(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.e_linearized)
        doc.Close()

        print("Done.")

        PDFNet.Terminate()


if __name__ == '__main__':
    main()

```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

require '../../../PDFNetC/Lib/PDFNetRuby'
include PDFNetRuby
require '../../LicenseKey/RUBY/LicenseKey'

$stdout.sync = true

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

#---------------------------------------------------------------------------------------
# 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/
#---------------------------------------------------------------------------------------

# 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("../../../PDFNetC/Lib/");

begin

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

	else

		# --------------------------------------------------------------------------------
		# Example 1) Process a PDF without specifying options
		puts "Example 1: processing icr.pdf"

		# Open the .pdf document
		doc = PDFDoc.new($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::E_linearized)
		doc.Close

		# --------------------------------------------------------------------------------
		# Example 2) Process a subset of PDF pages
		puts "Example 2: processing pages from icr.pdf"

		# Open the .pdf document
		doc = PDFDoc.new($input_path + "icr.pdf")

		# Process handwriting with custom options
		options = HandwritingICROptions.new

		# 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::E_linearized)
		doc.Close

		# --------------------------------------------------------------------------------
		# Example 3) Ignore zones specified for each page
		puts "Example 3: processing & ignoring zones"

		# Open the .pdf document
		doc = PDFDoc.new($input_path + "icr.pdf")

		# Process handwriting with custom options
		options = HandwritingICROptions.new

		# Process page 2 by ignoring the signature area on the bottom
		options.SetPages("2")
		ignore_zones_page2 = RectCollection.new
		# 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(Rect.new(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::E_linearized)
		doc.Close

		# --------------------------------------------------------------------------------
		# 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
		puts "Example 4: extract & apply"

		# Open the .pdf document
		doc = PDFDoc.new($input_path + "icr.pdf")

		# Extract ICR results in JSON format
		json = HandwritingICRModule.GetICRJsonFromPDF(doc)
		File.open($output_path + "icr-get.json", 'w') { |file| file.write(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::E_linearized)
		doc.Close

		print("Done.")
	end

rescue => error
	puts "Unable to extract handwriting, error: " + error.message
end

PDFNet.Terminate
```

{% endcode %}
{% endtab %}

{% tab title="VB" %}
{% code lineNumbers="true" %}

```vb
'---------------------------------------------------------------------------------------
' Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
' Consult legal.txt regarding legal and license information.     
'---------------------------------------------------------------------------------------
Imports System

Imports pdftron
Imports pdftron.Common
Imports pdftron.SDF
Imports pdftron.PDF

' <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>
Module HandwritingICRTestVB
    Dim pdfNetLoader As PDFNetLoader
    Sub New()
        pdfNetLoader = pdftron.PDFNetLoader.Instance()
    End Sub

    ' The main entry point for the application.
    Sub Main()

        ' 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 Not HandwritingICRModule.IsModuleAvailable() Then
            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
        End If

        ' Relative path to the folder containing test files.
        Dim input_path As String = "../../../../TestFiles/HandwritingICR/"
        Dim output_path As String = "../../../../TestFiles/Output/"

        '--------------------------------------------------------------------------------
        ' Example 1) Process a PDF without specifying options
        Try
            Console.WriteLine("Example 1: processing icr.pdf")

            ' Open the .pdf document
            Using doc As PDFDoc = 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()
            End Using
        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try

        '--------------------------------------------------------------------------------
        ' Example 2) Process a subset of PDF pages
        Try
            Console.WriteLine("Example 2: processing pages from icr.pdf")

            ' Open the .pdf document
            Using doc As PDFDoc = New PDFDoc(input_path + "icr.pdf")
                ' Process handwriting with custom options
                Dim options As 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()
            End Using
        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try

        '--------------------------------------------------------------------------------
        ' Example 3) Ignore zones specified for each page
        Try
            Console.WriteLine("Example 3: processing & ignoring zones")

            ' Open the .pdf document
            Using doc As PDFDoc = New PDFDoc(input_path + "icr.pdf")
                ' Process handwriting with custom options
                Dim options As New HandwritingICROptions()

                ' Process page 2 by ignoring the signature area on the bottom
                options.SetPages("2")
                Dim ignore_zones_page2 As 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()
            End Using
        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try

        '--------------------------------------------------------------------------------
        ' 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 doc As PDFDoc = New PDFDoc(input_path + "icr.pdf")
                ' Extract ICR results in JSON format
                Dim json As String = 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-ignore.pdf", SDFDoc.SaveOptions.e_linearized)
                doc.Close()
            End Using
        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try

        Console.WriteLine("Done.")
        PDFNet.Terminate()
    End Sub

End Module
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

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

#import <OBJC/PDFNetOBJC.h>
#import <Foundation/Foundation.h>

//---------------------------------------------------------------------------------------
// 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/
//---------------------------------------------------------------------------------------

int main (int argc, const char * argv[])
{
    @autoreleasepool {
    
        // The first step in every application using PDFNet is to initialize the 
        // library. The library is usually initialized only once, but calling 
        // Initialize() multiple times is also fine.
        [PTPDFNet Initialize: 0];
        // The location of the Handwriting ICR Module
        [PTPDFNet AddResourceSearchPath:@"../../../Lib/"];
        
        // Test if the add-on is installed
        if (![PTHandwritingICRModule IsModuleAvailable]) {
            NSLog(@"");
            NSLog(@"Unable to run HandwritingICRTest: Apryse Handwriting ICR Module");
            NSLog(@"not available.");
            NSLog(@"---------------------------------------------------------------");
            NSLog(@"The Handwriting ICR Module is an optional add-on, available for download");
            NSLog(@"at https://docs.apryse.com/documentation/core/info/modules/. If you have already");
            NSLog(@"downloaded this module, ensure that the SDK is able to find the required files");
            NSLog(@"using the [PDFNet AddResourceSearchPath:] function.");
            NSLog(@"");

            return 1;
        }
        
        NSString *inputPath = @"../../TestFiles/HandwritingICR/";
        NSString *outputPath = @"../../TestFiles/Output/";

        int ret = 0;

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

            // Open the .pdf document
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: [inputPath stringByAppendingString:@"icr.pdf"]];
            
            // Run ICR on the .pdf with the default options
            [PTHandwritingICRModule ProcessPDF: doc options: nil];
            
            // Save the result with hidden text applied
            [doc SaveToFile: [outputPath stringByAppendingString: @"icr-simple.pdf"] flags: e_ptlinearized];
            [doc Close];
        }
        @catch (NSException *e) {
            NSLog(@"Exception: %@ - %@\n", e.name, e.reason);
            ret = 1;
        }

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

            // Open the .pdf document
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: [inputPath stringByAppendingString:@"icr.pdf"]];

            // Process handwriting with custom options
            PTHandwritingICROptions* options = [[PTHandwritingICROptions alloc] init];

            // Optionally, process a subset of pages
            [options SetPages: @"2-3"];
            
            // Run ICR on the .pdf
            [PTHandwritingICRModule ProcessPDF: doc options: options];
            
            // Save the result with hidden text applied
            [doc SaveToFile: [outputPath stringByAppendingString: @"icr-pages.pdf"] flags: e_ptlinearized];
            [doc Close];
        }
        @catch (NSException *e) {
            NSLog(@"Exception: %@ - %@\n", e.name, e.reason);
            ret = 1;
        }

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

            // Open the .pdf document
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: [inputPath stringByAppendingString:@"icr.pdf"]];

            // Process handwriting with custom options
            PTHandwritingICROptions* options = [[PTHandwritingICROptions alloc] init];

            // Process page 2 by ignoring the signature area on the bottom
            [options SetPages: @"2"];
            PTPDFRectCollection* ignore_zones_page2 = [[PTPDFRectCollection alloc] init];
            // 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: [[PTPDFRect alloc] initWithX1: 78 y1: 850.1 - 770 x2: 340 y2: 850.1 - 676]];
            [options AddIgnoreZonesForPage: ignore_zones_page2 page_num: 2];
            
            // Run ICR on the .pdf
            [PTHandwritingICRModule ProcessPDF: doc options: options];
            
            // Save the result with hidden text applied
            [doc SaveToFile: [outputPath stringByAppendingString: @"icr-ignore.pdf"] flags: e_ptlinearized];
            [doc Close];
        }
        @catch (NSException *e) {
            NSLog(@"Exception: %@ - %@\n", e.name, e.reason);
            ret = 1;
        }

        //--------------------------------------------------------------------------------
        // 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 {
            NSLog(@"Example 4: extract & apply");

            // Open the .pdf document
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: [inputPath stringByAppendingString:@"icr.pdf"]];

            // Extract ICR results in JSON format
            NSString *json = [PTHandwritingICRModule GetICRJsonFromPDF: doc options: nil];
            [json writeToFile: [outputPath stringByAppendingString: @"icr-get.json"] atomically:YES encoding:NSUTF8StringEncoding error:nil];

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

            // Apply potentially modified ICR JSON to the PDF
            [PTHandwritingICRModule ApplyICRJsonToPDF: doc json: json];
            
            // Save the result with hidden text applied
            [doc SaveToFile: [outputPath stringByAppendingString: @"icr-get-apply.pdf"] flags: e_ptlinearized];
            [doc Close];
        }
        @catch (NSException *e) {
            NSLog(@"Exception: %@ - %@\n", e.name, e.reason);
            ret = 1;
        }
        
        NSLog(@"Done.");
        [PTPDFNet Terminate: 0];
        return ret;
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/core/get-started/samples/icrtest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
