Migration de Tesseract.NET SDK vers IronOCR
Ce guide accompagne les développeurs .NET à travers une migration concrète de Kit de développement logiciel Tesseract .NET (Tesseract.Net.SDK, espace de noms Patagames.Ocr) vers IronOCR. Elle s'adresse spécifiquement aux équipes qui transposent les modèles d'initialisation de l'ère .NET Framework, les idiomes de destruction hérités et les pipelines exclusivement synchrones dans un environnement qui fonctionne désormais sous .NET 8, avec des conteneurs Linux et des frameworks web asynchrones. Si votre service OCR compile contre net472 et échoue au moment où quelqu'un ajoute <TargetFramework>net8.0</TargetFramework> à .csproj, ce guide est fait pour vous.
Pourquoi migrer depuis le SDK Tesseract.NET
Le SDK Patagames a apporté une réelle valeur ajoutée lorsque .NET Framework 4.5 constituait la base de déploiement et que Windows Server était la seule cible. Ce contexte a évolué. La plupart des organisations containerisent désormais leurs services, exécutent leur intégration continue (CI) sur des runners Linux et standardisent leurs environnements sur .NET 6, 8 ou 9. Le SDK Tesseract.NET ne peut pas suivre cette tendance.
Plafond dur à .NET Framework 4.5. Le package cible net20 à travers net45. Il ne produit pas d'assembly netstandard ou net6.0. Un fichier de projet qui inclut Tesseract.Net.SDK ne peut pas définir <TargetFramework>net8.0</TargetFramework>. La mise à niveau .NET que le reste du code effectue en un sprint se bloque indéfiniment au niveau de la couche OCR.
Pas de chemin d'accès au conteneur. Le SDK fournit des appels P/Invoke réservés à Windows vers des binaires natifs Windows. Sur n'importe quelle image de base Linux — mcr.microsoft.com/dotnet/aspnet:8.0, ubuntu:22.04, alpine:3.19 — l'application lance DllNotFoundException avant de traiter un seul document. Les conteneurs Windows constituent une solution de contournement, mais ils impliquent des images plus volumineuses, des coûts de licence supplémentaires et une incompatibilité avec la plupart des services Kubernetes gérés qui utilisent par défaut des pools de nœuds Linux.
L'API synchrone uniquement bloque les pipelines ASP.NET Core. La méthode OcrApi.GetTextFromImage() est synchrone. Dans .NET Core, l'appel d'opérations synchrones bloquantes sur les threads de requête réduit le débit sous charge et risque d'épuiser le pool de threads. IronOCR fournit ReadAsync() pour une intégration non bloquante. Consultez le guide OCR asynchrone pour le modèle.
La création du moteur par requête consomme de la mémoire. Le code .NET Framework crée couramment une instance OcrApi par appel de méthode ou par requête, puis la détruit à la sortie. Il s'agit d'une gestion idiomatique du cycle de vie du .NET Framework. C'est aussi coûteux : chaque Init() charge entre 40 et 100 Mo de données linguistiques. Dix requêtes simultanées chargent dix fois le même modèle linguistique. Le IronTesseract d'IronOCR est thread-safe — une instance vit toute la durée de vie de l'application et sert tous les appelants simultanés à partir d'un seul chargement de modèle linguistique.
Les anciens modèles de gestion des déchets accumulent les risques. L'utilisation correcte du SDK nécessite un using (var api = OcrApi.Create()) { ... } block — the C# 1.0 using statement that predates using var declarations. Les bases de code écrites avant C# 8.0 incluent souvent des modèles de disposition try/finally ou, dans les cas de bug, aucune disposition du tout. Ces modèles se compilent et s'exécutent sur .NET Framework, mais comportent une dette technique qui empêche toute refactorisation moderne.
Pas d'async, pas d'injection de dépendances, pas de démarrage moderne. Le SDK n'a pas de concept d'intégration de l'injection de dépendances, de durée de vie des services hébergés, ni de configuration IOptions<t>. Son intégration dans une application ASP.NET Core nécessite un enregistrement manuel du service et évite soigneusement l'instanciation à chaque requête. IronOCR s'intègre parfaitement en tant que service singleton dans le conteneur DI standard.
Le problème fondamental
// Tesseract.NET SDK: .NET Framework 4.5 ceiling — will not compile on net8.0
// Every project referencing this package is locked below the upgrade line
using Patagames.Ocr; // Patagames.Ocr targets net45; no netstandard or net8 assembly
public class OcrService
{
public string ProcessDocument(string imagePath)
{
// Synchronous-only — blocks ASP.NET Core request threads
// Non DI support — must be instantiated manually each time
using (var api = OcrApi.Create()) // C# 1.0 using statement, 40-100MB load per call
{
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
// Project cannot target net6.0, net8.0, or any Linux container base image
}
}
// IronOCR: same logic, any runtime from net462 to net9.0, any platform
using IronOcr; // Single NuGet, supports .NET Framework 4.6.2+, .NET 5/6/7/8/9
// Register once as singleton — load language model once, share across all requests
// Call ReadAsync() in ASP.NET Core for non-blocking operation
var ocr = new IronTesseract();
var result = await ocr.ReadAsync("document.jpg"); // Async-first, no thread blocking
Console.WriteLine(result.Text);
IronOCR vs Kit de développement logiciel Tesseract .NET : comparaison des fonctionnalités
Le tableau ci-dessous présente les fonctionnalités directement pertinentes pour une migration vers la modernisation .NET.
| Fonction | Kit de développement logiciel Tesseract .NET | IronOCR |
|---|---|---|
| .NET Framework 2.0-4.5 | Oui | Non |
| .NET Framework 4.6.2-4.8 | Non | Oui |
| .NET Core 2.x / 3.x | Non | Oui |
| .NET 5 | Non | Oui |
| .NET 6 | Non | Oui |
| .NET 7 | Non | Oui |
| .NET 8 | Non | Oui |
| .NET 9 | Non | Oui |
| Déploiement de Windows | Oui | Oui |
| Déploiement Linux | Non | Oui |
| Déploiement macOS | Non | Oui |
| Conteneurs Linux Docker | Non | Oui |
| Azure App Service (Linux) | Non | Oui |
| AWS Lambda | Non | Oui |
API asynchrone (ReadAsync) | Non | Oui |
| instance unique sécurisée pour les threads | Non | Oui |
| Intégration de l'injection de dépendances (DI) dans ASP.NET Core | Manuel | Service singleton |
| Entrée PDF native | Non | Oui |
| Prétraitement intégré | Non | Oui |
| Sortie PDF consultable | Non | Oui |
| Données structurées (mots, lignes, paragraphes) | Non | Oui |
| Support commercial / SLA | Non (développeur individuel) | Oui |
| Prix de la licence perpétuelle | ~20–50 $ (développeur unique) | De $999 |
Guide de démarrage rapide : migration du SDK Tesseract.NET vers IronOCR
Étape 1 : Remplacer le package NuGet
Supprimer Kit de développement logiciel Tesseract .NET :
dotnet remove package Tesseract.Net.SDK
Si PdfiumViewer ou une bibliothèque de rendu PDF similaire a été installée uniquement pour fournir des pages PDF au SDK, supprimez-la également — IronOCR lit les PDF en natif :
dotnet remove package PdfiumViewer
Installez IronOCR depuis NuGet :
Étape 2 : Mise à jour des espaces de noms
// Before (Tesseract.NET SDK)
using Patagames.Ocr;
using Patagames.Ocr.Enums;
// After (IronOCR)
using IronOcr;
Étape 3 : initialisation de la licence
Ajoutez l'appel à la clé de licence une fois au démarrage de l'application — dans Program.cs, Startup.cs, ou le constructeur de l'hôte de l'application :
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Une licence d'essai gratuite est disponible pour une évaluation sans filigrane.
Exemples de migration de code
Modèle de démarrage .NET Framework vers Modern Host Builder
Les applications .NET Framework initialisent typiquement le moteur OCR dans un constructeur statique, un événement Application_Start, ou un gestionnaire Global.asax. Aucun de ces éléments n'existe dans les applications .NET 6+ basées sur le modèle d'hôte générique.
Approche du SDK Tesseract.NET :
// Global.asax.cs — .NET Framework MVC application
// OcrApi lifecycle managed manually; no DI container involved
public class MvcApplication : System.Web.HttpApplication
{
// Static field — one engine for the app lifetime
// But: NOT thread-safe; concurrent requests share a single OcrApi instance
private static OcrApi _globalApi;
protected void Application_Start()
{
// Initialize OCR engine on app startup
// Path to tessdata hardcoded for deployment environment
_globalApi = OcrApi.Create();
_globalApi.Init(Languages.English);
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
protected void Application_End()
{
// Must manually dispose on shutdown
_globalApi?.Dispose();
}
}
Approche IronOCR :
// Program.cs — .NET 8ASP.NET Core application
// IronTesseract est compatible avec les threads ; register as singleton, inject where needed
var builder = WebApplication.CreateBuilder(args);
IronOcr.License.LicenseKey = builder.Configuration["IronOcr:LicenseKey"];
// Register as singleton — one instance, thread-safe, shared across all requests
builder.Services.AddSingleton<IronTesseract>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Le schéma Global.asax disparaît entièrement. IronTesseract s'enregistre en tant que service singleton standard, injecté dans les contrôleurs et services via le constructeur. Le modèle linguistique se charge une seule fois lors de la première utilisation et reste en mémoire pendant toute la durée de vie de l'application. Le guide d'installation d'IronTesseract couvre les options de configuration, notamment la sélection de la langue et le mode du moteur au moment de l'enregistrement.
Modernisation des modèles de gestion des systèmes hérités
Le code .NET Framework 2.0 utilise l'instruction de bloc using (var x = ...) { }. C# 8.0 a introduit les déclarations using var qui définissent la portée de la disposition au bloc englobant. Les anciennes bases de code comportent également des gardiens de disposition try/finally écrits lorsque les instructions using n'étaient pas fiables dans tous les scénarios. Tous ces modèles indiquent un code écrit pour .NET Framework et doivent être modernisés lors de la migration.
Approche du SDK Tesseract.NET :
// .NET Framework 4.x disposal patterns — three variants encountered in production
public class LegacyOcrProcessor
{
// Pattern 1: try/finally guard (pre-C# 2.0 style, still common in legacy code)
public string ProcessWithTryFinally(string imagePath)
{
OcrApi api = null;
try
{
api = OcrApi.Create();
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
finally
{
if (api != null)
api.Dispose(); // Manuel null check required
}
}
// Pattern 2: nested using blocks — one for engine, one for image object
public string ProcessWithNestedUsing(string imagePath)
{
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var img = OcrImage.FromFile(imagePath))
{
api.SetImage(img);
return api.GetText();
} // img disposed here
} // api disposed here — nested indentation grows with each resource
}
// Pattern 3: missing disposal — memory leak, common in older service code
public string ProcessUnsafe(string imagePath)
{
var api = OcrApi.Create(); // WARNING: never disposed
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
}
Approche IronOCR :
// Modern C# 8.0+ disposal — flat, readable, no nesting
public class ModernOcrProcessor
{
private readonly IronTesseract _ocr; // Injected singleton, never disposed per-request
public ModernOcrProcessor(IronTesseract ocr) => _ocr = ocr;
// Pattern 1: using var declaration — scoped to method, no nesting
public string ProcessDocument(string imagePath)
{
using var input = new OcrInput(); // OcrInput is the disposable resource, not the engine
input.LoadImage(imagePath);
return _ocr.Read(input).Text;
} // input disposed here automatically — no nesting, no try/finally
// Pattern 2: multiple inputs in one scope — still flat
public string ProcessMultipleInputs(string imagePath, string pdfPath)
{
using var imageInput = new OcrInput();
imageInput.LoadImage(imagePath);
using var pdfInput = new OcrInput();
pdfInput.LoadPdf(pdfPath);
var imageText = _ocr.Read(imageInput).Text;
var pdfText = _ocr.Read(pdfInput).Text;
return $"{imageText}\n{pdfText}";
} // both inputs disposed here — zero nesting
}
OcrInput est la seule ressource jetable dans IronOCR. Le moteur lui-même (IronTesseract) n'est pas détruit par requête — c'est un singleton. Cela élimine le rechargement du modèle linguistique de 40–100 MB par requête imposé par OcrApi.Create() + api.Init(). Le guide d'entrée des images couvre toutes les méthodes de chargement OcrInput, y compris les flux, les tableaux d'octets et les URLs.
Intégration asynchrone pour les contrôleurs ASP.NET Core
Le SDK Tesseract.NET ne dispose pas d'API asynchrone. Chaque appel est synchrone. Dans .NET Core, l'appel d'opérations synchrones bloquantes à partir d'actions de contrôleur asynchrones présente un risque d'épuisement du pool de threads en cas de charge importante. La solution de contournement courante — envelopper les appels synchrones dans Task.Run() — déleste le travail bloquant sur un thread de la piscine de threads mais n'élimine pas la consommation de thread. Le ReadAsync() d'IronOCR fournit une intégration I/O asynchrone authentique.
Approche du SDK Tesseract.NET :
// ASP.NET Core controller — forced workaround for synchronous OCR API
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Must copy upload to temp file — OcrApi does not accept streams directly
var tempPath = Path.GetTempFileName();
await using (var stream = System.IO.File.OpenWrite(tempPath))
await file.CopyToAsync(stream);
string text;
try
{
// Task.Run wraps synchronous call — still consumes a thread-pool thread
// Does NOT free the calling thread during OCR processing
text = await Task.Run(() =>
{
using (var api = OcrApi.Create()) // 40-100MB load per request
{
api.Init(Languages.English);
return api.GetTextFromImage(tempPath); // synchronous, blocking
}
});
}
finally
{
System.IO.File.Delete(tempPath); // Manuel temp file cleanup
}
return Ok(new { text });
}
}
Approche IronOCR :
// ASP.NET Core controller — genuine async OCR, no temp files, no thread blocking
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
private readonly IronTesseract _ocr; // Singleton injected via DI
public OcrController(IronTesseract ocr) => _ocr = ocr;
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Load stream directly — no temp file needed
using var input = new OcrInput();
input.LoadImage(file.OpenReadStream()); // Stream input, no disk write
// ReadAsync — genuinely non-blocking, integrates with ASP.NET Core pipeline
var result = await _ocr.ReadAsync(input);
return Ok(new
{
text = result.Text,
confidence = result.Confidence
});
}
}
Le fichier temporaire fait l'aller-retour. L'enveloppe Task.Run disparaît. Le OcrApi.Create() par requête et la charge de 40–100 MB qui le suivait disparaissent. Le guide pratique sur l'OCR asynchrone et le guide sur l'entrée de flux documentent le pipeline asynchrone complet, y compris la prise en charge des jetons d'annulation.
Traitement TIFF multi-images
L'article comparatif de la phase 1 traitait du traitement de base des images et des PDF. Le format TIFF multi-images est un cas particulier courant dans l'archivage de documents, les systèmes de télécopie et les pipelines d'imagerie médicale. Le Kit de développement logiciel Tesseract .NET nécessite le parcours manuel des trames de TIFF en utilisant System.Drawing.Bitmap, en extrayant chaque trame dans un fichier PNG temporaire, en exécutant l'OCR sur le fichier temporaire, et en nettoyant. Le schéma force des appels GC explicites sur les gros documents pour éviter les erreurs de mémoire.
Approche du SDK Tesseract.NET :
// Multi-frame TIFF: manual frame extraction to temp files + forced GC
using System.Drawing;
using System.Drawing.Imaging;
using Patagames.Ocr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var pageTexts = new List<string>();
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var bitmap = new Bitmap(tiffPath))
{
var dimension = new FrameDimension(bitmap.FrameDimensionsList[0]);
int frameCount = bitmap.GetFrameCount(dimension);
for (int i = 0; i < frameCount; i++)
{
bitmap.SelectActiveFrame(dimension, i);
// Must write each frame to a temp file — no in-memory path
var tempPath = Path.GetTempFileName() + ".png";
bitmap.Save(tempPath, ImageFormat.Png);
try
{
pageTexts.Add(api.GetTextFromImage(tempPath));
}
finally
{
File.Delete(tempPath); // Manuel cleanup on every frame
}
// Force GC every 10 frames — workaround for memory pressure
// Slows processing; indicates memory management is manual
if (i % 10 == 0)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
}
return pageTexts;
}
Approche IronOCR :
// Multi-frame TIFF: one method call, no temp files, no manual GC
using IronOcr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // Loads all frames natively — no temp files
var result = ocr.Read(input);
// Pages map directly to TIFF frames
return result.Pages.Select(page => page.Text).ToList();
}
Trente lignes réduites à huit. Pas de fichiers temporaires, pas d'itération de trames Bitmap, pas d'appels GC.Collect(). LoadImageFrames gère des TIFFs multi-trames arbitrairement grands sans écrire de fichiers intermédiaires. Le guide d'entrée TIFF et GIF couvre le chargement sélectif des images (par plage d'index) et les rappels de progression pour les documents volumineux.
Préparation du déploiement de conteneurs Docker
Le code du SDK Tesseract.NET qui s'exécute sur la machine Windows d'un développeur échoue à l'étape de compilation ou d'exécution de Docker lorsque l'image de base est Linux. La solution ne consiste pas à modifier le fichier Dockerfile : les binaires natifs sont réservés à Windows et ne peuvent en aucun cas être chargés sous Linux. Le support Linux d'IronOCR nécessite une petite addition apt-get au Dockerfile et rien d'autre dans le code de l'application.
Approche du SDK Tesseract.NET :
# Dockerfile attempt — fails at runtime on Linux base image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# This base image is Linux (Debian) by default
# Tesseract.Net.SDK's Windows native DLLs cannot load here
# Application throws DllNotFoundException on first OCR call
WORKDIR /app
COPY --from=build /app/publish .
# Even copying the Windows tessdata folder has no effect —
# the P/Invoke DLL cannot be loaded regardless of file placement
COPY tessdata/ ./tessdata/
ENTRYPOINT ["dotnet", "MyApp.dll"]
# Runtime error: DllNotFoundException: Unable to load DLL 'libtesseract'
# Non fix available within Tesseract.Net.SDK — requires replacing the library
Approche IronOCR :
# Dockerfile for IronOCR on Linux — add one apt-get line, nothing else changes
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Required system dependency for IronOCR on Debian/Ubuntu base images
RUN apt-get update && apt-get install -y libgdiplus \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/publish .
# Non tessdata folder — language data is bundled with the IronOcr NuGet packages
# Non platform check code — IronOCR runs identically on Windows and Linux
ENTRYPOINT ["dotnet", "MyApp.dll"]
Une ligne apt-get. Aucun dossier tessdata. L'application ne contient aucun code dépendant de la plateforme. Le même binaire d'application qui s'exécute sur la machine Windows d'un développeur s'exécute dans ce conteneur Linux sans modification. Le guide de déploiement Docker couvre les images basées sur Alpine (qui utilisent apk au lieu de apt-get), l'optimisation de la construction multi-étapes, et la configuration des variables d'environnement pour la clé de licence. Le guide de déploiement Linux couvre les scénarios Linux bare-metal et WSL2.
Référence de mappage de l'API Kit de développement logiciel Tesseract .NET vers IronOCR
| Kit de développement logiciel Tesseract .NET | Équivalent d'IronOCR | Notes |
|---|---|---|
Install-Package Tesseract.Net.SDK | dotnet add package IronOcr | IronOCR cible .NET Framework 4.6.2+ et .NET 5–9 |
using Patagames.Ocr; | using IronOcr; | espace de noms unique |
using Patagames.Ocr.Enums; | (not needed) | Les énumérations se trouvent dans l'espace de noms IronOcr |
OcrApi.Create() | new IronTesseract() | IronTesseract est compatible avec les threads ; utiliser en tant que singleton |
api.Init(Languages.English) | ocr.Language = OcrLanguage.English | Affectation de propriété, pas appel de méthode |
api.Init(Languages.English \N-)| Langues.Allemand) | ocr.Language = OcrLanguage.English + OcrLanguage.German | Opérateur +, non ET bit à bit |
api.GetTextFromImage(path) | ocr.Read("path.jpg").Text | Directement ou via OcrInput |
api.GetTextFromImage(path) (async) | await ocr.ReadAsync(input) | Async authentique — pas besoin d'enveloppe Task.Run |
OcrImage.FromFile(path) | input.LoadImage(path) | OcrInput remplace OcrImage |
OcrImage.FromBitmap(bitmap) | input.LoadImage(bitmap) | |
new MemoryStream(bytes) → OcrImage.FromBitmap | input.LoadImage(bytes) | Prise en charge directe des tableaux d'octets |
api.SetImage(img) ; api.GetText() | ocr.Read(input).Text | OcrInput passé à Read |
api.GetMeanConfidence() | result.Confidence | Renvoie un pourcentage ; also available per-word |
api.SetRectangle(x, y, w, h) | input.LoadImage(path, new CropRectangle(x, y, w, h)) | OCR basé sur la région via CropRectangle |
api.SetVariable("tessedit_char_whitelist", x) | ocr.Configuration.WhiteListCharacters = x | |
api.SetVariable("tessedit_char_blacklist", x) | ocr.Configuration.BlackListCharacters = x | |
| Itération de trame bitmap + fichier temporaire | input.LoadImageFrames(tiffPath) | Prise en charge native des fichiers TIFF multi-trames |
| (synchronous only) | result.SaveAsSearchablePdf("out.pdf") | Pas d'équivalent dans le SDK Tesseract.NET |
| (no structured output) | result.Pages, result.Words, result.Lines | Coordonnées et niveau de confiance au niveau du mot |
Contournements GC.Collect() | (not needed) | IronOCR gère la mémoire en interne |
Vérification de la plateforme : IsOSPlatform(Windows) | (remove entirely) | IronOCR est multiplateforme |
| Gestion des dossiers Tessdata | (remove entirely) | Langages fournis avec les paquets NuGet |
Problèmes de migration courants et solutions
Problème n° 1 : conflit entre les frameworks cibles du projet
Tesseract.NET SDK : Après avoir supprimé Tesseract.Net.SDK et ajouté IronOcr, le projet cible encore net45 ou net472 selon l'ancienne exigence. IronOCR supporte net462 et plus tard, donc les projets net45 doivent avoir le framework cible mis à jour avant que le package ne soit restauré proprement.
Solution : Mettez à jour <TargetFramework> dans le fichier .csproj avant d'ajouter IronOCR. Si le projet doit prendre en charge à la fois les anciens et les nouveaux environnements d'exécution pendant une migration progressive, utilisez le multi-ciblage :
<!-- Single modern target (preferred) -->
<TargetFramework>net8.0</TargetFramework>
<!-- Multi-targeting during phased migration — supports both simultaneously -->
<TargetFrameworks>net462;net8.0</TargetFrameworks>
IronOCR détermine automatiquement l'assembly approprié pour chaque cible. La même commande dotnet add package IronOcr fonctionne pour les deux. La page de la bibliothèque OCR .NET répertorie tous les frameworks cibles pris en charge.
Problème n° 2 : le champ statique OcrApi a été remplacé par un singleton DI
Tesseract.NET SDK : Le code hérité enregistre une seule instance OcrApi comme champ statique (dans Global.asax, un localisateur de service statique, ou une classe wrapper singleton). Ce modèle était nécessaire car OcrApi n'est pas thread-safe — partager une instance à travers les threads provoque des conditions de concurrence, donc le champ statique était protégé par un verrou ou était en réalité recréé par requête malgré le nom du champ.
Solution : Enregistrez IronTesseract comme véritable singleton thread-safe via le conteneur DI. Supprimer le verrou, supprimer le champ statique, supprimer toute recréation à chaque requête :
// Remove: private static OcrApi _instance; / private static readonly object _lock = new();
// Replace with DI registration in Program.cs
builder.Services.AddSingleton<IronTesseract>();
// In consuming classes — constructor injection
public class DocumentProcessor
{
private readonly IronTesseract _ocr;
public DocumentProcessor(IronTesseract ocr) => _ocr = ocr;
public async Task<string> ProcessAsync(string path)
{
using var input = new OcrInput();
input.LoadImage(path);
var result = await _ocr.ReadAsync(input);
return result.Text;
}
}
Problème n° 3 : dossier Tessdata manquant après le déploiement
Tesseract.NET SDK : après être passées à IronOCR, les équipes laissent parfois les étapes de déploiement de tessdata dans les pipelines CI/CD. Le dossier tessdata/ référencé dans les scripts de construction et les manifestes de déploiement n'existe plus — c'était une partie de l'ancienne gestion du modèle linguistique du SDK. Les scripts échouent lorsqu'ils tentent de copier ou de vérifier un dossier qui n'existe plus.
Solution : Supprimez toutes les références à tessdata des scripts de déploiement, des cibles de copie .csproj, des commandes COPY de Docker et des étapes de pipeline CI/CD. Les données linguistiques d'IronOCR sont fournies avec les paquets NuGet. Exécutez dotnet restore et les données linguistiques sont disponibles. Rien d'autre n'est nécessaire :
# Remove from CI/CD pipeline
# BEFORE (delete these lines):
# - cp -r tessdata/ $DEPLOY_PATH/tessdata/
# - test -f $DEPLOY_PATH/tessdata/eng.traineddata
# AFTER: nothing — language data is in the NuGet package restore output
dotnet restore # Downloads IronOcr and any IronOcr.Languages.* packages
dotnet publish # Includes language data automatically
Le guide multilingue explique comment installer des packs de langues spécifiques sous forme de paquets NuGet pour les déploiements hors ligne ou en environnement isolé.
Problème 4 : BadImageFormatException sur un Mismatch 32/64 bits
Tesseract.NET SDK : Le SDK est fourni avec des binaires natifs Windows x86 et x64 distincts. Les projets ciblant AnyCPU résolvent parfois le mauvais binaire selon l'architecture du processus. L'erreur se manifeste sous forme de BadImageFormatException ou DllNotFoundException à l'exécution sur des machines où l'architecture du processus ne correspond pas au DLL natif dans le dossier de sortie.
Solution : IronOCR regroupe le binaire natif correct pour chaque plateforme dans le package NuGet et résout le bon binaire automatiquement via le dossier runtimes/ dans la disposition du package. Pas de paramètre cible Platform, pas de commandes de copie conditionnelles à l'architecture, pas de sous-dossiers x64 à gérer :
<!-- Remove architecture-specific build configurations from .csproj -->
<!-- BEFORE: Conditional native DLL copy based on Platform target -->
<!--
<ItemGroup Condition="'$(Platform)' == 'x64'">
<Content Include="$(SolutionDir)libs\x64\*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
-->
<!-- AFTER: Nothing. IronOCR resolves the correct binary automatically. -->
Problème n° 5 : migration des chaînes de configuration
Tesseract.NET SDK : Les variables du moteur Tesseract sont définies via api.SetVariable(string name, string value) en utilisant des clés de chaîne brute de l'API Tesseract (par exemple, "tessedit_char_whitelist", "tessedit_pageseg_mode"). Il s'agit de chaînes non typées sans complétion IDE. Les fautes de frappe provoquent des échecs silencieux : la variable est ignorée, ce n'est pas une exception.
Solution : IronOCR expose la configuration du moteur sous forme de propriétés typées sur ocr.Configuration. Les fautes de frappe se transforment en erreurs de compilation :
// Before: untyped string variables, silent failures on typos
api.SetVariable("tessedit_char_whitelist", "0123456789");
api.SetVariable("tessedit_pageseg_mode", "7");
// After: typed properties, compile-time validation, IDE completion
ocr.Configuration.WhiteListCharacters = "0123456789";
ocr.Configuration.PageSegmentationMode = TesseractPageSegmentationMode.SingleLine;
La documentation de référence de l'API IronTesseract répertorie toutes les propriétés de configuration avec leurs types et les valeurs acceptées.
Numéro 6 : Rapports d'avancement pour les tâches par lots longues
Tesseract.NET SDK : Le code de traitement par lots qui rapporte la progression utilisant IProgress<t> fonctionne au niveau du travail (incrémenter un compteur après chaque fichier) mais ne peut pas rapporter dans un seul document — il n'y a pas de mécanisme de rappel à l'intérieur de GetTextFromImage(). Pour un document de 500 pages, la barre de progression reste bloquée jusqu'à ce que l'ensemble du document soit traité.
Solution : IronOCR fournit un suivi de progression intégré via l'événement OcrProgress sur OcrInput. Affichage de la progression par page, permettant des barres de progression précises pour les longs documents de plusieurs pages :
// IronOCR: page-level progress tracking for multi-page documents
using IronOcr;
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("large-archive.pdf");
// Subscribe to page-level progress events
input.OcrProgress += (sender, e) =>
{
Console.WriteLine($"Processing page {e.CurrentPage} of {e.TotalPages} " +
$"({e.ProgressPercent:F0}%)");
};
var result = ocr.Read(input);
Console.WriteLine($"Complete: {result.Pages.Count} pages extracted");
Le guide de suivi de la progression couvre l'intégration avec ASP.NET Core SignalR pour la transmission en temps réel de la progression aux clients navigateur.
Liste de contrôle pour la migration du SDK Tesseract.NET
Pré-migration
Vérifiez le code source pour repérer toutes les utilisations du SDK Tesseract.NET avant de modifier quoi que ce soit :
# Find all files referencing Patagames namespace
grep -rl "Patagames" --include="*.cs" .
# Find all OcrApi instantiation points
grep -rn "OcrApi.Create" --include="*.cs" .
# Find tessdata references in project and build files
grep -rn "tessdata" --include="*.cs" --include="*.csproj" --include="*.yaml" --include="*.yml" .
# Find platform guard checks that can be removed after migration
grep -rn "IsOSPlatform.*Windows" --include="*.cs" .
# Find Task.Run wrappers around synchronous OCR calls
grep -rn "Task.Run" --include="*.cs" . | grep -i "ocr\|image\|text"
# Count distinct OcrApi.Create() call sites to estimate migration scope
grep -c "OcrApi.Create" $(find . -name "*.cs")
Documentez le nombre de sites d'appel OcrApi.Create() — chacun est un candidat pour un remplacement par injection de singleton. Notez tous les schémas de disposition try/finally pour la modernisation. Identifiez toute initialisation Global.asax, Application_Start, ou de constructeur statique qui sera déplacée vers Program.cs.
Migration de code
- Mettez à jour
<TargetFramework>ànet8.0(ou le runtime moderne cible) dans tous les fichiers.csproj - Exécutez
dotnet remove package Tesseract.Net.SDKdans chaque projet - Exécutez
dotnet remove package PdfiumViewer(ou un package de rendu PDF équivalent) si présent - Exécutez
dotnet add package IronOcrdans chaque projet - Ajoutez
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";àProgram.csou au constructeur de l'hôte - Enregistrez
IronTesseractcomme singleton dans le conteneur DI :services.AddSingleton<IronTesseract>() - Remplacez tous
using Patagames.Ocr;etusing Patagames.Ocr.Enums;parusing IronOcr; - Remplacez
OcrApi.Create()+api.Init(Languages.X)parIronTesseractinjecté par constructeur - Remplacer
using (var api = OcrApi.Create()) { ... }blocks withusing var input = new OcrInput()declarations - Remplacez
api.GetTextFromImage(path)parocr.Read(input).Textouawait ocr.ReadAsync(input) - Remplacez
Task.Run(() => { /* synchronous OCR */ })par directementawait ocr.ReadAsync(input) - Remplacez
api.GetMeanConfidence()parresult.Confidence - Remplacez les boucles d'itération de trames Bitmap de TIFF par
input.LoadImageFrames(tiffPath) - Remplacez
api.SetVariable("tessedit_char_whitelist", x)parocr.Configuration.WhiteListCharacters = x - Supprimez le dossier tessdata du projet, supprimez toutes les références au script de déploiement vers tessdata
Après la migration
- Compilez le projet ciblant
net8.0et confirmez qu'aucune référencePatagamesne reste dans la sortie de construction - Exécutez l'application sur un hôte Linux ou un conteneur Docker Linux et confirmez qu'il n'y a pas
DllNotFoundException - Vérifier que le texte issu de l'OCR correspond au résultat obtenu avant la migration sur un échantillon représentatif de documents de production (10 à 20 documents)
- Tester le traitement des fichiers TIFF multipages et vérifier que le nombre de pages correspond au nombre de trames d'origine
- Exécutez des tests de charge sur les points d'extrémité ASP.NET Core en utilisant
ReadAsync()et vérifiez que les métriques de la piscine de threads ne montrent aucun blocage - Confirmez que le conteneur DI résout
IronTesseractcomme un singleton (même instance pour toutes les requêtes) - Vérifiez que le pipeline CI/CD s'exécute sans erreur maintenant que les étapes de copie de tessdata ont été supprimées
- Tester la création d'une image Docker et l'exécution d'un conteneur sur une image de base Linux
- Vérifier que les événements de progression se déclenchent correctement sur un document multipages (PDF ou TIFF)
- Vérifiez que les scores de confiance se situent dans la fourchette attendue pour les documents dont la qualité est confirmée
Principaux avantages de la migration vers IronOCR
Le blocage de mise à niveau .NET a disparu. Avant la migration, tout projet visant à faire passer le service de .NET Framework 4.x à .NET 8s'arrêtait au niveau de la couche OCR. Après la migration, le service OCR se compile et s'exécute sur .NET Framework 4.6.2, .NET 6, .NET 8et .NET 9à partir de la même référence de package. La mise à niveau est débloquée. Les équipes qui géraient un déploiement de runtime hérité distinct uniquement pour l'OCR peuvent désormais tout regrouper sur une seule cible de runtime moderne.
Le déploiement en conteneur fonctionne sans compromis. Le DllNotFoundException sur les images de base Linux est éliminé. La même application binaire qui s'exécute sur une station de travail Windows d'un développeur s'exécute à l'intérieur d'un conteneur Debian ou Alpine avec une ligne apt-get dans le Dockerfile. Les déploiements Kubernetes, les applications Azure Container et les tâches AWS ECS sur des pools de nœuds Linux fonctionnent tous sans licence de conteneur Windows, sans tailles d'image plus grandes ou chemins de code conditionnels à l'architecture. Le guide de déploiement Docker et le guide Azure documentent la configuration exacte pour chaque environnement cible.
Les pipelines orientés asynchrone éliminent la pression sur la piscine de threads. La solution de contournement Task.Run qui enveloppait l'OCR synchrone dans une méthode asynchrone est remplacée par ReadAsync(). Les threads de requête ASP.NET Core sont libérés pendant le traitement OCR plutôt que bloqués. En cas de forte concurrence, cela se traduit directement par un débit de requêtes plus élevé et une latence réduite pour l'ensemble de l'application, et pas seulement pour les points de terminaison OCR.
La consommation de mémoire baisse proportionnellement à la concurrence. Un service qui créait auparavant une instance OcrApi par requête simultanée — chacune chargeant 40–100 MB de données linguistiques — charge maintenant ces données une seule fois dans une instance singleton IronTesseract. Avec dix requêtes simultanées, la différence est de 400 à 1 000 Mo par rapport à une charge fixe unique. Cette réduction est immédiatement visible dans les métriques des ressources des conteneurs et permet de réduire les limites de mémoire des pods, d'augmenter la densité des pods et de diminuer les coûts de l'infrastructure cloud.
Les schémas modernes de C# remplacent la cérémonie de .NET Framework. Les gardes de disposition try/finally, les blocs imbriqués using, les appels entre trames TIFF GC.Collect() — tous ces éléments disparaissent. using var input = new OcrInput() est l'ensemble du schéma de gestion des ressources. Les revues de code sont plus courtes. L'intégration de nouveaux développeurs au service OCR prend moins de temps. La documentation de référence de l'API OcrResult décrit le modèle d'objet de résultat complet, y compris les données structurées, les scores de confiance et la sortie PDF consultable, qui remplacent les schémas de traitement manuel des résultats de l'ancien SDK.
Le support commercial remplace la dépendance à un seul développeur. Le SDK Tesseract.NET est géré par un développeur individuel, sans SLA ni garantie de continuité organisationnelle. IronOCR est développé par Iron Software, une entité commerciale disposant de canaux d'assistance dédiés, de processus documentés de divulgation des failles de sécurité et de conditions de licence répondant aux exigences d'approvisionnement des entreprises. La page de licences IronOCR couvre les niveaux de support et le modèle de licence perpétuelle (à partir de $999) qui remplace à la fois les frais du SDK Patagames et le coût caché du maintien d'une infrastructure Windows uniquement sur une plateforme .NET en modernisation.
