Integrating OCR in the browser with tesseract.js
Optical Character Recognition (OCR) has traditionally been a server-side task, requiring users to upload documents to a server for processing. However, with advancements in web technologies, it's now possible to perform text recognition directly in the browser. This shift towards browser-based OCR offers immediate feedback, enhanced privacy, and reduced server load. In this article, we'll explore how to integrate OCR into your web applications using the open-source Tesseract.js library, enabling instant text recognition without leaving the browser.
Why browser-based OCR?
Performing OCR in the browser offers several benefits:
- Immediate Feedback: Users receive instant results without waiting for server processing.
- Enhanced Privacy: Sensitive documents never leave the user's device, addressing privacy concerns.
- Reduced Server Load: Offloading processing to the client reduces server costs and resource usage.
- Offline Capabilities: OCR can run offline after the application, worker script, WASM core, and required language data have been downloaded and cached for offline use. The CDN example below needs a network connection on its first run.
Introducing tesseract.js: a powerful open-source OCR library
Tesseract.js is an open-source JavaScript library that brings the robust capabilities of Google's Tesseract OCR engine to web applications. Version 6.0.0 introduces significant improvements in memory management, runtime performance, and overall stability. The library now focuses on core text recognition functionality, with all output formats except 'text' disabled by default for optimal performance.
What’s new in tesseract.js v6.0.0
Tesseract.js v6.0.0 comes with several key improvements:
- Fixed memory leaks for more stable long-running sessions.
- Reduced runtime and memory usage for faster text recognition.
- Output formats other than 'text' are disabled by default to streamline performance.
- Simplified API initialization for easier integration.
Browser compatibility and requirements
Use a current Chrome, Firefox, Safari, or Edge browser with WebAssembly (WASM) and Web Worker support. WASM support alone does not guarantee compatibility with all Tesseract.js dependencies.
Ensure your server correctly serves WebAssembly files with the MIME type 'application/wasm'.
Getting started with tesseract.js
Installation
You can add Tesseract.js to your project using npm:
npm install tesseract.js@6
Or include it via CDN:
<script src="https://unpkg.com/tesseract.js@v6.0.0/dist/tesseract.min.js"></script>
Tesseract.js automatically loads the necessary WASM files. Make sure your server supports the correct MIME types for WASM.
Basic example: recognizing text from an image
Below is a simple example demonstrating how to perform OCR on an image. Include the CDN script above before this block. Tesseract.js accepts images; render PDF pages to images with a separate PDF renderer before passing them to OCR.
<input type="file" id="imageInput" accept="image/*" />
<div id="result"></div>
<script>
async function performOCR(file) {
const worker = await Tesseract.createWorker('eng', 1, {
logger: (msg) => console.log('Worker progress:', msg),
errorHandler: () => console.error('OCR worker failed.'),
})
try {
const {
data: { text },
} = await worker.recognize(file)
return text
} finally {
await worker.terminate()
}
}
document.getElementById('imageInput').addEventListener('change', async (e) => {
const file = e.target.files[0]
const resultElement = document.getElementById('result')
if (!file) return
if (!file.type.startsWith('image/')) {
resultElement.textContent = 'Please select an image file.'
return
}
resultElement.textContent = 'Processing…'
try {
const text = await performOCR(file)
resultElement.textContent = text
} catch {
resultElement.textContent = 'Unable to recognize this image. Please try another image.'
}
})
</script>
Handling multiple languages
The worker’s errorHandler handles its error event; a failed recognition still rejects the
recognize() promise, and finally terminates the initialized worker.
Tesseract.js supports various languages. Here’s how you can perform OCR on images containing text in multiple languages:
async function performMultilingualOCR(file, languages = ['eng', 'deu']) {
const worker = await Tesseract.createWorker(languages, 1, {
logger: (msg) => console.log('Worker progress:', msg),
errorHandler: () => console.error('OCR worker failed.'),
})
try {
const {
data: { text },
} = await worker.recognize(file)
return text
} finally {
await worker.terminate()
}
}
Performance optimization
Improving OCR performance and accuracy can be achieved with a few additional techniques.
Image preprocessing
Try filters or resizing for your input images, and compare recognition accuracy. Downscaling can erase small text, so the width below is a memory tradeoff, not a universal OCR setting:
async function preprocessImage(file) {
const url = URL.createObjectURL(file)
try {
const img = new Image()
await new Promise((resolve, reject) => {
img.onload = resolve
img.onerror = () => reject(new Error('Unable to decode image.'))
img.src = url
})
const canvas = document.createElement('canvas')
const maxWidth = 1000
const scale = img.width > maxWidth ? maxWidth / img.width : 1
canvas.width = Math.max(1, Math.round(img.width * scale))
canvas.height = Math.max(1, Math.round(img.height * scale))
const ctx = canvas.getContext('2d')
if (!ctx) throw new Error('Canvas processing is unavailable.')
ctx.filter = 'grayscale(100%) contrast(150%)'
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
return await new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) resolve(blob)
else reject(new Error('Unable to encode processed image.'))
}, 'image/png')
})
} finally {
URL.revokeObjectURL(url)
}
}
async function optimizedOCR(file) {
const processedImage = await preprocessImage(file)
return performOCR(processedImage)
}
Memory management
Efficiently managing the worker's lifecycle is crucial, especially when processing multiple images:
async function batchProcessImages(files) {
const worker = await Tesseract.createWorker('eng', 1, {
logger: (msg) => console.log('Worker progress:', msg),
errorHandler: () => console.error('OCR worker failed.'),
})
const results = []
try {
for (const file of files) {
const {
data: { text },
} = await worker.recognize(file)
results.push(text)
}
} finally {
await worker.terminate()
}
return results
}
Error handling and validation
Robust error handling is essential for a smooth user experience. The example below adds file type and size validation along with proper error reporting:
async function validateAndPerformOCR(file) {
const MAX_SIZE = 5 * 1024 * 1024 // 5MB
const SUPPORTED_TYPES = ['image/jpeg', 'image/png', 'image/webp']
if (!SUPPORTED_TYPES.includes(file.type)) {
throw new Error('Unsupported file type. Please use JPEG, PNG, or WebP images.')
}
if (file.size > MAX_SIZE) {
throw new Error('File size exceeds 5MB limit.')
}
return performOCR(file)
}
Security considerations and best practices
When implementing browser-based OCR, consider the following guidelines:
- Inform users that processing occurs locally to ensure data privacy.
- Validate file types and sizes to prevent unexpected behavior.
- Monitor memory usage and clean up worker instances appropriately.
- Consider progressive loading for large images to avoid blocking the UI.
- Provide clear, real-time feedback during processing.
- Handle errors gracefully with user-friendly messages.
See the Tesseract.js worker API for initialization options, including paths to locally hosted worker, core, and language assets.
Conclusion
Tesseract.js v6.0.0 provides a powerful solution for implementing OCR directly in web browsers with improved performance, robust memory management, and a simplified API. By following the best practices outlined in this guide, you can build efficient, secure, and user-friendly OCR applications that respect user privacy and deliver rapid results.
If you need a more advanced OCR solution with server-side processing and support for various document formats, consider checking out Transloadit's Document OCR service.
