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

# OCR workflows: output, language & quality on Server/Desktop

Learn how to use the IRIS OCR module with Apryse SDK to create searchable PDFs and extract text from scanned documents in multiple languages. Get code samples and metadata as JSON for further processi

{% 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#OpticalCharacterRecognition(OCR)" class="button primary">Package: OCR</a><a href="/core/learn-more/modules.md#default-ocr-module" class="button primary">Module: OCR</a><a href="https://showcase.apryse.com/ocr-module" class="button primary">Live demo</a>
{% endhint %}

{% hint style="info" %}
**IRIS OCR module**

If only one OCR module is present (either the IRIS or default or alternative OCR module), Apryse SDK will use that module automatically (license permitting). When multiple OCR modules are present, the IRIS module can be selected using the OCR options object: \`OCROptions.setEngine("iris")\`.
{% endhint %}

To make a searchable PDF by adding invisible text to an image using OCR.

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

```cpp
PDFDoc doc;

// Run OCR on the image without options
OCRModule::ImageToPDF(doc, image_path, NULL);
```

{% endcode %}
{% endtab %}

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

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

// Run OCR on the image without options            
OCRModule.ImageToPDF(doc, image_path, null);
```

{% endcode %}
{% endtab %}

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

```go
doc := NewPDFDoc()
// Run OCR on the image without options
ocrOpts := NewOCROptions()
OCRModuleImageToPDF(doc, image_path, ocrOpts)
```

{% endcode %}
{% endtab %}

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

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

   ' Run OCR on the image without options
   OCRModule.ImageToPDF(doc, image_path, nil)
      
End Using
```

{% endcode %}
{% endtab %}

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

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

// Run OCR on the image without options
OCRModule.imageToPDF(doc, image_path, null);
```

{% endcode %}
{% endtab %}

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

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

   // Run OCR on the image without options
   await PDFNet.OCRModule.imageToPDF(doc, image_path);
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

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

```objc
PTPDFDoc * doc = [[PTPDFDoc alloc] init];

// Run OCR on the image without options
[PTOCRModule ImageToPDF: doc src: image_path options: nil];
```

{% endcode %}
{% endtab %}

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

```python
doc = PDFDoc()

# Run OCR on the image without options
OCRModule.ImageToPDF(doc, image_path, None)
```

{% endcode %}
{% endtab %}

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

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

// Run OCR on the image without options
OCRModule::ImageToPDF($doc, $image_path, NULL);
```

{% endcode %}
{% endtab %}

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

```ruby
doc = PDFDoc.new

# Run OCR on the image without options
OCRModule.ImageToPDF(doc, image_path, nil)
```

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

[Convert images to PDF with searchable/selectable text](/core/get-started/samples/ocrtest.md) Full code sample which shows how to use the Apryse OCR module on scanned documents in multiple languages. The OCR module can make searchable PDFs and extract scanned text for further indexing. Samples available in Python, C# (.Net), C++, Go, Java, Node.js (JavaScript), PHP, Ruby, VB.

## Process a scanned document

To make a searchable PDF by adding invisible text to an image based PDF such as a scanned document using OCR.

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

```cpp
PDFDoc doc(filename);

// Set English as the language of choice
OCROptions opts;
opts.AddLang("eng");

// Run OCR on the PDF with options
OCRModule::ProcessPDF(doc, &opts);
```

{% endcode %}
{% endtab %}

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

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

// Set English as the language of choice
OCROptions opts = new OCROptions();
opts.AddLang("eng");

// Run OCR on the PDF with options            
OCRModule.ProcessPDF(doc, opts);
```

{% endcode %}
{% endtab %}

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

```go
doc = NewPDFDoc(filename)
// Set English as the language of choice
opts = NewOCROptions()
opts.AddLang("eng")
// Run OCR on the PDF with options
OCRModuleProcessPDF(doc, opts)
```

{% endcode %}
{% endtab %}

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

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

   ' Set English as the language of choice
   Dim opts As OCROptions = New OCROptions()
   opts.AddLang("eng")

   ' Run OCR on the PDF with options
   OCRModule.ProcessPDF(doc, opts)
      
End Using
```

{% endcode %}
{% endtab %}

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

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

// Set English as the language of choice
OCROptions options = new OCROptions();
options.addLang("eng");

// Run OCR on the PDF with options
OCRModule.processPDF(doc, options);
```

{% endcode %}
{% endtab %}

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

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

   // Set English as the language of choice
   const opts = new PDFNet.OCRModule.OCROptions();
   opts.addLang("eng");

   // Run OCR on the PDF with options
   await PDFNet.OCRModule.processPDF(doc, opts);
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

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

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

// Set English as the language of choice
PTObjSet * set = [[PTObjSet alloc] init];
PTObj * options = [set CreateDict];
PTObj * lang_array = [options PutArray: @"Langs"];
[lang_array PushBackString: @"eng"];

// Run OCR on the PDF with options
[PTOCRModule ProcessPDF: doc options: options];
```

{% endcode %}
{% endtab %}

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

```python
doc = PDFDoc(filename)

# Set English as the language of choice
opts = OCROptions()
opts.AddLang("eng")

# Run OCR on the PDF with options
OCRModule.ProcessPDF(doc, opts)
```

{% endcode %}
{% endtab %}

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

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

// Set English as the language of choice
$opts = new OCROptions();
$opts->AddLang("eng");

// Run OCR on the PDF with options
OCRModule::ProcessPDF($doc, $opts);
```

{% endcode %}
{% endtab %}

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

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

# Set English as the language of choice
opts = OCROptions.new
opts.AddLang("eng")

# Run OCR on the PDF with options
CRModule.ProcessPDF(doc, opts)
```

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

[Add searchable/selectable text to an image based PDF like a scanned document](/core/get-started/samples/ocrtest.md) Full code sample which shows how to use the Apryse OCR module on scanned documents in multiple languages. The OCR module can make searchable PDFs and extract scanned text for further indexing. Samples available in Python, C# (.Net), C++, Go, Java, Node.js (JavaScript), PHP, Ruby, VB

## Get metadata as JSON

If you want to apply raw OCR output to the input document, you can either call `OCRModule::ImageToPDF` (if input file is an image) or `OCROptions::ProcessPDF` (for a PDF). However, it is likely that some post-processing will be beneficial, e.g., comparing results against white/black lists. To this purpose, you can first extract text and corresponding metadata as either JSON or XML before re-applying processed results to the input document.

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

```cpp
// Setup empty destination doc
PDFDoc doc;

std:string image_path = "path/to/image";

// Extract OCR results as JSON
UString json = OCRModule::GetOCRJsonFromImage(doc, image_path, opts);

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

// Re-apply results. 
OCRModule::ApplyOCRJsonToPDF(doc, json);
```

{% endcode %}
{% endtab %}

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

```csharp
// Setup empty destination doc
PDFDoc doc = new PDFDoc();
string image_path = "path/to/image";

// Extract OCR results as JSON
string json = OCRModule.GetOCRJsonFromImage(doc, image_path, opts);

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

// Re-apply results. 
OCRModule.ApplyOCRJsonToPDF(doc, json);
```

{% endcode %}
{% endtab %}

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

```go
doc := NewPDFDoc()
image_path = "path/to/image"
opts = NewOCROptions()
json := OCRModuleGetOCRJsonFromImage(doc, image_path, opts)
// Post-processing step (whatever it might be)
// Re-apply results. 
OCRModuleApplyOCRJsonToPDF(doc, json)
```

{% endcode %}
{% endtab %}

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

```vb
' Setup empty destination doc
Using doc As PDFDoc = New PDFDoc()
	 Dim image_path As String = "path/to/image"

	' Extract OCR results as JSON
	 Dim json As String = OCRModule.GetOCRJsonFromImage(doc, image_path, opts)

	' Post-processing step (whatever it might be) 

	' Re-apply results. 
	OCRModule.ApplyOCRJsonToPDF(doc, json)

End Using
```

{% endcode %}
{% endtab %}

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

```java
// Setup empty destination doc
PDFDoc doc = new PDFDoc();
String image_path = "path/to/image";

// Extract OCR results as JSON
String json = OCRModule.getOCRJsonFromImage(doc, image_path, opts);

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

// Re-apply results. 
OCRModule.applyOCRJsonToPDF(doc, json);
```

{% endcode %}
{% endtab %}

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

```js
async function main() {
   // Setup empty destination doc
   const doc = await PDFNet.PDFDoc.create();
   const image_path = "path/to/image";

   // Extract OCR results as JSON
   const json = await PDFNet.OCRModule.getOCRJsonFromImage(doc, image_path, opts);

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

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

{% endcode %}
{% endtab %}

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

```objc
// Setup empty destination doc
PTPDFDoc * doc = [[PTPDFDoc alloc] init];

NSString * image_path = @"path/to/image";

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

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

// Re-apply results. 
[PTOCRModule ApplyOCRJsonToPDF: doc json: json];
```

{% endcode %}
{% endtab %}

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

```python
# Setup empty destination doc
doc = PDFDoc()
image_path = "path/to/image"

# Extract OCR results as JSON
json = OCRModule.GetOCRJsonFromImage(doc, image_path, opts)

# Post-processing step (whatever it might be) 

# Re-apply results. 
OCRModule.ApplyOCRJsonToPDF(doc, json)
```

{% endcode %}
{% endtab %}

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

```php
// Setup empty destination doc
$doc = new PDFDoc();
$image_path = "path/to/image";

// Extract OCR results as JSON
$json = OCRModule::GetOCRJsonFromImage($doc, $image_path, $opts);

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

// Re-apply results. 
OCRModule::ApplyOCRJsonToPDF($doc, $json);
```

{% endcode %}
{% endtab %}

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

```ruby
# Setup empty destination doc
doc = PDFDoc.new

image_path = "path/to/image"

# Extract OCR results as JSON
json = OCRModule.GetOCRJsonFromImage(doc, image_path, opts)

# Post-processing step (whatever it might be) 

# Re-apply results. 
OCRModule.ApplyOCRJsonToPDF(doc, json)
```

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

### Output Attributes

OCR 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 OCR output has the following:

| Attribute                                                                                                                        | Value                                      | Description                    |
| -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------------------ |
| x                                                                                                                                | bouding box lower left corner x coordinate |                                |
| y                                                                                                                                | bouding 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   |
| Finally, each line has an optional `box` property consisting of 4 values having the same interpretation as `pdftron::PDF::Rect`. |                                            |                                |

### Sample JSON output

Below is a sample JSON output that the OCR module would output.

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

```json
{  
   "Page":[  
      {  
         "Para":[  
            {  
               "Line":[  
                  {  
                     "Word":[  
                        {  
                           "font-size": 27,
                           "length": 64,
                           "orientation": "U",
                           "text":"Hello",
                           "x": 273,
                           "y": 265
                        }
                     ],
                     "box":[  
                        273,
                        265,
                        64,
                        29
                     ]
                  }
               ]
            }
         ],
         "num": 1,
         "dpi": 96,
         "origin": "BottomLeft"
      }
   ]
}
```

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

## External OCR results

The API can also be used to apply OCR XML/JSON generated by different OCR engines. The expected structure for input JSON and XML respectively are:

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

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

```xml
<Doc>
	<Page num="1" origin="TopLeft" dpi="96">
		<Word font-size="12" x="321" y="141" length="43">ABC</Word>
	</Page>
</Doc>
```

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

Note that the OCR structure is simplified and we are 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 (i.e., 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.

## Language options

You use `pdftron.PDF.OCROptions` convenience class to pass OCR parameters. You can call `pdftron.PDF.OCROptions.AddLang` to pick a target language. If no language option is set, English is assumed.

You can review the [lists of supported languages](/core/ocr/ocr.md) for the default, alternative, and IRIS OCR.

{% hint style="warning" %}
Only one of the Chinese (traditional), Chinese (simplified), Japanese and Korean can be selected at the same time
{% endhint %}

## Adding languages to the alternative OCR module

Additional [trained language files](https://github.com/tesseract-ocr/tessdata/) can be placed in the search path ( which can be registered using `PDFNet::AddResourceSearchPath` ). Afterwards, they can be referred to via their file prefix.

## Multiple languages

Multiple languages can be specified, although it is not recommended to use more than 3 languages.

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

```cpp
// Add French, Spanish and default English to target languages
OCROptions opts;
opts.AddLang("fra");
opts.AddLang("spa");
```

{% endcode %}
{% endtab %}

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

```csharp
// Add French, Spanish and default English to target languages
OCROptions opts = new OCROptions();
opts.AddLang("fra");
opts.AddLang("spa");
```

{% endcode %}
{% endtab %}

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

```go
opts = NewOCROptions()
opts.AddLang("fra")
opts.AddLang("spa")
```

{% endcode %}
{% endtab %}

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

```vb
' Add French, Spanish and default English to target languages
Dim opts As OCROptions = New OCROptions()
opts.AddLang("fra")
opts.AddLang("spa")
```

{% endcode %}
{% endtab %}

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

```java
// Add French, Spanish and default English to target languages
OCROptions opts = new OCROptions();
opts.addLang("fra");
opts.addLang("spa");
```

{% endcode %}
{% endtab %}

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

```js
async function main() {
   // Add French, Spanish and default English to target languages
   const opts = new PDFNet.OCRModule.OCROptions();
   opts.addLang("fra");
   opts.addLang("spa");
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

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

```objc
// Add French, Spanish and default English to target languages
PTObjSet * set = [[PTObjSet alloc] init];
PTObj * options = [set CreateDict];
PTObj * lang_array = [options PutArray: @"Langs"];
[lang_array PushBackString: @"fra"];
[lang_array PushBackString: @"spa"];
```

{% endcode %}
{% endtab %}

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

```python
# Add French, Spanish and default English to target languages
opts = OCROptions()
opts.AddLang("fra")
opts.AddLang("spa")
```

{% endcode %}
{% endtab %}

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

```php
// Add French, Spanish and default English to target languages
$opts = new OCROptions();
$opts->AddLang("fra");
$opts->AddLang("spa");
```

{% endcode %}
{% endtab %}

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

```ruby
# Add French, Spanish and default English to target languages
opts = OCROptions.new
opts.AddLang("fra")
opts.AddLang("spa")
```

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

## Output quality options

When processing documents with known layouts, we can enhance output quality by either specifying regions that we want OCR to ignore via `OCROptions::AddIgnoreZonesForPage`, or listing exclusive regions to process via `OCROptions::AddTextZonesForPage`. Both zone options act as stencils: With the ignore zones, we white out the areas inside the supplied rectangular regions before processing, and, for the text zones, we white out areas outside of the supplied regions. The options store an array of [RectCollection](https://sdk.apryse.com/api/PDFTronSDK/cpp/classpdftron_1_1_p_d_f_1_1_rect_collection.html), where the index into the array corresponds to the relevant page number. `OCROptions::AddIgnoreZonesForPage` can also be used to skip pages via setting ignore zone to equal page's media box.

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

```cpp
// Optionally specify page zones for OCR extraction in a multipage document
RectCollection page_zones;

page_zones.AddRect(900, 2384, 1236, 2480);
page_zones.AddRect(948, 1288, 1672, 1476);

// OCR will only process the two specified zones on the first page
opts.AddTextZonesForPage(page_zones, 1);

// Reset zone container
page_zones.Clear();

page_zones.AddRect(428, 1484, 1784, 2344);

// OCR will only process one specified zone on the second page
opts.AddTextZonesForPage(page_zones, 2);
```

{% endcode %}
{% endtab %}

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

```csharp
// Optionally specify page zones for OCR extraction in a multipage document
RectCollection page_zones = new RectCollection();

page_zones.AddRect(900, 2384, 1236, 2480);
page_zones.AddRect(948, 1288, 1672, 1476);

// OCR will only process the two specified zones on the first page
opts.AddTextZonesForPage(page_zones, 1);

// Reset zone container
page_zones.Clear();

page_zones.AddRect(428, 1484, 1784, 2344);

// OCR will only process one specified zone on the second page
opts.AddTextZonesForPage(page_zones, 2);
```

{% endcode %}
{% endtab %}

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

```go
// Optionally specify page zones for OCR extraction in a multipage document
textZones := NewRectCollection()
// select horizontal BUFFER ZONE sign
textZones.AddRect(NewRect(900.0, 2384.0, 1236.0, 2480.0))
textZones.AddRect(NewRect(948.0, 1288.0, 1672.0, 1476.0))
opts.AddTextZonesForPage(textZones, 1)
// Reset zone container
textZones.Clear();
textZones.AddRect(NewRect(428.0, 1484.0, 1784.0, 2344.0))
// OCR will only process one specified zone on the second page
opts.AddTextZonesForPage(textZones, 2)
```

{% endcode %}
{% endtab %}

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

```vb
' Optionally specify page zones for OCR extraction in a multipage document
Dim page_zones As RectCollection = New RectCollection()

page_zones.AddRect(900, 2384, 1236, 2480)
page_zones.AddRect(948, 1288, 1672, 1476)

' OCR will only process the two specified zones on the first page
opts.AddTextZonesForPage(page_zones, 1)

' Reset zone container
page_zones.Clear()

page_zones.AddRect(428, 1484, 1784, 2344)

' OCR will only process one specified zone on the second page
opts.AddTextZonesForPage(page_zones, 2)
```

{% endcode %}
{% endtab %}

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

```java
// Optionally specify page zones for OCR extraction in a multipage document
RectCollection page_zones = new RectCollection();

page_zones.addRect(900, 2384, 1236, 2480);
page_zones.addRect(948, 1288, 1672, 1476);

// OCR will only process the two specified zones on the first page
opts.addTextZonesForPage(page_zones, 1);

// Reset zone container
page_zones.clear();

page_zones.addRect(428, 1484, 1784, 2344);

// OCR will only process one specified zone on the second page
opts.addTextZonesForPage(page_zones, 2);
```

{% endcode %}
{% endtab %}

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

```js
async function main() {
   // Optionally specify page zones for OCR extraction in a multipage document
   let page_zones = [];

   page_zones.push(new PDFNet.Rect(900, 2384, 1236, 2480));
   page_zones.push(new PDFNet.Rect(948, 1288, 1672, 1476));

   // OCR will only process the two specified zones on the first page
   opts.addTextZonesForPage(page_zones, 1);

   // Reset zone container
   page_zones = [];

   page_zones.push(new PDFNet.Rect(428, 1484, 1784, 2344));

   // OCR will only process one specified zone on the second page
   opts.addTextZonesForPage(page_zones, 2);
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

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

```objc
PTPDFRectCollection * page_zones = [[PTPDFRectCollection alloc] init];

[page_zones AddRect: [[PTPDFRect alloc] initWithX1:900 y1: 2384 x2: 1236 y2: 2480 ]];
[page_zones AddRect: [[PTPDFRect alloc] initWithX1:948 y1: 1288 x2: 1672 y2: 1476 ]];

// OCR will only process the two specified zones on the first page
[opts AddTextZonesForPage: page_zones page_num:1];

// Reset zone container
[page_zones Clear];

[page_zones AddRect: [[PTPDFRect alloc] initWithX1:428 y1: 1484 x2: 1784 y2: 2344 ]];

// OCR will only process one specified zone on the second page
[opts AddTextZonesForPage: page_zones page_num:2];
```

{% endcode %}
{% endtab %}

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

```python
# Optionally specify page zones for OCR extraction in a multipage document
page_zones = RectCollection()

page_zones.AddRect(Rect(900, 2384, 1236, 2480))
page_zones.AddRect(Rect(948, 1288, 1672, 1476))

# OCR will only process the two specified zones on the first page
opts.AddTextZonesForPage(page_zones, 1)

# Reset zone container
page_zones.Clear()

page_zones.AddRect(Rect(428, 1484, 1784, 2344))

# OCR will only process one specified zone on the second page
opts.AddTextZonesForPage(page_zones, 2)
```

{% endcode %}
{% endtab %}

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

```php
// Optionally specify page zones for OCR extraction in a multipage document
$page_zones = new RectCollection();

$page_zones->AddRect(new Rect(900.0, 2384.0, 1236.0, 2480.0));
$page_zones->AddRect(new Rect(948.0, 1288.0, 1672.0, 1476.0));

// OCR will only process the two specified zones on the first page
$opts->AddTextZonesForPage($page_zones, 1);

// Reset zone container
$page_zones->Clear();

$page_zones->AddRect(new Rect(428.0, 1484.0, 1784.0, 2344.0));

// OCR will only process one specified zone on the second page
$opts->AddTextZonesForPage($page_zones, 2);
```

{% endcode %}
{% endtab %}

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

```ruby
# Optionally specify page zones for OCR extraction in a multipage document
page_zones = RectCollection.new

page_zones.AddRect(Rect.new(900, 2384, 1236, 2480))
page_zones.AddRect(Rect.new(948, 1288, 1672, 1476))

# OCR will only process the two specified zones on the first page
opts.AddTextZonesForPage(page_zones, 1)

# Reset zone container
page_zones.Clear

page_zones.AddRect(Rect.new(428, 1484, 1784, 2344))

# OCR will only process one specified zone on the second page
opts.AddTextZonesForPage(page_zones, 2)
```

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

## Setting Input Resolution

We enable users to manually set input image resolution (tweaking which can often lead to better results in practice).

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

```cpp
// Manually override DPI
opts.AddDPI(300);
```

{% endcode %}
{% endtab %}

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

```csharp
// Manually override DPI
opts.AddDPI(300);
```

{% endcode %}
{% endtab %}

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

```go
// Manually override DPI
opts.AddDPI(300);
```

{% endcode %}
{% endtab %}

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

```vb
' Manually override DPI
opts.AddDPI(300)
```

{% endcode %}
{% endtab %}

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

```java
// Manually override DPI
opts.addDPI(300);
```

{% endcode %}
{% endtab %}

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

```js
// Manually override DPI
opts.addDPI(300);
```

{% endcode %}
{% endtab %}

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

```objc
// Manually override DPI
[opts AddDPI: 300];
```

{% endcode %}
{% endtab %}

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

```python
# Manually override DPI
opts.AddDPI(300)
```

{% endcode %}
{% endtab %}

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

```php
// Manually override DPI
$opts->AddDPI(300);
```

{% endcode %}
{% endtab %}

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

```ruby
# Manually override DPI
opts.AddDPI(300)
```

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

## Setting the Threading Mode

{% hint style="info" %}
This is only available with the [default OCR](/core/learn-more/modules.md).
{% endhint %}

The default OCR Module contains a manifest file (`Lib/OCRModuleApryse.manifest`) that lists the engine's capabilities in JSON format. This is the place where threading mode may be configured.

Open the manifest file in a text editor, such as Notepad, and find the line `"threading_mode": ""`. Edit the empty value based on your preference:

* Minimum threads: `"threading_mode": "limited"`. Use as few threads as possible. This is ideal in a server environment, where each web requests serves a different user, so each OCR process should limit its threads usage.
* Balanced threads: `"threading_mode": "optimized"`. Use more threads to ensure the OCR process finishes as fast as possible. This is ideal in a desktop or single-user batch environment, where processing time is critical, and the OCR is allowed to use the optimal number of threads.
* System default: `"threading_mode": ""`. The engine chooses the ideal value based on the environment. This setting is used out of the box.


---

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