> 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/handwriting-icr/workflow.md).

# Handwriting Intelligent Character Recognition (ICR) workflows for the Apryse Server SDK

Learn how to use the Handwriting ICR module with Apryse Server SDK to create searchable PDFs and extract handwritten text from documents. Get code samples and metadata as JSON for further processing.

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

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

<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 %}

This guide includes handwriting ICR workflows starting with the simplest use cases, then moving to more advanced use cases.

## Process a scanned document

Make a searchable PDF by adding invisible text to an image-based PDF, such as a scanned document, using Handwriting ICR.

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

```cpp
PDFDoc doc(input_pdf_path);

// Run ICR on the .pdf with the default options.
HandwritingICRModule::ProcessPDF(doc);
```

{% endcode %}
{% endtab %}

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

```csharp
PDFDoc doc = new PDFDoc(input_pdf_path);

// Run ICR on the .pdf with the default options.
HandwritingICRModule.ProcessPDF(doc);
```

{% endcode %}
{% endtab %}

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

```go
doc := NewPDFDoc(input_pdf_path)
// Run ICR on the .pdf with the default options.
HandwritingICRModuleProcessPDF(doc)
```

{% endcode %}
{% endtab %}

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

```vb
Using doc As PDFDoc = New PDFDoc(input_pdf_path)

   ' Run ICR on the .pdf with the default options.
   HandwritingICRModule.ProcessPDF(doc)
      
End Using
```

{% endcode %}
{% endtab %}

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

```java
PDFDoc doc = new PDFDoc(input_pdf_path);

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

{% endcode %}
{% endtab %}

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

```js
async function main() {
   const doc = await PDFNet.PDFDoc.createFromFilePath(input_pdf_path);

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

{% endcode %}
{% endtab %}

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

```objc
PTPDFDoc * doc = [[PTPDFDoc alloc] initWithFilepath: [input_pdf_path]];

// Run ICR on the .pdf with the default options
[PTHandwritingICRModule ProcessPDF: doc options: nil];
```

{% endcode %}
{% endtab %}

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

```python
doc = PDFDoc(input_pdf_path)

# Run ICR on the .pdf with the default options
HandwritingICRModule.ProcessPDF(doc)
```

{% endcode %}
{% endtab %}

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

```php
$doc = new PDFDoc($input_pdf_path);

// Run ICR on the .pdf with the default options
HandwritingICRModule::ProcessPDF($doc);
```

{% endcode %}
{% endtab %}

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

```ruby
doc = PDFDoc.new(input_pdf_path)

# Run ICR on the .pdf with the default options
HandwritingICRModule.ProcessPDF(doc)
```

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

### Full code sample to process a scanned document

We also have a [full code sample to add searchable/selectable text to an image-based PDF, like a scanned document,](/core/handwriting-icr/samples.md) which shows how to use the Apryse Handwriting ICR module on scanned documents in multiple programming languages. The Handwriting ICR module can make searchable PDFs and extract scanned text for further indexing. Samples are available in Python, C# (.Net), C++, Go, Java, Node.js (JavaScript), PHP, Ruby, VB, and Obj-C.

## Extract handwritten text as JSON

If you want to apply raw ICR output to the input document, you can call `HandwritingICRModule.ProcessPDF`. However, it is likely that some post-processing will be beneficial, e.g., common spell checker or comparing results against white/blacklists. For this purpose, you can, first, extract text and corresponding metadata as JSON before re-applying the processed results to the input document.

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

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

// Extract ICR results in JSON format.
UString json = HandwritingICRModule::GetICRJsonFromPDF(doc);

// Post-processing step (whatever it might be) 

// Re-apply results. 
HandwritingICRModule::ApplyICRJsonToPDF(doc, json);
```

{% endcode %}
{% endtab %}

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

```csharp
// Open the .pdf document
PDFDoc doc = new PDFDoc(input_pdf_path);

// Extract ICR results in JSON format
string json = HandwritingICRModule.GetICRJsonFromPDF(doc);

// Post-processing step (whatever it might be) 

// Re-apply results. 
HandwritingICRModule.ApplyICRJsonToPDF(doc, json);
```

{% endcode %}
{% endtab %}

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

```go
doc := NewPDFDoc(input_pdf_path)
json := HandwritingICRModuleGetICRJsonFromPDF(doc)
// Post-processing step (whatever it might be)
// Re-apply results. 
HandwritingICRModuleApplyICRJsonToPDF(doc, json)
```

{% endcode %}
{% endtab %}

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

```vb
' Open the .pdf document
Using doc As PDFDoc = New PDFDoc(input_pdf_path)
	' Extract ICR results in JSON format
	 Dim json As String = HandwritingICRModule.GetICRJsonFromPDF(doc)

	' Post-processing step (whatever it might be) 

	' Re-apply results. 
	HandwritingICRModule.ApplyICRJsonToPDF(doc, json)

End Using
```

{% endcode %}
{% endtab %}

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

```java
// Open the .pdf document
PDFDoc doc = new PDFDoc(input_pdf_path);

// Extract ICR results in JSON format
String json = HandwritingICRModule.getICRJsonFromPDF(doc);

// Post-processing step (whatever it might be) 

// Re-apply results. 
HandwritingICRModule.applyICRJsonToPDF(doc, json);
```

{% endcode %}
{% endtab %}

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

```js
async function main() {
   // Open the .pdf document
   const doc = await PDFNet.PDFDoc.createFromFilePath(input_pdf_path);
   
   // Extract ICR results in JSON format
   const json = await PDFNet.HandwritingICRModule.getICRJsonFromPDF(doc);

   // Post-processing step (whatever it might be) 

   // Re-apply results. 
   await PDFNet.HandwritingICRModule.applyICRJsonToPDF(doc, json);
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

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

```objc
// Open the .pdf document
PTPDFDoc * doc = [[PTPDFDoc alloc] initWithFilepath: input_pdf_path];

// Extract OCR results as JSON
NSString * json = [PTHandwritingICRModule GetICRJsonFromPDF: doc options: nil];

// Post-processing step (whatever it might be) 

// Re-apply results. 
[PTHandwritingICRModule ApplyICRJsonToPDF: doc json: json];
```

{% endcode %}
{% endtab %}

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

```python
# Open the .pdf document
doc = PDFDoc(input_pdf_path)

# Extract OCR results as JSON
json = HandwritingICRModule.GetICRJsonFromPDF(doc)

# Post-processing step (whatever it might be) 

# Re-apply results. 
HandwritingICRModule.ApplyICRJsonToPDF(doc, json)
```

{% endcode %}
{% endtab %}

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

```php
// Open the .pdf document
$doc = new PDFDoc($input_pdf_path);

// Extract ICR results in JSON format
$json = HandwritingICRModule::GetICRJsonFromPDF($doc);

// Post-processing step (whatever it might be) 

// Re-apply results. 
HandwritingICRModule::ApplyICRJsonToPDF($doc, $json);
```

{% endcode %}
{% endtab %}

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

```ruby
# Open the .pdf document
doc = PDFDoc.new(input_pdf_path)

# Extract ICR results in JSON format
json = HandwritingICRModule.GetICRJsonFromPDF(doc)

# Post-processing step (whatever it might be) 

# Re-apply results. 
HandwritingICRModule.ApplyICRJsonToPDF(doc, json)
```

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

### Output Attributes

ICR output consists of nested arrays:

* Array of pages.
* Array of paragraphs.
* Array of lines.
* Array of words.

Pages have additional metadata:

| Attribute | Value      | Description                                                                               |
| --------- | ---------- | ----------------------------------------------------------------------------------------- |
| num       |            | page number                                                                               |
| dpi       |            | document resolution (needed to correctly scale the coordinates from points to pixels)     |
| origin    | TopLeft    | coordinate system has origin at the top left corner (default)                             |
|           | BottomLeft | coordinate system has origin at the bottom left corner (i.e., PDF page coordinate system) |

Then, each word in the ICR output includes the following:

| Attribute                                                                                                               | Value                                       | Description                    |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ------------------------------ |
| x                                                                                                                       | bounding box lower left corner x coordinate |                                |
| y                                                                                                                       | bounding box lower left corner y coordinate |                                |
| length                                                                                                                  | length of bounding box                      |                                |
| font-size                                                                                                               | text's font size                            |                                |
| text                                                                                                                    | text output                                 |                                |
| orientation                                                                                                             | L                                           | 270 degrees clockwise rotation |
|                                                                                                                         | R                                           | 90 degrees clockwise rotation  |
|                                                                                                                         | D                                           | 180 degrees clockwise rotation |
|                                                                                                                         | U                                           | 0 degrees clockwise rotation   |
| Each line has an optional `box` property consisting of 4 values having the same interpretation as `pdftron::PDF::Rect`. |                                             |                                |

## External ICR results

The API can also be used to apply ICR JSON generated by different OCR or ICR engines. The expected structure for input JSON is:

{% tabs %}
{% tab title="JSON" %}
{% code lineNumbers="true" %}

```json
{  
   "Page":[  
    	{  
          "Word":[  
              {  
                  "font-size": 12,
                  "length": 43,
                  "text":"ABC",
                  "x": 321,
                  "y": 141
              }
         ],
         "num": 1,
         "dpi": 96,
         "origin": "TopLeft"
      	}
   ]
}
```

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

Note that the ICR structure is simplified and we're expecting an array of `Page`, with each page consisting of `Word` array. Each `Word` is described by its text content and 4 typographic point values (font-size="12" x="321" y="141" length="43" in the example above) needed to construct the bounding box for placement of text on a page.


---

# 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/handwriting-icr/workflow.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.
