Passer au contenu du pied de page
VIDéOS

Migration de Dynamsoft OCR vers IronOCR

Ce guide fournit un chemin de migration complet pour les développeurs .NET passant de Reconnaissance d'étiquettes Dynamsoft à IronOCR . Il couvre le remplacement des packages NuGet , les mises à jour des espaces de noms, l'initialisation des licences et des exemples pratiques de migration de code pour des scénarios distincts des comparaisons de capacités générales, notamment l'élimination de la configuration des modèles, la suppression du JSON des paramètres d'exécution, la migration de la définition de région et la simplification de l'analyse des résultats.

Pourquoi migrer depuis Dynamsoft OCR ?

Dynamsoft Label Recognizer est un logiciel spécialisé. Cette précision est idéale pour les déploiements ciblés, mais elle engendre des difficultés dès que le périmètre d'application s'étend au-delà du cas d'utilisation initial MRZ ou VIN.

Les paramètres d'exécution JSON sont une surface de maintenance. Chaque flux de travail de reconnaissance Dynamsoft commence par AppendSettingsFromString, chargeant un document JSON qui déclare des tableaux de paramètres, des modèles de caractères et des références de régions. Ces modèles JSON sont des artefacts de déploiement distincts — ils ne sont pas compilés dans votre binaire. Ils nécessitent un contrôle de version, une gestion du pipeline de déploiement et des mises à jour manuelles lorsque Dynamsoft modifie les schémas de modèles entre les différentes versions du SDK. IronOCR ne nécessite aucun fichier de configuration : instanciez IronTesseract, appelez .Read() et le moteur sélectionne automatiquement les paramètres appropriés.

Tarification annuelle par abonnement. Licences Reconnaissance d'étiquettes Dynamsoft à partir de 599 $ par appareil et par an. Il n'existe pas d'option perpétuelle. Un cluster de traitement à cinq appareils coûte plus de 2 995 $ par an — et ce budget ne couvre que la reconnaissance MRZ et la reconnaissance d'étiquettes structurées. Ajoutez Dynamsoft Barcode Reader pour les codes-barres ou Dynamsoft Document Normalizer pour la correction des bords, et la facture annuelle se multiplie par le nombre de produits. La licence Lite de IronOCR est $999 à usage unique et couvre l'OCR général, les étiquettes structurées, les codes-barres, les PDF natifs, la sortie PDF consultable et plus de 125 langues à partir d'un seul package.

La définition des régions nécessite des modèles JSON. Définir une région de reconnaissance dans Dynamsoft signifie créer un bloc JSON ReferenceRegionArray, le référencer dans un LabelRecognizerParameterArray, et charger l'ensemble du document avant que le traitement d'image ne commence. IronOCR utilise un seul constructeur CropRectangle(x, y, width, height) passé directement à OcrInput.LoadImage. Modifier une région se fait par la simple modification d'un nombre, et non par une nouvelle analyse d'un document JSON.

L'analyse des résultats est entièrement votre responsabilité. RecognizeFile et RecognizeByFile renvoient des tableaux LineResult contenant des chaînes de texte brut. Chaque structure dont vous avez besoin (décalages de champs, conversions de dates, validation des chiffres de contrôle, gestion des séparateurs de noms) nécessite un code d'analyse personnalisé en plus de cette sortie brute. IronOCR renvoie un OcrResult avec .Pages, .Lines, .Words et .Characters comme collections typées avec des coordonnées de boîte englobante, des scores de confiance et des métadonnées de police déjà remplies.

L'absence de prise en charge native du format PDF crée une dépendance cachée. Reconnaissance d'étiquettes Dynamsoft ne prend pas en charge les fichiers PDF en entrée. Tout fichier PDF arrivant dans votre pipeline de traitement nécessite une bibliothèque externe pour convertir chaque page en bitmap, une boucle d'itération de page et une étape d'agrégation des résultats avant le premier appel à Dynamsoft. IronOCR lit les PDF nativement : new IronTesseract().Read("document.pdf") traite chaque page sans dépendance secondaire, boucle de rendu ou dossier temporaire d'images.

Les blocs d'initialisation multiproduits grandissent avec l'étendue. Une application Dynamsoft qui gère des étiquettes structurées, des codes-barres et la normalisation des documents comporte trois appels statiques InitLicense au démarrage, trois chaînes de suppression et trois dépendances de version SDK indépendantes. La mise à niveau du SDK implique une coordination entre tous les produits. IronOCR possède une seule ligne d'initialisation et une seule version de package, quelles que soient les fonctionnalités utilisées par l'application.

Le problème fondamental

Dynamsoft requiert un fichier de configuration JSON chargé lors de l'exécution avant que la reconnaissance puisse démarrer :

// Dynamsoft: JSON template required before any image processing
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();

string settings = @"{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""VIN_Label"",
        ""ReferenceRegionNameArray"": [""VinRegion""],
        ""CharacterModelName"": ""VIN""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""VinRegion"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [5, 40],
            ""SecondPoint"": [95, 40],
            ""ThirdPoint"":  [95, 60],
            ""FourthPoint"": [5, 60]
        }
    }]
}";

recognizer.AppendSettingsFromString(settings);  // fails silently if JSON is malformed
var results = recognizer.RecognizeFile(imagePath);
// Dynamsoft: JSON template required before any image processing
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();

string settings = @"{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""VIN_Label"",
        ""ReferenceRegionNameArray"": [""VinRegion""],
        ""CharacterModelName"": ""VIN""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""VinRegion"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [5, 40],
            ""SecondPoint"": [95, 40],
            ""ThirdPoint"":  [95, 60],
            ""FourthPoint"": [5, 60]
        }
    }]
}";

recognizer.AppendSettingsFromString(settings);  // fails silently if JSON is malformed
var results = recognizer.RecognizeFile(imagePath);
' Dynamsoft: JSON template required before any image processing
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()

Dim settings As String = "{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""VIN_Label"",
        ""ReferenceRegionNameArray"": [""VinRegion""],
        ""CharacterModelName"": ""VIN""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""VinRegion"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [5, 40],
            ""SecondPoint"": [95, 40],
            ""ThirdPoint"":  [95, 60],
            ""FourthPoint"": [5, 60]
        }
    }]
}"

recognizer.AppendSettingsFromString(settings)  ' fails silently if JSON is malformed
Dim results = recognizer.RecognizeFile(imagePath)
$vbLabelText   $csharpLabel
// IronOCR: no JSON, no template files — region is a constructor argument
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var region = new CropRectangle(x: 50, y: 400, width: 900, height: 200);
using var input = new OcrInput();
input.LoadImage(imagePath, region);

var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
// IronOCR: no JSON, no template files — region is a constructor argument
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var region = new CropRectangle(x: 50, y: 400, width: 900, height: 200);
using var input = new OcrInput();
input.LoadImage(imagePath, region);

var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
Imports IronOcr

' IronOCR: no JSON, no template files — region is a constructor argument
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim region As New CropRectangle(x:=50, y:=400, width:=900, height:=200)
Using input As New OcrInput()
    input.LoadImage(imagePath, region)

    Dim result = New IronTesseract().Read(input)
    Console.WriteLine(result.Text)
End Using
$vbLabelText   $csharpLabel

Comparaison des fonctionnalités IronOCR et de Dynamsoft OCR

Le tableau ci-dessous présente l'intégralité des différences de fonctionnalités entre les deux bibliothèques.

Fonction Reconnaissance d'étiquettes Dynamsoft IronOCR
OCR de documents généraux Non pris en charge Prise en charge complète
Reconnaissance de la MRZ Spécialisé (sortie texte brut) Intégré avec des champs structurés
Reconnaissance du NIV Spécialisé (modèle requis) OCR standard avec ciblage régional
lecture d'étiquettes industrielles Spécialisé (modèle requis) Oui, via CropRectangle
configuration des paramètres d'exécution Requis (JSON via AppendSettingsFromString) Non requis
artefacts de déploiement de modèle Requis (fichiers JSON) None
Entrée PDF native Non pris en charge Oui
PDF protégé par mot de passe Non pris en charge Oui
Entrée TIFF multipage Itération manuelle des pages Natif (LoadImageFrames)
Sortie PDF consultable Non pris en charge Oui (SaveAsSearchablePdf)
Lecture de codes-barres Produit séparé (lecteur de codes-barres Dynamsoft) Intégré (ReadBarCodes = true)
Prétraitement automatique Limité Oui (Détournement, Réduction du bruit, Contraste, Binarisation, Netteté, Dilatation, Érosion)
Sortie structurée (mots, lignes, paragraphes) Chaînes de texte brut LineResult Entièrement dactylographié avec coordonnées et confiance
Soutien linguistique Limité (Latin MRZ) Plus de 125 langues, regroupées sous forme de packages NuGet
Multilingue simultané Non pris en charge Oui (OcrLanguage.French + OcrLanguage.German)
scores de confiance Par ligne seulement Par mot, ligne, page
Exportation hOCR Non pris en charge Oui
Modèle de licence Abonnement annuel (599 $ et plus par appareil et par an) Perpétuel ($999 à usage unique, version Lite)
Plusieurs produits requis Oui (3+ pour une couverture complète) Non (un seul paquet)
Prise en charge du .NET Framework .NET Framework 4.x+ .NET Framework 4.6.2+, .NET 5/6/7/8/9
Déploiement multiplateforme Oui Oui (Windows, Linux, macOS, Docker, Azure, AWS)
Paquet NuGet Dynamsoft.LabelRecognizer IronOcr

Démarrage rapide : Migration de Dynamsoft OCR vers IronOCR

Étape 1 : Remplacer le package NuGet

Supprimez le package Dynamsoft :

dotnet remove package Dynamsoft.LabelRecognizer
dotnet remove package Dynamsoft.LabelRecognizer
SHELL

Installez IronOCR depuis la galerie NuGet :

dotnet add package IronOcr

Étape 2 : Mise à jour des espaces de noms

// Before (Dynamsoft)
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;

// After (IronOCR)
using IronOcr;
// Before (Dynamsoft)
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;

// After (IronOCR)
using IronOcr;
Imports IronOcr
$vbLabelText   $csharpLabel

Étape 3 : initialisation de la licence

Remplacez chaque appel statique InitLicense Dynamsoft par une seule attribution de licence IronOCR au démarrage de l'application :

// Before (Dynamsoft — one call per product)
LabelRecognizer.InitLicense("DYNAMSOFT-LICENSE-KEY");

// After (IronOCR — one line, all features)
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Before (Dynamsoft — one call per product)
LabelRecognizer.InitLicense("DYNAMSOFT-LICENSE-KEY");

// After (IronOCR — one line, all features)
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
' Before (Dynamsoft — one call per product)
LabelRecognizer.InitLicense("DYNAMSOFT-LICENSE-KEY")

' After (IronOCR — one line, all features)
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Exemples de migration de code

Reconnaissance basée sur des modèles pour un moteur sans configuration

Le système de modèles JSON de Dynamsoft fournit au SDK des instructions détaillées sur les modèles de caractères, les spécifications de région et les paramètres de reconnaissance avant tout traitement d'image. Pour la plupart des charges de travail OCR réelles, cette configuration ajoute de la complexité à la configuration sans apporter d'avantages en matière de reconnaissance, car le moteur Tesseract sous-jacent gère automatiquement la détection de la mise en page.

Approche Dynamsoft :

using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;

// JSON template required before recognition
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();

string invoiceTemplate = @"{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""Invoice_Header"",
        ""ReferenceRegionNameArray"": [""HeaderRegion""],
        ""CharacterModelName"": ""NumberLetter""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""HeaderRegion"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [0, 0],
            ""SecondPoint"": [100, 0],
            ""ThirdPoint"":  [100, 20],
            ""FourthPoint"": [0, 20]
        }
    }]
}";

recognizer.AppendSettingsFromString(invoiceTemplate);

var results = recognizer.RecognizeFile("invoice.jpg");
var headerText = new StringBuilder();
foreach (var result in results)
    foreach (var line in result.LineResults)
        headerText.AppendLine(line.Text);

Console.WriteLine(headerText.ToString());
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;

// JSON template required before recognition
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();

string invoiceTemplate = @"{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""Invoice_Header"",
        ""ReferenceRegionNameArray"": [""HeaderRegion""],
        ""CharacterModelName"": ""NumberLetter""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""HeaderRegion"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [0, 0],
            ""SecondPoint"": [100, 0],
            ""ThirdPoint"":  [100, 20],
            ""FourthPoint"": [0, 20]
        }
    }]
}";

recognizer.AppendSettingsFromString(invoiceTemplate);

var results = recognizer.RecognizeFile("invoice.jpg");
var headerText = new StringBuilder();
foreach (var result in results)
    foreach (var line in result.LineResults)
        headerText.AppendLine(line.Text);

Console.WriteLine(headerText.ToString());
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
Imports Dynamsoft.Core
Imports System.Text

' JSON template required before recognition
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()

Dim invoiceTemplate As String = "{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""Invoice_Header"",
        ""ReferenceRegionNameArray"": [""HeaderRegion""],
        ""CharacterModelName"": ""NumberLetter""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""HeaderRegion"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [0, 0],
            ""SecondPoint"": [100, 0],
            ""ThirdPoint"":  [100, 20],
            ""FourthPoint"": [0, 20]
        }
    }]
}"

recognizer.AppendSettingsFromString(invoiceTemplate)

Dim results = recognizer.RecognizeFile("invoice.jpg")
Dim headerText As New StringBuilder()
For Each result In results
    For Each line In result.LineResults
        headerText.AppendLine(line.Text)
    Next
Next

Console.WriteLine(headerText.ToString())
recognizer.Dispose()
$vbLabelText   $csharpLabel

Approche IronOCR :

using IronOcr;

// No template file — region specified inline, engine auto-configures
var region = new CropRectangle(x: 0, y: 0, width: 1200, height: 200);
using var input = new OcrInput();
input.LoadImage("invoice.jpg", region);
input.Deskew();

var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
Console.WriteLine($"Confidence: {result.Confidence}%");
using IronOcr;

// No template file — region specified inline, engine auto-configures
var region = new CropRectangle(x: 0, y: 0, width: 1200, height: 200);
using var input = new OcrInput();
input.LoadImage("invoice.jpg", region);
input.Deskew();

var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr

' No template file — region specified inline, engine auto-configures
Dim region As New CropRectangle(x:=0, y:=0, width:=1200, height:=200)
Using input As New OcrInput()
    input.LoadImage("invoice.jpg", region)
    input.Deskew()

    Dim result = New IronTesseract().Read(input)
    Console.WriteLine(result.Text)
    Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
$vbLabelText   $csharpLabel

L'approche de Dynamsoft exige la création, la validation et le déploiement d'un modèle JSON avant tout traitement d'image. Une faute de frappe dans AppendSettingsFromString renvoie des résultats vides à l'exécution — il n'y a pas de validation à la compilation. CropRectangle de IronOCR est un constructeur simple : vérification des types à la compilation, pas de fichiers externes, aucun artefact de déploiement. Consultez le guide OCR par région pour connaître tous les modèles de ciblage.

Lecture du code VIN avec migration de région

L'extraction des numéros d'identification des véhicules est une spécialité de Dynamsoft Label Recognizer. Son modèle de gabarit VIN est optimisé pour le format alphanumérique spécifique à 17 caractères. La migration vers IronOCR remplace le modèle de gabarit par un pipeline de prétraitement et un ciblage de région, qui gère les mêmes conditions de plaque VIN sans nécessiter de configuration de modèle de caractères.

Approche Dynamsoft :

using Dynamsoft.LabelRecognizer;

LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();

// VIN requires a specific character model and region configuration
string vinTemplate = @"{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""VIN_Scan"",
        ""ReferenceRegionNameArray"": [""VIN_Zone""],
        ""CharacterModelName"": ""VIN""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""VIN_Zone"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [10, 35],
            ""SecondPoint"": [90, 35],
            ""ThirdPoint"":  [90, 65],
            ""FourthPoint"": [10, 65]
        }
    }]
}";
recognizer.AppendSettingsFromString(vinTemplate);

var results = recognizer.RecognizeFile("vehicle-vin.jpg");
string rawVin = results
    .SelectMany(r => r.LineResults)
    .Select(l => l.Text)
    .FirstOrDefault() ?? string.Empty;

Console.WriteLine($"Raw VIN text: {rawVin}");  // still requires validation
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;

LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();

// VIN requires a specific character model and region configuration
string vinTemplate = @"{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""VIN_Scan"",
        ""ReferenceRegionNameArray"": [""VIN_Zone""],
        ""CharacterModelName"": ""VIN""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""VIN_Zone"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [10, 35],
            ""SecondPoint"": [90, 35],
            ""ThirdPoint"":  [90, 65],
            ""FourthPoint"": [10, 65]
        }
    }]
}";
recognizer.AppendSettingsFromString(vinTemplate);

var results = recognizer.RecognizeFile("vehicle-vin.jpg");
string rawVin = results
    .SelectMany(r => r.LineResults)
    .Select(l => l.Text)
    .FirstOrDefault() ?? string.Empty;

Console.WriteLine($"Raw VIN text: {rawVin}");  // still requires validation
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer

LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()

' VIN requires a specific character model and region configuration
Dim vinTemplate As String = "{
    ""LabelRecognizerParameterArray"": [{
        ""Name"": ""VIN_Scan"",
        ""ReferenceRegionNameArray"": [""VIN_Zone""],
        ""CharacterModelName"": ""VIN""
    }],
    ""ReferenceRegionArray"": [{
        ""Name"": ""VIN_Zone"",
        ""Localization"": {
            ""SourceType"": ""LST_MANUAL_SPECIFICATION"",
            ""FirstPoint"":  [10, 35],
            ""SecondPoint"": [90, 35],
            ""ThirdPoint"":  [90, 65],
            ""FourthPoint"": [10, 65]
        }
    }]
}"
recognizer.AppendSettingsFromString(vinTemplate)

Dim results = recognizer.RecognizeFile("vehicle-vin.jpg")
Dim rawVin As String = results _
    .SelectMany(Function(r) r.LineResults) _
    .Select(Function(l) l.Text) _
    .FirstOrDefault() OrElse String.Empty

Console.WriteLine($"Raw VIN text: {rawVin}")  ' still requires validation
recognizer.Dispose()
$vbLabelText   $csharpLabel

Approche IronOCR :

using IronOcr;
using System.Text.RegularExpressions;

// Target the VIN plate region directly — no template file
var vinRegion = new CropRectangle(x: 100, y: 350, width: 800, height: 300);

using var input = new OcrInput();
input.LoadImage("vehicle-vin.jpg", vinRegion);
input.Contrast();   // recover faded stamped digits
input.Sharpen();    // clarify character boundaries on embossed plates

var result = new IronTesseract().Read(input);

// VIN: 17 chars, no I/O/Q
var vinMatch = Regex.Match(result.Text, @"\b[A-HJ-NPR-Z0-9]{17}\b");
string vin = vinMatch.Success ? vinMatch.Value : result.Text.Trim();

Console.WriteLine($"VIN: {vin}");
Console.WriteLine($"Confidence: {result.Confidence}%");
using IronOcr;
using System.Text.RegularExpressions;

// Target the VIN plate region directly — no template file
var vinRegion = new CropRectangle(x: 100, y: 350, width: 800, height: 300);

using var input = new OcrInput();
input.LoadImage("vehicle-vin.jpg", vinRegion);
input.Contrast();   // recover faded stamped digits
input.Sharpen();    // clarify character boundaries on embossed plates

var result = new IronTesseract().Read(input);

// VIN: 17 chars, no I/O/Q
var vinMatch = Regex.Match(result.Text, @"\b[A-HJ-NPR-Z0-9]{17}\b");
string vin = vinMatch.Success ? vinMatch.Value : result.Text.Trim();

Console.WriteLine($"VIN: {vin}");
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr
Imports System.Text.RegularExpressions

' Target the VIN plate region directly — no template file
Dim vinRegion As New CropRectangle(x:=100, y:=350, width:=800, height:=300)

Using input As New OcrInput()
    input.LoadImage("vehicle-vin.jpg", vinRegion)
    input.Contrast()   ' recover faded stamped digits
    input.Sharpen()    ' clarify character boundaries on embossed plates

    Dim result = New IronTesseract().Read(input)

    ' VIN: 17 chars, no I/O/Q
    Dim vinMatch = Regex.Match(result.Text, "\b[A-HJ-NPR-Z0-9]{17}\b")
    Dim vin As String = If(vinMatch.Success, vinMatch.Value, result.Text.Trim())

    Console.WriteLine($"VIN: {vin}")
    Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
$vbLabelText   $csharpLabel

Les coordonnées CropRectangle utilisent la même référence de pixel que la spécification à base de pourcentage SecondPoint de Dynamsoft — convertissez en multipliant les valeurs en pourcentage de Dynamsoft par les dimensions de votre image. Le pipeline de prétraitement (Contrast, Sharpen) remplace l'optimisation du modèle de caractères que Dynamsoft incorpore dans son modèle VIN. Le guide de correction de la qualité d'image traite de la sélection des filtres pour les surfaces en relief et à faible contraste.

Traitement par lots TIFF multipages

Dynamsoft Label Recognizer traite les images individuelles. Les documents TIFF multipages — courants dans les systèmes de gestion de documents, les archives d'imagerie médicale et les chaînes de télécopie — nécessitent une itération externe : charger chaque image, la faire passer individuellement dans le système de reconnaissance et agréger les résultats. IronOCR gère nativement les TIFF à plusieurs cadres via LoadImageFrames.

Approche Dynamsoft :

using Dynamsoft.LabelRecognizer;
// Requires an external TIFF library to extract frames

LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(genericTemplate);

// External library needed to iterate TIFF frames
var tiffImage = System.Drawing.Image.FromFile("scanned-batch.tiff");
int frameCount = tiffImage.GetFrameCount(
    System.Drawing.Imaging.FrameDimension.Page);

var allText = new StringBuilder();
for (int i = 0; i < frameCount; i++)
{
    tiffImage.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
    string tempPath = $"frame_{i}.jpg";
    tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Jpeg);

    var results = recognizer.RecognizeFile(tempPath);
    foreach (var r in results)
        foreach (var line in r.LineResults)
            allText.AppendLine(line.Text);

    System.IO.File.Delete(tempPath);  // clean up temp files
}

Console.WriteLine(allText.ToString());
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
// Requires an external TIFF library to extract frames

LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(genericTemplate);

// External library needed to iterate TIFF frames
var tiffImage = System.Drawing.Image.FromFile("scanned-batch.tiff");
int frameCount = tiffImage.GetFrameCount(
    System.Drawing.Imaging.FrameDimension.Page);

var allText = new StringBuilder();
for (int i = 0; i < frameCount; i++)
{
    tiffImage.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
    string tempPath = $"frame_{i}.jpg";
    tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Jpeg);

    var results = recognizer.RecognizeFile(tempPath);
    foreach (var r in results)
        foreach (var line in r.LineResults)
            allText.AppendLine(line.Text);

    System.IO.File.Delete(tempPath);  // clean up temp files
}

Console.WriteLine(allText.ToString());
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Text

' Requires an external TIFF library to extract frames

LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
recognizer.AppendSettingsFromString(genericTemplate)

' External library needed to iterate TIFF frames
Dim tiffImage As Image = Image.FromFile("scanned-batch.tiff")
Dim frameCount As Integer = tiffImage.GetFrameCount(FrameDimension.Page)

Dim allText As New StringBuilder()
For i As Integer = 0 To frameCount - 1
    tiffImage.SelectActiveFrame(FrameDimension.Page, i)
    Dim tempPath As String = $"frame_{i}.jpg"
    tiffImage.Save(tempPath, Imaging.ImageFormat.Jpeg)

    Dim results = recognizer.RecognizeFile(tempPath)
    For Each r In results
        For Each line In r.LineResults
            allText.AppendLine(line.Text)
        Next
    Next

    File.Delete(tempPath)  ' clean up temp files
Next

Console.WriteLine(allText.ToString())
recognizer.Dispose()
$vbLabelText   $csharpLabel

Approche IronOCR :

using IronOcr;

// No frame iteration, no temp files, no external TIFF library
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff");  // loads all frames natively
input.Deskew();
input.DeNoise();

var ocr = new IronTesseract();
var result = ocr.Read(input);

// Results organized per page
foreach (var page in result.Pages)
{
    Console.WriteLine($"Frame {page.PageNumber}: {page.Lines.Count} lines");
    Console.WriteLine(page.Text);
}

// Save entire batch as a single searchable PDF
result.SaveAsSearchablePdf("batch-searchable.pdf");
using IronOcr;

// No frame iteration, no temp files, no external TIFF library
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff");  // loads all frames natively
input.Deskew();
input.DeNoise();

var ocr = new IronTesseract();
var result = ocr.Read(input);

// Results organized per page
foreach (var page in result.Pages)
{
    Console.WriteLine($"Frame {page.PageNumber}: {page.Lines.Count} lines");
    Console.WriteLine(page.Text);
}

// Save entire batch as a single searchable PDF
result.SaveAsSearchablePdf("batch-searchable.pdf");
Imports IronOcr

' No frame iteration, no temp files, no external TIFF library
Using input As New OcrInput()
    input.LoadImageFrames("scanned-batch.tiff") ' loads all frames natively
    input.Deskew()
    input.DeNoise()

    Dim ocr As New IronTesseract()
    Dim result = ocr.Read(input)

    ' Results organized per page
    For Each page In result.Pages
        Console.WriteLine($"Frame {page.PageNumber}: {page.Lines.Count} lines")
        Console.WriteLine(page.Text)
    Next

    ' Save entire batch as a single searchable PDF
    result.SaveAsSearchablePdf("batch-searchable.pdf")
End Using
$vbLabelText   $csharpLabel

L'approche Dynamsoft nécessite System.Drawing pour l'extraction de cadres, un fichier temporaire sur disque par cadre, et un nettoyage manuel après chaque passe. LoadImageFrames de IronOCR lit tous les cadres en un seul appel — pas de fichiers temporaires, pas de suivi des index de cadres. Après l'OCR, SaveAsSearchablePdf archive l'ensemble du lot en tant que document consultable en un seul appel de méthode. Le guide sur le format TIFF multi-images et le guide sur la sortie PDF consultable couvrent ces deux fonctionnalités en détail.

Analyse syntaxique structurée des résultats au niveau des mots

Dynamsoft RecognizeFile renvoie un tableau DLRResult. Chaque DLRResult contient une collection LineResults d'objets DLRLineResult avec une propriété Text et une propriété Location contenant le quadrilatère englobant. L'extraction des positions au niveau des mots nécessite de diviser le texte de la ligne en fonction des espaces blancs et de diviser proportionnellement le cadre englobant la ligne — une approximation qui ne fonctionne pas avec les polices proportionnelles. IronOCR expose les boîtes englobantes de niveau mot en tant que propriétés typées sur chaque objet OcrResult.Word.

Approche Dynamsoft :

using Dynamsoft.LabelRecognizer;

LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(settingsJson);

var results = recognizer.RecognizeFile("form-scan.jpg");

foreach (var dlrResult in results)
{
    foreach (var lineResult in dlrResult.LineResults)
    {
        // Line-level data only — word boundaries are not provided
        Console.WriteLine($"Text: {lineResult.Text}");
        Console.WriteLine($"Confidence: {lineResult.Confidence}");

        // Location is a quadrilateral — four corner points
        var loc = lineResult.Location;
        Console.WriteLine($"Top-left: ({loc.Points[0].X}, {loc.Points[0].Y})");

        // To get word positions: split text and divide bounding box manually
        var words = lineResult.Text.Split(' ');
        int approxWidth = (loc.Points[1].X - loc.Points[0].X) / words.Length;
        for (int i = 0; i < words.Length; i++)
        {
            int wordX = loc.Points[0].X + (i * approxWidth);
            Console.WriteLine($"  Word '{words[i]}' approx at x={wordX}");
        }
    }
}
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;

LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(settingsJson);

var results = recognizer.RecognizeFile("form-scan.jpg");

foreach (var dlrResult in results)
{
    foreach (var lineResult in dlrResult.LineResults)
    {
        // Line-level data only — word boundaries are not provided
        Console.WriteLine($"Text: {lineResult.Text}");
        Console.WriteLine($"Confidence: {lineResult.Confidence}");

        // Location is a quadrilateral — four corner points
        var loc = lineResult.Location;
        Console.WriteLine($"Top-left: ({loc.Points[0].X}, {loc.Points[0].Y})");

        // To get word positions: split text and divide bounding box manually
        var words = lineResult.Text.Split(' ');
        int approxWidth = (loc.Points[1].X - loc.Points[0].X) / words.Length;
        for (int i = 0; i < words.Length; i++)
        {
            int wordX = loc.Points[0].X + (i * approxWidth);
            Console.WriteLine($"  Word '{words[i]}' approx at x={wordX}");
        }
    }
}
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer

LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
recognizer.AppendSettingsFromString(settingsJson)

Dim results = recognizer.RecognizeFile("form-scan.jpg")

For Each dlrResult In results
    For Each lineResult In dlrResult.LineResults
        ' Line-level data only — word boundaries are not provided
        Console.WriteLine($"Text: {lineResult.Text}")
        Console.WriteLine($"Confidence: {lineResult.Confidence}")

        ' Location is a quadrilateral — four corner points
        Dim loc = lineResult.Location
        Console.WriteLine($"Top-left: ({loc.Points(0).X}, {loc.Points(0).Y})")

        ' To get word positions: split text and divide bounding box manually
        Dim words = lineResult.Text.Split(" "c)
        Dim approxWidth As Integer = (loc.Points(1).X - loc.Points(0).X) \ words.Length
        For i As Integer = 0 To words.Length - 1
            Dim wordX As Integer = loc.Points(0).X + (i * approxWidth)
            Console.WriteLine($"  Word '{words(i)}' approx at x={wordX}")
        Next
    Next
Next
recognizer.Dispose()
$vbLabelText   $csharpLabel

Approche IronOCR :

using IronOcr;

var result = new IronTesseract().Read("form-scan.jpg");

// Word-level positions are first-class properties — no manual division
foreach (var page in result.Pages)
{
    foreach (var paragraph in page.Paragraphs)
    {
        Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");

        foreach (var line in paragraph.Lines)
        {
            foreach (var word in line.Words)
            {
                Console.WriteLine(
                    $"  Word: '{word.Text}' " +
                    $"at ({word.X},{word.Y}) " +
                    $"size {word.Width}x{word.Height} " +
                    $"confidence {word.Confidence}%");
            }
        }
    }
}
using IronOcr;

var result = new IronTesseract().Read("form-scan.jpg");

// Word-level positions are first-class properties — no manual division
foreach (var page in result.Pages)
{
    foreach (var paragraph in page.Paragraphs)
    {
        Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");

        foreach (var line in paragraph.Lines)
        {
            foreach (var word in line.Words)
            {
                Console.WriteLine(
                    $"  Word: '{word.Text}' " +
                    $"at ({word.X},{word.Y}) " +
                    $"size {word.Width}x{word.Height} " +
                    $"confidence {word.Confidence}%");
            }
        }
    }
}
Imports IronOcr

Dim result = New IronTesseract().Read("form-scan.jpg")

' Word-level positions are first-class properties — no manual division
For Each page In result.Pages
    For Each paragraph In page.Paragraphs
        Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}")

        For Each line In paragraph.Lines
            For Each word In line.Words
                Console.WriteLine(
                    $"  Word: '{word.Text}' " &
                    $"at ({word.X},{word.Y}) " &
                    $"size {word.Width}x{word.Height} " &
                    $"confidence {word.Confidence}%")
            Next
        Next
    Next
Next
$vbLabelText   $csharpLabel

IronOCR offre une véritable hiérarchie : les pages contiennent des paragraphes, les paragraphes contiennent des lignes, les lignes contiennent des mots, les mots contiennent des caractères. À chaque niveau, .X, .Y, .Width, .Height et .Confidence sont exposés en tant que propriétés numériques entières et à virgule flottante — pas besoin d'arithmétique sur les coordonnées quadrilatérales. Le guide des résultats structurés documente chaque propriété accessible, et le guide d'évaluation de la confiance explique le seuil de confiance pour les chaînes de traitement automatisées des documents.

Traitement parallèle asynchrone pour la numérisation d'étiquettes à haut volume

Le Reconnaissance d'étiquettes Dynamsoft est thread-safe, mais son appel RecognizeFile est synchrone. Le conditionner avec Task.Run produit un traitement parallèle, mais chaque appel partage l'état de configuration via AppendSettingsFromString — le chargement des modèles sur plusieurs threads nécessite une séquence d'initialisation minutieuse. Les instances IronTesseract de IronOCR sont indépendantes : créez-en une par tâche, appelez Read, et le modèle de thread est simple.

Approche Dynamsoft :

using Dynamsoft.LabelRecognizer;
using System.Threading.Tasks;

// InitLicense must be called once before parallel work begins
LabelRecognizer.InitLicense(licenseKey);

// Each thread needs its own recognizer instance with its own template load
var results = new System.Collections.Concurrent.ConcurrentBag<string>();

await Task.WhenAll(imagePaths.Select(async path =>
{
    // Cannot share recognizer instances safely across tasks
    var recognizer = new LabelRecognizer();
    recognizer.AppendSettingsFromString(templateJson);  // reload JSON per instance

    await Task.Run(() =>
    {
        var dlrResults = recognizer.RecognizeFile(path);
        var text = string.Join("\n",
            dlrResults.SelectMany(r => r.LineResults).Select(l => l.Text));
        results.Add(text);
    });

    recognizer.Dispose();
}));

Console.WriteLine($"Processed {results.Count} images");
using Dynamsoft.LabelRecognizer;
using System.Threading.Tasks;

// InitLicense must be called once before parallel work begins
LabelRecognizer.InitLicense(licenseKey);

// Each thread needs its own recognizer instance with its own template load
var results = new System.Collections.Concurrent.ConcurrentBag<string>();

await Task.WhenAll(imagePaths.Select(async path =>
{
    // Cannot share recognizer instances safely across tasks
    var recognizer = new LabelRecognizer();
    recognizer.AppendSettingsFromString(templateJson);  // reload JSON per instance

    await Task.Run(() =>
    {
        var dlrResults = recognizer.RecognizeFile(path);
        var text = string.Join("\n",
            dlrResults.SelectMany(r => r.LineResults).Select(l => l.Text));
        results.Add(text);
    });

    recognizer.Dispose();
}));

Console.WriteLine($"Processed {results.Count} images");
Imports Dynamsoft.LabelRecognizer
Imports System.Threading.Tasks
Imports System.Collections.Concurrent

' InitLicense must be called once before parallel work begins
LabelRecognizer.InitLicense(licenseKey)

' Each thread needs its own recognizer instance with its own template load
Dim results As New ConcurrentBag(Of String)()

Await Task.WhenAll(imagePaths.Select(Async Function(path)
    ' Cannot share recognizer instances safely across tasks
    Dim recognizer As New LabelRecognizer()
    recognizer.AppendSettingsFromString(templateJson)  ' reload JSON per instance

    Await Task.Run(Sub()
        Dim dlrResults = recognizer.RecognizeFile(path)
        Dim text = String.Join(vbLf, dlrResults.SelectMany(Function(r) r.LineResults).Select(Function(l) l.Text))
        results.Add(text)
    End Sub)

    recognizer.Dispose()
End Function))

Console.WriteLine($"Processed {results.Count} images")
$vbLabelText   $csharpLabel

Approche IronOCR :

using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

var extractedTexts = new ConcurrentDictionary<string, string>();

// Each IronTesseract instance is independent — no shared state
Parallel.ForEach(imagePaths, imagePath =>
{
    var ocr = new IronTesseract();
    var result = ocr.Read(imagePath);
    extractedTexts[imagePath] = result.Text;
});

foreach (var (path, text) in extractedTexts)
    Console.WriteLine($"{System.IO.Path.GetFileName(path)}: {text.Length} characters");
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

var extractedTexts = new ConcurrentDictionary<string, string>();

// Each IronTesseract instance is independent — no shared state
Parallel.ForEach(imagePaths, imagePath =>
{
    var ocr = new IronTesseract();
    var result = ocr.Read(imagePath);
    extractedTexts[imagePath] = result.Text;
});

foreach (var (path, text) in extractedTexts)
    Console.WriteLine($"{System.IO.Path.GetFileName(path)}: {text.Length} characters");
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Dim extractedTexts As New ConcurrentDictionary(Of String, String)()

' Each IronTesseract instance is independent — no shared state
Parallel.ForEach(imagePaths, Sub(imagePath)
    Dim ocr As New IronTesseract()
    Dim result = ocr.Read(imagePath)
    extractedTexts(imagePath) = result.Text
End Sub)

For Each kvp In extractedTexts
    Dim path = kvp.Key
    Dim text = kvp.Value
    Console.WriteLine($"{System.IO.Path.GetFileName(path)}: {text.Length} characters")
Next
$vbLabelText   $csharpLabel

IronOCR ne nécessite aucune séquence d'initialisation avant le début du travail parallèle. Une seule attribution IronOcr.License.LicenseKey au démarrage de l'application active toutes les instances. Aucun rechargement de modèle par thread, aucune validation JSON par instance. Pour les scénarios côté serveur non bloquants, le guide OCR asynchrone couvre les modèles basés sur await pour ASP.NET Core et Azure Functions.

Sortie PDF consultable à partir des archives d'étiquettes numérisées

Dynamsoft ne propose aucune fonctionnalité d'exportation PDF. Les archives d'étiquettes numérisées traitées par Dynamsoft restent des fichiers image uniquement — non consultables, non indexables par les systèmes de gestion de documents et non conformes aux normes d'archivage PDF/A. IronOCR ajoute une sortie PDF consultable en tant qu'appel de méthode unique sur l'objet OcrResult.

Approche Dynamsoft :

using Dynamsoft.LabelRecognizer;

// Process scanned label — extract text into a string
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(labelTemplate);

var results = recognizer.RecognizeFile("scanned-labels.jpg");
var extractedText = new StringBuilder();
foreach (var r in results)
    foreach (var line in r.LineResults)
        extractedText.AppendLine(line.Text);

// Cannot create a searchable PDF — save text to a sidecar .txt file instead
System.IO.File.WriteAllText("scanned-labels.txt", extractedText.ToString());

// The original image remains unsearchable
Console.WriteLine("No PDF output available in Dynamsoft Label Recognizer.");
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;

// Process scanned label — extract text into a string
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(labelTemplate);

var results = recognizer.RecognizeFile("scanned-labels.jpg");
var extractedText = new StringBuilder();
foreach (var r in results)
    foreach (var line in r.LineResults)
        extractedText.AppendLine(line.Text);

// Cannot create a searchable PDF — save text to a sidecar .txt file instead
System.IO.File.WriteAllText("scanned-labels.txt", extractedText.ToString());

// The original image remains unsearchable
Console.WriteLine("No PDF output available in Dynamsoft Label Recognizer.");
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
Imports System.IO
Imports System.Text

' Process scanned label — extract text into a string
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer = New LabelRecognizer()
recognizer.AppendSettingsFromString(labelTemplate)

Dim results = recognizer.RecognizeFile("scanned-labels.jpg")
Dim extractedText = New StringBuilder()
For Each r In results
    For Each line In r.LineResults
        extractedText.AppendLine(line.Text)
    Next
Next

' Cannot create a searchable PDF — save text to a sidecar .txt file instead
File.WriteAllText("scanned-labels.txt", extractedText.ToString())

' The original image remains unsearchable
Console.WriteLine("No PDF output available in Dynamsoft Label Recognizer.")
recognizer.Dispose()
$vbLabelText   $csharpLabel

Approche IronOCR :

using IronOcr;

// Read, preprocess, and produce a searchable PDF archive in one pipeline
using var input = new OcrInput();
input.LoadImage("scanned-labels.jpg");
input.Deskew();
input.Contrast();

var ocr = new IronTesseract();
var result = ocr.Read(input);

// Searchable PDF: original image layer preserved, invisible text layer added
result.SaveAsSearchablePdf("scanned-labels-searchable.pdf");

Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%");
Console.WriteLine($"Extracted text preview: {result.Text.Substring(0, 100)}");
using IronOcr;

// Read, preprocess, and produce a searchable PDF archive in one pipeline
using var input = new OcrInput();
input.LoadImage("scanned-labels.jpg");
input.Deskew();
input.Contrast();

var ocr = new IronTesseract();
var result = ocr.Read(input);

// Searchable PDF: original image layer preserved, invisible text layer added
result.SaveAsSearchablePdf("scanned-labels-searchable.pdf");

Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%");
Console.WriteLine($"Extracted text preview: {result.Text.Substring(0, 100)}");
Imports IronOcr

' Read, preprocess, and produce a searchable PDF archive in one pipeline
Using input As New OcrInput()
    input.LoadImage("scanned-labels.jpg")
    input.Deskew()
    input.Contrast()

    Dim ocr As New IronTesseract()
    Dim result = ocr.Read(input)

    ' Searchable PDF: original image layer preserved, invisible text layer added
    result.SaveAsSearchablePdf("scanned-labels-searchable.pdf")

    Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%")
    Console.WriteLine($"Extracted text preview: {result.Text.Substring(0, 100)}")
End Using
$vbLabelText   $csharpLabel

Le PDF consultable conserve l'image numérisée originale en pleine résolution et y ajoute une couche de texte OCR invisible. Les systèmes de gestion documentaire, les index de recherche et les visionneuses PDF peuvent désormais effectuer des recherches dans le contenu des étiquettes. Le guide pratique au format PDF consultable et le guide de traitement des documents numérisés couvrent les archives multipages et les flux de travail de conversion par lots.

Référence de mappage de l'API OCR de Dynamsoft vers IronOCR

Reconnaissance d'étiquettes Dynamsoft Équivalent d'IronOCR
LabelRecognizer.InitLicense(key) IronOcr.License.LicenseKey = key
new LabelRecognizer() new IronTesseract()
recognizer.AppendSettingsFromString(json) Non requis — configuration automatique
recognizer.RecognizeFile(path) ocr.Read(path)
recognizer.RecognizeByFile(path, templateName) ocr.Read(path)
recognizer.RecognizeBuffer(buffer, width, height, ...) input.LoadImage(imageBytes) puis ocr.Read(input)
DLRResult[] (tableau de résultats) OcrResult (objet de résultat unique)
DLRResult.LineResults OcrResult.Lines
DLRLineResult.Text OcrResult.Line.Text
DLRLineResult.Confidence OcrResult.Line.Words[i].Confidence
DLRLineResult.Location.Points[i] OcrResult.Line.X, .Y, .Width, .Height
ReferenceRegionArray (JSON) new CropRectangle(x, y, w, h)
LabelRecognizerParameterArray (JSON) Non requis
CharacterModelName dans le modèle Non requis
recognizer.Dispose() using var ocr = new IronTesseract()
Aucune prise en charge de l'importation de fichiers PDF input.LoadPdf(path)
Aucun fichier PDF consultable result.SaveAsSearchablePdf(path)
Aucune entrée TIFF multipage input.LoadImageFrames(path)
Lecture de code-barres (produit séparé) ocr.Configuration.ReadBarCodes = true
Appels multiples InitLicense (par produit) Attribution unique IronOcr.License.LicenseKey

Problèmes de migration courants et solutions

Problème 1 : AppendSettingsFromString renvoie des résultats vides après la migration

Dynamsoft : La reconnaissance renvoie silencieusement des tableaux DLRResult vides lorsque AppendSettingsFromString reçoit une chaîne JSON mal formée. Aucune exception n'est levée. Les équipes qui migrent depuis Dynamsoft ajoutent parfois des vérifications de valeurs nulles défensives dans tout leur code d'analyse des résultats afin de se prémunir contre cette défaillance silencieuse.

Solution : Supprimez entièrement AppendSettingsFromString. IronOCR ne nécessite aucune configuration de modèle. Si un ciblage de région spécifique est nécessaire, remplacez le JSON ReferenceRegionArray par un CropRectangle :

// Remove all AppendSettingsFromString calls
// Replace region JSON with a CropRectangle constructor
var region = new CropRectangle(x: 0, y: 400, width: 1200, height: 300);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
var result = new IronTesseract().Read(input);
// Remove all AppendSettingsFromString calls
// Replace region JSON with a CropRectangle constructor
var region = new CropRectangle(x: 0, y: 400, width: 1200, height: 300);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
var result = new IronTesseract().Read(input);
Imports System

' Remove all AppendSettingsFromString calls
' Replace region JSON with a CropRectangle constructor
Dim region As New CropRectangle(x:=0, y:=400, width:=1200, height:=300)
Using input As New OcrInput()
    input.LoadImage(imagePath, region)
    Dim result = New IronTesseract().Read(input)
End Using
$vbLabelText   $csharpLabel

Le guide d'installation d'IronTesseract documente toutes les options de configuration du moteur qui peuvent être définies en tant que propriétés plutôt que sous forme de chaînes JSON.

Problème 2 : Appels multiples à InitLicense au démarrage de l'application

Dynamsoft : Une application utilisant Label Recognizer, Barcode Reader et Document Normalizer appelle trois méthodes InitLicense distinctes au démarrage, chacune nécessitant sa propre clé de licence. Les équipes stockent trois variables d'environnement, font pivoter trois clés indépendamment et déboguent trois échecs d'initialisation distincts.

Solution : Supprimez tous les appels InitLicense Dynamsoft. Remplacer par une seule ligne IronOCR :

// Remove:
// LabelRecognizer.InitLicense(mrzKey);
// BarcodeReader.InitLicense(barcodeKey);
// DocumentNormalizer.InitLicense(docKey);

// Add once, at application startup:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
// Remove:
// LabelRecognizer.InitLicense(mrzKey);
// BarcodeReader.InitLicense(barcodeKey);
// DocumentNormalizer.InitLicense(docKey);

// Add once, at application startup:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
' Remove:
' LabelRecognizer.InitLicense(mrzKey)
' BarcodeReader.InitLicense(barcodeKey)
' DocumentNormalizer.InitLicense(docKey)

' Add once, at application startup:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
$vbLabelText   $csharpLabel

Une seule variable d'environnement active toutes les fonctionnalités IronOCR (OCR, codes-barres, traitement PDF et plus de 125 langues) sans qu'aucune initialisation par fonctionnalité ne soit requise.

Problème 3 : L'agrégation de texte LineResult produit une sortie brouillée

Dynamsoft : RecognizeFile renvoie un DLRResult par région d'étiquette détectée. Les applications qui concatènent lineResult.Text sur tous les résultats avec des séparateurs \n produisent une sortie qui mélange les lignes de différentes zones d'étiquette sur la page — parce que l'ordre des objets DLRResult est l'ordre de détection des régions, pas l'ordre de lecture.

Solution : La hiérarchie des résultats d'IronOCR organise la sortie dans l'ordre de lecture. Utilisez la structure PagesParagraphsLines pour accéder au texte dans l'ordre naturel du document :

var result = new IronTesseract().Read(imagePath);

// Reading-order text — no manual aggregation
Console.WriteLine(result.Text);

// Or access paragraph-level groupings
foreach (var paragraph in result.Pages[0].Paragraphs)
    Console.WriteLine(paragraph.Text);
var result = new IronTesseract().Read(imagePath);

// Reading-order text — no manual aggregation
Console.WriteLine(result.Text);

// Or access paragraph-level groupings
foreach (var paragraph in result.Pages[0].Paragraphs)
    Console.WriteLine(paragraph.Text);
Imports IronOcr

Dim result = New IronTesseract().Read(imagePath)

' Reading-order text — no manual aggregation
Console.WriteLine(result.Text)

' Or access paragraph-level groupings
For Each paragraph In result.Pages(0).Paragraphs
    Console.WriteLine(paragraph.Text)
Next
$vbLabelText   $csharpLabel

Problème n° 4 : Fichiers JSON de modèle manquants sur le serveur de déploiement

Dynamsoft : Les fichiers JSON de modèle sont des artefacts de déploiement distincts. Lorsqu'un fichier modèle est manquant ou a un chemin incorrect sur un nouveau serveur, AppendSettingsFromString échoue — parfois silencieusement, parfois avec une exception à l'exécution — et le déploiement brise la reconnaissance sans toucher au code de l'application.

Solution : IronOCR ne possède aucun fichier modèle. Après le remplacement du package NuGet et la mise à jour des espaces de noms, la liste des artefacts de déploiement se réduit aux binaires de l'application et à une variable d'environnement. Ajoutez une vérification de validation au démarrage si nécessaire :

// Validate license at startup — no template files to check
if (!IronOcr.License.IsValidLicense)
    throw new InvalidOperationException("IronOCR license key is invalid or missing.");

var ocr = new IronTesseract();
// Ready to process — no file dependencies
// Validate license at startup — no template files to check
if (!IronOcr.License.IsValidLicense)
    throw new InvalidOperationException("IronOCR license key is invalid or missing.");

var ocr = new IronTesseract();
// Ready to process — no file dependencies
Imports IronOcr

' Validate license at startup — no template files to check
If Not IronOcr.License.IsValidLicense Then
    Throw New InvalidOperationException("IronOCR license key is invalid or missing.")
End If

Dim ocr As New IronTesseract()
' Ready to process — no file dependencies
$vbLabelText   $csharpLabel

Problème n° 5 : Gestion de la chaîne d'élimination pour plusieurs produits

Dynamsoft : Chaque instance de produit Dynamsoft (LabelRecognizer, BarcodeReader, DocumentNormalizer) implémente IDisposable. Les classes de service qui agrègent plusieurs produits portent des implémentations Dispose à plusieurs niveaux, et omettre un appel Dispose sur toute instance de produit provoque des fuites de ressources natives qui se manifestent par une croissance de la mémoire sous charge.

Solution : IronTesseract et OcrInput d'IronOCR implémentent tous deux IDisposable, mais le modèle de disposition est plus simple — une classe, un pattern. Enregistrez une instance IronTesseract dans le conteneur DI comme singleton, ou utilisez des blocs using pour des instances de courte durée :

// Short-lived pattern
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = new IronTesseract().Read(input);

// Long-lived singleton (register in Program.cs)
builder.Services.AddSingleton<IronTesseract>();
// Short-lived pattern
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = new IronTesseract().Read(input);

// Long-lived singleton (register in Program.cs)
builder.Services.AddSingleton<IronTesseract>();
Imports IronOcr

' Short-lived pattern
Using input As New OcrInput()
    input.LoadImage(imagePath)
    Dim result = (New IronTesseract()).Read(input)
End Using

' Long-lived singleton (register in Program.vb)
builder.Services.AddSingleton(Of IronTesseract)()
$vbLabelText   $csharpLabel

Le guide de suivi de la progression couvre la gestion du cycle de vie des tâches par lots de longue durée, et le guide OCR asynchrone présente les modèles singleton dans ASP.NET Core.

Problème n° 6 : Modèle de caractères non disponible pour le format d'étiquette personnalisé

Dynamsoft : Le champ CharacterModelName dans un modèle fait référence à un fichier modèle qui doit exister dans le répertoire d'installation de Dynamsoft SDK. Les modèles de personnages personnalisés nécessitent le téléchargement de fichiers de modèle supplémentaires depuis le portail de Dynamsoft et leur placement dans le chemin SDK approprié. L'absence d'un modèle entraîne l'échec de la reconnaissance et une erreur d'exécution obscure.

Solution : IronOCR n'utilise pas de fichiers de modèles de caractères. Pour les polices personnalisées ou spécialisées, utilisez une formation linguistique personnalisée :

// No character model files needed
// For specialized fonts, use a custom language pack
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English;  // or load a custom trained pack

using var input = new OcrInput();
input.LoadImage(specializedFontImage);
input.Binarize();  // helps with specialized font clarity

var result = ocr.Read(input);
// No character model files needed
// For specialized fonts, use a custom language pack
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English;  // or load a custom trained pack

using var input = new OcrInput();
input.LoadImage(specializedFontImage);
input.Binarize();  // helps with specialized font clarity

var result = ocr.Read(input);
Imports IronTesseract

' No character model files needed
' For specialized fonts, use a custom language pack
Dim ocr As New IronTesseract()
ocr.Language = OcrLanguage.English  ' or load a custom trained pack

Using input As New OcrInput()
    input.LoadImage(specializedFontImage)
    input.Binarize()  ' helps with specialized font clarity

    Dim result = ocr.Read(input)
End Using
$vbLabelText   $csharpLabel

Le guide de formation aux polices personnalisées couvre la formation d'un pack de langue personnalisé pour les polices d'étiquettes propriétaires sans aucune configuration de chemin de fichier.

Liste de contrôle de migration OCR Dynamsoft

Pré-migration

Vérifiez le code source pour toutes les références à Dynamsoft :

# Find all Dynamsoft using statements
grep -r "using Dynamsoft" --include="*.cs" .

# Find InitLicense calls (one per product)
grep -r "InitLicense" --include="*.cs" .

# Find AppendSettingsFromString calls (template loads)
grep -r "AppendSettingsFromString" --include="*.cs" .

# Find template JSON strings (inline or file references)
grep -r "LabelRecognizerParameterArray\|ReferenceRegionArray\|CharacterModelName" --include="*.cs" .

# Find RecognizeFile and RecognizeByFile calls
grep -r "RecognizeFile\|RecognizeByFile\|RecognizeBuffer" --include="*.cs" .

# Find LineResult result parsing patterns
grep -r "LineResults\|DLRResult\|DLRLineResult" --include="*.cs" .

# Identify any JSON template files in the project
find . -name "*.json" | xargs grep -l "LabelRecognizerParameterArray" 2>/dev/null
# Find all Dynamsoft using statements
grep -r "using Dynamsoft" --include="*.cs" .

# Find InitLicense calls (one per product)
grep -r "InitLicense" --include="*.cs" .

# Find AppendSettingsFromString calls (template loads)
grep -r "AppendSettingsFromString" --include="*.cs" .

# Find template JSON strings (inline or file references)
grep -r "LabelRecognizerParameterArray\|ReferenceRegionArray\|CharacterModelName" --include="*.cs" .

# Find RecognizeFile and RecognizeByFile calls
grep -r "RecognizeFile\|RecognizeByFile\|RecognizeBuffer" --include="*.cs" .

# Find LineResult result parsing patterns
grep -r "LineResults\|DLRResult\|DLRLineResult" --include="*.cs" .

# Identify any JSON template files in the project
find . -name "*.json" | xargs grep -l "LabelRecognizerParameterArray" 2>/dev/null
SHELL

Résultats de l'inventaire :

  • Comptez les sites d'appel InitLicense (un par produit Dynamsoft utilisé)
  • Comptez les sites d'appel AppendSettingsFromString (un par modèle de reconnaissance)
  • Liste de tous les fichiers de modèles JSON qui seront supprimés après la migration
  • Identifiez toute définition ReferenceRegionArray (convertir en CropRectangle)
  • Notez quelles fonctionnalités sont couvertes par des produits distincts (codes-barres, normalisation des documents).

Migration de code

  1. Supprimez le package NuGet Dynamsoft.LabelRecognizer (et tout autre package Dynamsoft)
  2. Installez le package NuGet IronOcr (dotnet add package IronOcr)
  3. Remplacez tous using Dynamsoft.LabelRecognizer; et using Dynamsoft.Core; par using IronOcr;
  4. Remplacez tous les appels LabelRecognizer.InitLicense(key) par un seul IronOcr.License.LicenseKey = key au démarrage de l'application
  5. Supprimez tous les appels AppendSettingsFromString(json) — aucun équivalent requis
  6. Remplacez les coordonnées JSON ReferenceRegionArray par des constructeurs new CropRectangle(x, y, width, height)
  7. Remplacez l'instanciation new LabelRecognizer() par new IronTesseract()
  8. Remplacez recognizer.RecognizeFile(path) par ocr.Read(path)
  9. Remplacez l'itération des résultats DLRLineResult par la hiérarchie .Words
  10. Remplacez l'agrégation manuelle des chaînes lineResult.Text par result.Text ou une énumération structurée des pages
  11. Remplacez BarcodeReader.InitLicense + BarcodeReader.DecodeFile par ocr.Configuration.ReadBarCodes = true
  12. Supprimez les chaînes Dispose multiproduits et remplacez-les par using var ocr = new IronTesseract()
  13. Supprimez les fichiers de modèle JSON du projet et des artefacts de déploiement.
  14. Remplacez les boucles d'itération de cadre sur les fichiers TIFF par input.LoadImageFrames(path)
  15. Ajoutez result.SaveAsSearchablePdf(outputPath) partout où les sorties scannées doivent être archivées

Après la migration

  • Vérifiez que IronOcr.License.IsValidLicense renvoie true au démarrage de l'application
  • Confirmez que tous les résultats de reconnaissance renvoient des result.Text non vides pour les entrées précédemment fonctionnelles
  • Vérifiez result.Confidence sur des échantillons représentatifs — des valeurs au-dessus de 80 % indiquent une bonne qualité de reconnaissance
  • Testez l'exactitude du ciblage des régions en comparant les sorties CropRectangle avec les résultats de région Dynamsoft précédents
  • Validez la lecture des codes-barres en exécutant ocr.Configuration.ReadBarCodes = true sur des entrées qui nécessitaient précédemment le Dynamsoft Barcode Reader
  • Vérifiez que le traitement des TIFF multipages produit un OcrResult.Page par cadre
  • Vérifier que le PDF interrogeable est bien interrogeable dans une visionneuse PDF.
  • Exécutez des tests de traitement parallèle avec Parallel.ForEach et vérifiez qu'il n'y a pas de contention de thread
  • Tester toutes les cibles de déploiement (Linux, Docker, Azure) pour confirmer que le déploiement d'un seul package fonctionne sans fichiers de modèle JSON
  • Vérifiez qu'aucune variable d'environnement de clé de licence Dynamsoft ne subsiste dans la configuration de déploiement.

Principaux avantages de la migration vers IronOCR

Un seul package élimine la taxe de coordination multiproduits. Chaque capacité — OCR général, extraction MRZ, lecture de code-barres, entrée PDF native, sortie PDF consultable, prétraitement et plus de 125 langues — est proposée dans un seul package NuGet IronOcr. Les mises à niveau de version affectent une entrée de package dans un seul fichier .csproj. La rotation de clé de licence est une seule variable d'environnement. L'inventaire des artefacts de déploiement se réduit aux fichiers binaires de l'application, sans fichiers de modèles JSON ni répertoires de modèles de caractères.

Aucune dépendance de fichier de configuration. Le système de modèles Dynamsoft exige la présence et le chemin d'accès correct des fichiers JSON lors de l'exécution. IronOCR ne dépend d'aucun fichier d'exécution autre que le package NuGet lui-même. Les images Docker deviennent déterministes : ce qui réussit l'intégration continue est exactement ce qui est exécuté en production. Le guide de déploiement Docker montre un Dockerfile complet nécessitant seulement une ligne apt-get install pour Linux.

La sortie structurée réduit le code d'intégration. Dynamsoft renvoie des chaînes de texte brut LineResult. L'extraction de données structurées (positions des champs, limites des mots, niveau de confiance par jeton) nécessite un post-traitement que votre code possède et teste. La hiérarchie des résultats d'IronOCR expose les pages, les paragraphes, les lignes, les mots et les caractères sous forme de collections dactylographiées avec des coordonnées et des scores de confiance à chaque niveau. Les équipes qui migrent depuis Dynamsoft suppriment généralement 30 à 50 % de leur code de traitement des résultats, car IronOCR fournit la structure qu'elles construisaient manuellement. La page de résultats OCR documente le modèle de sortie complet.

La licence perpétuelle élimine l'incertitude budgétaire annuelle. Reconnaissance d'étiquettes Dynamsoft ne propose pas d'option de licence perpétuelle. Un cluster de traitement fonctionnant pendant cinq ans coûte plus de 2 995 $ par an pour la seule reconnaissance d'étiquettes, avant même d'ajouter les produits de normalisation des codes-barres ou des documents. La licence Lite de $999 de IronOCR est un achat unique qui couvre toutes les fonctionnalités indéfiniment. Pour les déploiements gouvernementaux, Enterprise et de production à long terme, la suppression des dépendances de renouvellement annuel d'un composant de traitement de documents essentiel réduit la complexité des achats et élimine le risque d'interruption d'abonnement en cours de projet. La page de licences IronOCR répertorie tous les niveaux et ce que chacun couvre.

Compatibilité multiplateforme sans configuration spécifique. IronOCR détermine le binaire d'exécution approprié pour Windows x64, Linux x64, macOS x64 et macOS ARM grâce au graphe d'identifiants d'exécution de NuGet. Pas de blocs conditionnels <PackageReference>, pas de code de détection de plate-forme, pas de configuration de chemin binaire natif. Le même code using IronOcr; compile et s'exécute sur Windows, Linux, AWS Lambda et Azure App Service sans modification.

La couverture linguistique s'adapte aux besoins de l'application. Reconnaissance d'étiquettes Dynamsoft est conçu pour les formats MRZ à caractères latins. Les systèmes d'écriture non latins (arabe, chinois, japonais, coréen, hébreu) ​​ne font pas partie de son champ d'application. IronOCR prend en charge plus de 125 langues installées sous forme de packages NuGet individuels : dotnet add package IronOcr.Languages.Arabic ajoute le support de l'arabe sans modification de code dans le pipeline de reconnaissance. L'index des langues répertorie chaque pack de langue disponible. Pour les applications traitant des documents d'identité internationaux, des étiquettes d'expédition multilingues ou des factures transfrontalières, cette étendue signifie qu'une seule bibliothèque couvre tous les types de documents rencontrés par une application en pleine croissance.

Veuillez noterDynamsoft et Tesseract sont des marques déposées de leurs propriétaires respectifs. Ce site n'est affilié, soutenu ou sponsorisé par Dynamsoft ou Google. Tous les noms de produits, logos et marques sont la propriété de leurs propriétaires respectifs. Les comparaisons sont à titre informatif uniquement et reflètent les informations publiquement disponibles au moment de l'écriture.

Questions Fréquemment Posées

Pourquoi devrais-je migrer du SDK OCR de Dynamsoft vers IronOCR ?

Parmi les motivations communes, citons l'élimination de la complexité de l'interopérabilité COM, le remplacement de la gestion des licences basée sur les fichiers, l'absence de facturation à la page, l'activation du déploiement Docker/conteneur et l'adoption d'un flux de travail NuGet-natif qui s'intègre à l'outillage .NET standard.

Quels sont les principaux changements de code lors de la migration du SDK OCR de Dynamsoft vers IronOCR ?

Remplacer les séquences d'initialisation de Dynamsoft OCR par l'instanciation d'IronTesseract, supprimer la gestion du cycle de vie de COM (modèles explicites Create/Load/Close) et mettre à jour les noms des propriétés des résultats. Le résultat est une réduction significative du nombre de lignes de code.

Comment installer IronOCR pour commencer la migration ?

Exécutez "Install-Package IronOcr" dans la console du Package Manager ou "dotnet add package IronOcr" dans le CLI. Les packs de langues sont des paquets distincts : 'dotnet add package IronOcr.Languages.French' pour le français, par exemple.

IronOCR atteint-il la précision d'OCR de Dynamsoft OCR SDK pour les documents commerciaux standard ?

IronOcr atteint un niveau de précision élevé pour les contenus commerciaux standard, notamment les factures, les contrats, les reçus et les formulaires dactylographiés. Les filtres de prétraitement d'image (désalignement, suppression du bruit, amélioration du contraste) améliorent encore la reconnaissance sur des données dégradées.

Comment IronOCR gère-t-il les données linguistiques que Dynamsoft OCR SDK installe séparément ?

Les données linguistiques de l'IronOcr sont distribuées sous forme de packages NuGet. 'dotnet add package IronOcr.Languages.German' installe la prise en charge de l'allemand. Il n'y a pas de placement manuel de fichiers ou de chemins d'accès aux répertoires.

La migration du SDK OCR de Dynamsoft vers IronOCR nécessite-t-elle des changements au niveau de l'infrastructure de déploiement ?

IronOcr nécessite moins de changements d'infrastructure que le SDK OCR de Dynamsoft. Il n'y a pas de chemin binaire pour le SDK, de placement de fichier de licence ou de configuration de serveur de licence. Le package NuGet contient le moteur OCR complet, et la clé de licence est une chaîne de caractères définie dans le code de l'application.

Comment configurer les licences IronOCR après la migration ?

Attribuer IronOcr.License.LicenseKey = "YOUR-KEY" dans le code de démarrage de l'application. Dans Docker ou Kubernetes, stockez la clé dans une variable d'environnement et lisez-la au démarrage. Utilisez License.IsValidLicense pour valider avant d'accepter le trafic.

IronOcr peut-il traiter les PDF de la même manière que Dynamsoft OCR ?

Oui, IronOCR lit aussi bien les PDF natifs que les PDF numérisés. Instanciez IronTesseract, appelez ocr.Read(input) où l'input est un chemin PDF ou OcrPdfInput, et itérez les pages OcrResult. Aucun pipeline de rendu PDF séparé n'est nécessaire.

Comment IronOcr gère-t-il le threading dans le cadre d'un traitement à haut volume ?

IronTesseract est sûr pour l'instanciation par thread. Créez une instance par thread dans un Parallel.ForEach ou un Task pool, exécutez l'OCR simultanément et disposez de chaque instance lorsque vous avez terminé. Aucun état global ou verrouillage n'est nécessaire.

Quels formats de sortie IronOCR prend-il en charge après l'extraction du texte ?

IronOCR renvoie des résultats structurés comprenant le texte, les coordonnées des mots, les scores de confiance et la structure des pages. Les options d'exportation comprennent le texte brut, le PDF interrogeable et les objets de résultats structurés pour le traitement en aval.

La tarification d'IronOCR est-elle plus prévisible que celle de Dynamsoft OCR SDK pour la mise à l'échelle des charges de travail ?

IronOCR utilise des licences perpétuelles forfaitaires sans frais par page ou par volume. Que vous traitiez 10 000 ou 10 millions de pages, le coût de la licence reste constant. Les options de licence en volume et en équipe sont disponibles sur la page de tarification d'IronOcr.

Qu'advient-il de mes tests existants après avoir migré du SDK OCR de Dynamsoft vers IronOCR ?

Les tests qui vérifient le contenu du texte extrait doivent continuer à passer après la migration. Les tests qui valident les modèles d'appel d'API ou le cycle de vie des objets COM devront être mis à jour pour refléter le modèle d'initialisation et de résultat plus simple d'IronOcr.

Kannaopat Udonpant
Ingénieur logiciel
Avant de devenir ingénieur logiciel, Kannapat a obtenu un doctorat en ressources environnementales à l'université d'Hokkaido au Japon. Pendant qu'il poursuivait son diplôme, Kannapat est également devenu membre du laboratoire de robotique de véhicules, qui fait partie du département de bioproduction. En 2022, il a utilisé ses compé...
Lire la suite

Équipe de soutien Iron

Nous sommes en ligne 24 heures sur 24, 5 jours sur 7.
Chat
Email
Appelez-moi