How to OCR documents on AWS Lambda
This how-to article provides a step-by-step guide for setting up an AWS Lambda function using IronOCR. By following this guide, you will learn how to configure IronOCR and efficiently read documents stored in an S3 bucket.
How to OCR documents on AWS Lambda
- Download a C# library to perform OCR on documents
- Create and choose the project template
- Modify the FunctionHandler code
- Configure and deploy the project
- Invoke the function and check the results in S3
Installation
This article will use an S3 bucket, so the AWSSDK.S3 package is required.
If you are using IronOCR ZIP, it is essential to set the temporary folder.
// Set temporary folder path and log file path for IronOCR.
var awsTmpPath = @"/tmp/";
IronOcr.Installation.InstallationPath = awsTmpPath;
IronOcr.Installation.LogFilePath = awsTmpPath;
// Set temporary folder path and log file path for IronOCR.
var awsTmpPath = @"/tmp/";
IronOcr.Installation.InstallationPath = awsTmpPath;
IronOcr.Installation.LogFilePath = awsTmpPath;
' Set temporary folder path and log file path for IronOCR.
Dim awsTmpPath = "/tmp/"
IronOcr.Installation.InstallationPath = awsTmpPath
IronOcr.Installation.LogFilePath = awsTmpPath
Start using IronOCR in your project today with a free trial.
Create an AWS Lambda Project
With Visual Studio, creating a containerized AWS Lambda is an easy process:
- Install the AWS Toolkit for Visual Studio.
- Select an 'AWS Lambda Project (.NET Core - C#)'.
- Select a '.NET 8 (Container Image)' blueprint, then select 'Finish'.
Add Package Dependencies
Using the IronOCR library in .NET 8 does not require additional dependencies to be installed for use on AWS Lambda. Modify the project's Dockerfile with the following:
FROM public.ecr.aws/lambda/dotnet:8
# Update all installed packages
RUN dnf update -y
WORKDIR /var/task
# Copy build artifacts from the host machine into the Docker image
COPY "bin/Release/lambda-publish" .
Modify the FunctionHandler Code
This example retrieves an image from an S3 bucket, processes it, and saves a searchable PDF back to the same bucket. Setting the temp folder is essential when using IronOCR ZIP, as the library requires write permissions to copy the runtime folder from the DLLs.
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;
using IronOcr;
using System;
using System.IO;
using System.Threading.Tasks;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace IronOcrZipAwsLambda
{
public class Function
{
// Initialize the S3 client with a specific region endpoint
private static readonly IAmazonS3 _s3Client = new AmazonS3Client(Amazon.RegionEndpoint.APSoutheast1);
/// <summary>
/// Function handler to process OCR on the PDF stored in S3.
/// </summary>
/// <param name="context">The ILambdaContext that provides methods for logging and describing the Lambda environment.</param>
public async Task FunctionHandler(ILambdaContext context)
{
// Set up necessary paths for IronOCR
var awsTmpPath = @"/tmp/";
IronOcr.Installation.InstallationPath = awsTmpPath;
IronOcr.Installation.LogFilePath = awsTmpPath;
// Set license key for IronOCR
IronOcr.License.LicenseKey = "IRONOCR-MYLICENSE-KEY-1EF01";
string bucketName = "deploymenttestbucket"; // Your bucket name
string pdfName = "sample";
string objectKey = $"IronPdfZip/{pdfName}.pdf";
string objectKeyForSearchablePdf = $"IronPdfZip/{pdfName}-SearchablePdf.pdf";
try
{
// Retrieve the PDF file from S3
var pdfData = await GetPdfFromS3Async(bucketName, objectKey);
// Initialize IronTesseract for OCR processing
IronTesseract ironTesseract = new IronTesseract();
OcrInput ocrInput = new OcrInput();
ocrInput.LoadPdf(pdfData);
OcrResult result = ironTesseract.Read(ocrInput);
// Log the OCR result
context.Logger.LogLine($"OCR result: {result.Text}");
// Upload the searchable PDF to S3
await UploadPdfToS3Async(bucketName, objectKeyForSearchablePdf, result.SaveAsSearchablePdfBytes());
context.Logger.LogLine($"PDF uploaded successfully to {bucketName}/{objectKeyForSearchablePdf}");
}
catch (Exception e)
{
context.Logger.LogLine($"[ERROR] FunctionHandler: {e.Message}");
}
}
/// <summary>
/// Retrieves a PDF from S3 and returns it as a byte array.
/// </summary>
private async Task<byte[]> GetPdfFromS3Async(string bucketName, string objectKey)
{
var request = new GetObjectRequest
{
BucketName = bucketName,
Key = objectKey
};
using (var response = await _s3Client.GetObjectAsync(request))
using (var memoryStream = new MemoryStream())
{
await response.ResponseStream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
}
/// <summary>
/// Uploads the generated searchable PDF back to S3.
/// </summary>
private async Task UploadPdfToS3Async(string bucketName, string objectKey, byte[] pdfBytes)
{
using (var memoryStream = new MemoryStream(pdfBytes))
{
var request = new PutObjectRequest
{
BucketName = bucketName,
Key = objectKey,
InputStream = memoryStream,
ContentType = "application/pdf"
};
await _s3Client.PutObjectAsync(request);
}
}
}
}
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;
using IronOcr;
using System;
using System.IO;
using System.Threading.Tasks;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace IronOcrZipAwsLambda
{
public class Function
{
// Initialize the S3 client with a specific region endpoint
private static readonly IAmazonS3 _s3Client = new AmazonS3Client(Amazon.RegionEndpoint.APSoutheast1);
/// <summary>
/// Function handler to process OCR on the PDF stored in S3.
/// </summary>
/// <param name="context">The ILambdaContext that provides methods for logging and describing the Lambda environment.</param>
public async Task FunctionHandler(ILambdaContext context)
{
// Set up necessary paths for IronOCR
var awsTmpPath = @"/tmp/";
IronOcr.Installation.InstallationPath = awsTmpPath;
IronOcr.Installation.LogFilePath = awsTmpPath;
// Set license key for IronOCR
IronOcr.License.LicenseKey = "IRONOCR-MYLICENSE-KEY-1EF01";
string bucketName = "deploymenttestbucket"; // Your bucket name
string pdfName = "sample";
string objectKey = $"IronPdfZip/{pdfName}.pdf";
string objectKeyForSearchablePdf = $"IronPdfZip/{pdfName}-SearchablePdf.pdf";
try
{
// Retrieve the PDF file from S3
var pdfData = await GetPdfFromS3Async(bucketName, objectKey);
// Initialize IronTesseract for OCR processing
IronTesseract ironTesseract = new IronTesseract();
OcrInput ocrInput = new OcrInput();
ocrInput.LoadPdf(pdfData);
OcrResult result = ironTesseract.Read(ocrInput);
// Log the OCR result
context.Logger.LogLine($"OCR result: {result.Text}");
// Upload the searchable PDF to S3
await UploadPdfToS3Async(bucketName, objectKeyForSearchablePdf, result.SaveAsSearchablePdfBytes());
context.Logger.LogLine($"PDF uploaded successfully to {bucketName}/{objectKeyForSearchablePdf}");
}
catch (Exception e)
{
context.Logger.LogLine($"[ERROR] FunctionHandler: {e.Message}");
}
}
/// <summary>
/// Retrieves a PDF from S3 and returns it as a byte array.
/// </summary>
private async Task<byte[]> GetPdfFromS3Async(string bucketName, string objectKey)
{
var request = new GetObjectRequest
{
BucketName = bucketName,
Key = objectKey
};
using (var response = await _s3Client.GetObjectAsync(request))
using (var memoryStream = new MemoryStream())
{
await response.ResponseStream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
}
/// <summary>
/// Uploads the generated searchable PDF back to S3.
/// </summary>
private async Task UploadPdfToS3Async(string bucketName, string objectKey, byte[] pdfBytes)
{
using (var memoryStream = new MemoryStream(pdfBytes))
{
var request = new PutObjectRequest
{
BucketName = bucketName,
Key = objectKey,
InputStream = memoryStream,
ContentType = "application/pdf"
};
await _s3Client.PutObjectAsync(request);
}
}
}
}
Imports Amazon.Lambda.Core
Imports Amazon.S3
Imports Amazon.S3.Model
Imports IronOcr
Imports System
Imports System.IO
Imports System.Threading.Tasks
' Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
<Assembly: LambdaSerializer(GetType(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))>
Namespace IronOcrZipAwsLambda
Public Class [Function]
' Initialize the S3 client with a specific region endpoint
Private Shared ReadOnly _s3Client As IAmazonS3 = New AmazonS3Client(Amazon.RegionEndpoint.APSoutheast1)
''' <summary>
''' Function handler to process OCR on the PDF stored in S3.
''' </summary>
''' <param name="context">The ILambdaContext that provides methods for logging and describing the Lambda environment.</param>
Public Async Function FunctionHandler(ByVal context As ILambdaContext) As Task
' Set up necessary paths for IronOCR
Dim awsTmpPath = "/tmp/"
IronOcr.Installation.InstallationPath = awsTmpPath
IronOcr.Installation.LogFilePath = awsTmpPath
' Set license key for IronOCR
IronOcr.License.LicenseKey = "IRONOCR-MYLICENSE-KEY-1EF01"
Dim bucketName As String = "deploymenttestbucket" ' Your bucket name
Dim pdfName As String = "sample"
Dim objectKey As String = $"IronPdfZip/{pdfName}.pdf"
Dim objectKeyForSearchablePdf As String = $"IronPdfZip/{pdfName}-SearchablePdf.pdf"
Try
' Retrieve the PDF file from S3
Dim pdfData = Await GetPdfFromS3Async(bucketName, objectKey)
' Initialize IronTesseract for OCR processing
Dim ironTesseract As New IronTesseract()
Dim ocrInput As New OcrInput()
ocrInput.LoadPdf(pdfData)
Dim result As OcrResult = ironTesseract.Read(ocrInput)
' Log the OCR result
context.Logger.LogLine($"OCR result: {result.Text}")
' Upload the searchable PDF to S3
Await UploadPdfToS3Async(bucketName, objectKeyForSearchablePdf, result.SaveAsSearchablePdfBytes())
context.Logger.LogLine($"PDF uploaded successfully to {bucketName}/{objectKeyForSearchablePdf}")
Catch e As Exception
context.Logger.LogLine($"[ERROR] FunctionHandler: {e.Message}")
End Try
End Function
''' <summary>
''' Retrieves a PDF from S3 and returns it as a byte array.
''' </summary>
Private Async Function GetPdfFromS3Async(ByVal bucketName As String, ByVal objectKey As String) As Task(Of Byte())
Dim request = New GetObjectRequest With {
.BucketName = bucketName,
.Key = objectKey
}
Using response = Await _s3Client.GetObjectAsync(request)
Using memoryStream As New MemoryStream()
Await response.ResponseStream.CopyToAsync(memoryStream)
Return memoryStream.ToArray()
End Using
End Using
End Function
''' <summary>
''' Uploads the generated searchable PDF back to S3.
''' </summary>
Private Async Function UploadPdfToS3Async(ByVal bucketName As String, ByVal objectKey As String, ByVal pdfBytes() As Byte) As Task
Using memoryStream As New MemoryStream(pdfBytes)
Dim request = New PutObjectRequest With {
.BucketName = bucketName,
.Key = objectKey,
.InputStream = memoryStream,
.ContentType = "application/pdf"
}
Await _s3Client.PutObjectAsync(request)
End Using
End Function
End Class
End Namespace
Before the try block, the file 'sample.pdf' is specified for reading from the IronPdfZip directory. The GetPdfFromS3Async
method is then used to retrieve the PDF byte, which is passed to the LoadPdf
method.
Increase Memory and Timeout
The amount of memory allocated in the Lambda function will vary based on the size of the documents being processed and the number of documents processed simultaneously. As a baseline, set the memory to 512 MB and the timeout to 300 seconds in aws-lambda-tools-defaults.json
.
{
"function-memory-size": 512,
"function-timeout": 300
}
When the memory is insufficient, the program will throw the error: 'Runtime exited with error: signal: killed.' Increasing the memory size can resolve this issue. For more details, refer to the troubleshooting article: AWS Lambda - Runtime Exited Signal: Killed.
Publish
To publish in Visual Studio, right-click on the project and select 'Publish to AWS Lambda...', then configure the necessary settings. You can read more about publishing a Lambda on the AWS website.
Try It Out!
You can activate the Lambda function either through the Lambda console or through Visual Studio.
Frequently Asked Questions
How can I perform OCR on documents in AWS using C#?
You can use IronOCR to perform OCR on documents stored in Amazon S3 buckets by integrating it with AWS Lambda. This involves creating a Lambda function in C# that retrieves documents from S3, processes them with IronOCR, and then uploads the results back to S3.
What steps are involved in setting up OCR on AWS Lambda with C#?
To set up OCR on AWS Lambda using C#, you need to download the IronOCR library, create an AWS Lambda project in Visual Studio, configure your function handler to use IronOCR for processing, and deploy your function. This setup allows you to convert images into searchable PDFs.
What is the recommended configuration for running OCR in AWS Lambda?
For optimal performance when running OCR with IronOCR in AWS Lambda, it is recommended to set a memory allocation of at least 512 MB and a timeout period of 300 seconds. These settings help manage the processing of large or multiple documents.
How do I handle 'Runtime exited with error: signal: killed' in AWS Lambda?
This error often indicates that your Lambda function has exhausted its allocated memory. Increasing the memory allocation in the Lambda function's configuration can resolve this issue, especially when processing large documents with IronOCR.
Can I test my AWS Lambda OCR function locally before deployment?
Yes, you can test your AWS Lambda OCR function locally using the AWS Toolkit for Visual Studio. This toolkit provides a local environment for simulating Lambda executions, allowing you to debug and refine your function before deployment.
What is the purpose of a Dockerfile in an AWS Lambda project?
A Dockerfile in an AWS Lambda project is used to create a container image that defines the execution environment and dependencies for your Lambda function. This ensures that your function has all the necessary components to run properly in AWS.
Do I need any additional dependencies to use IronOCR in .NET 8 on AWS Lambda?
No additional dependencies are needed beyond the IronOCR library and the necessary AWS SDK packages when using .NET 8 on AWS Lambda. This simplifies the integration process for executing OCR tasks.
What are the prerequisites for integrating C# OCR with AWS Lambda?
Before integrating C# OCR with AWS Lambda, you need to install the AWS SDK for S3, IronOCR library, and AWS Toolkit for Visual Studio. You'll also need a configured S3 bucket for storing and retrieving documents.