跳至頁尾內容
影片

如何使用OCR工具從圖像中提取阿拉伯文字

本指南為.NET開發者介紹從GdPicture.NET OCR到IronOCR的完整遷移過程。 它涵蓋了套件替換、命名空間變更,以及每一個主要OCR工作流程的實用前/後程式碼模式,特別著重於消除GdPicture資源管理模型中定義的整數圖像ID生命週期。 不需要閱讀比較文章。

為什麼要從GdPicture.NET遷移

GdPicture.NET是一個文件影像平臺,專為需要掃描儀整合、DICOM支持、PDF編輯、註釋和OCR的團隊設計,由單一供應商提供。 當OCR是唯一需求時,平台的定價和API架構會產生隨著時間累積的摩擦。

基礎OCR流程的插件費用。從掃描的PDF中提取文字並生成可搜尋輸出需要三個獨立的授權組件:核心SDK大約$4,000,OCR插件大約$2,000,和PDF插件大約$2,000。這是一個$8,000的入門成本,加上每年20%的維護費用。 需要僅提供OCR的團隊承擔了整個文件影像平臺的定價結構。 IronOCR涵蓋同樣的工作流程——圖像OCR、PDF OCR、預處理、可搜尋的PDF輸出——從單一套件,成本從$999到$2,999永久使用,無需考慮每項特徵的授權決策。 檢視IronOCR授權頁面了解完整的級別分解。

整數圖像ID生命週期。通過GdPicture載入的每個圖像都返回一個int。 您將該整數傳遞給OCR操作,然後在完成後調用ReleaseGdPictureImage。 此模式早於IDisposable。 當正確遵循時,它可以正常工作; 但若遺漏則導致記憶體洩漏。 在每天處理數百個文件的生產服務中,一個錯誤分支沒有釋放調用產生的記憶體增長問題真的難以診斷。 IronOCR的using語句消除了整個清理負擔。

版本特定的命名空間。GdPicture將主要版本號嵌入其命名空間中:using GdPicture14。 升級到下一個主要版本需要更新每個引用GdPicture類的源文件中的using指令。 在大量應用程式中,OCR分佈在數十個服務中,這是一個多小時的查找和替換任務,並且不提供功能改進。 IronOCR的命名空間已在所有主要版本中IronOcr

外部資源資料夾要求。GdPicture OCR要求一個.traineddata語言文件目錄。該路徑在開發機上有效,然後在不具備目錄結構的Linux伺服器、Docker容器和Azure App Service部署中失效。IronOCR將英語支持內建在NuGet包中; 其他語言作為NuGet包安裝,隨著構建輸出一起攜帶。

三個組件初始化。GdPicture中的PDF OCR工作流程需要實例化GdPicturePDF——三個獨立的組件具有個別的銷毀要求——加上許可管理員註冊和資源資料夾分配。 IronOCR在啟動時需要一行,在調用時需要一個類。

無原生執行緒安全。GdPicture OCR實例不是執行緒安全的。 並行文件處理需要小心的實例管理和同步以避免狀態損壞。 IronOCR設計用於並發使用:每執行緒建立一個IronTesseract,或在負載下共享單個實例——無論哪種模式都不需要額外的同步程式碼。

根本問題

GdPicture為每個圖像分配記憶體作為運行時管理的整數句柄。 在TIFF處理迴圈中的每次RenderPageToGdPictureImage調用建立一個新的分配,必須手動釋放:

// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);

var frameIds = new List<int>();
try
{
    for (int i = 1; i <= pdf.GetPageCount(); i++)
    {
        pdf.SelectPage(i);
        int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
        if (frameId != 0) frameIds.Add(frameId);
        // ... OCR call here ...
    }
}
finally
{
    foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);

var frameIds = new List<int>();
try
{
    for (int i = 1; i <= pdf.GetPageCount(); i++)
    {
        pdf.SelectPage(i);
        int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
        if (frameId != 0) frameIds.Add(frameId);
        // ... OCR call here ...
    }
}
finally
{
    foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
Imports System.Collections.Generic

' GdPicture: every frame = new integer ID = manual release required
Using pdf As New GdPicturePDF()
    pdf.LoadFromFile("multi-page.tiff", False)

    Dim frameIds As New List(Of Integer)()
    Try
        For i As Integer = 1 To pdf.GetPageCount()
            pdf.SelectPage(i)
            Dim frameId As Integer = pdf.RenderPageToGdPictureImage(200, False) ' new allocation
            If frameId <> 0 Then frameIds.Add(frameId)
            ' ... OCR call here ...
        Next
    Finally
        For Each id In frameIds
            _imaging.ReleaseGdPictureImage(id) ' manual per-frame release
        Next
    End Try
End Using
$vbLabelText   $csharpLabel

IronOCR完全消除了該生命週期。 OcrInput 處理框架枚舉和清理:

// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
Imports IronOcr

Dim input As New OcrInput()
Using input
    input.LoadImageFrames("multi-page.tiff")
    Dim result = New IronTesseract().Read(input)
End Using
$vbLabelText   $csharpLabel

IronOCRvs GdPicture.NET:功能比較

下表映射了兩個程式庫之間的功能涵蓋範圍,針對以OCR為重點的工作流程。

功能 GdPicture.NET IronOCR
安裝 多個NuGet包 dotnet add package IronOcr
許可激活 LicenseManager.RegisterKEY() IronOcr.License.LicenseKey = "..."
主要升級的命名空間 需要查找並替換 (GdPicture14 → 下一個) 不變 (IronOcr)
組件初始化 GdPictureImaging + GdPictureOCR + GdPicturePDF new IronTesseract()
資源記憶體模型 整數ID的手動跟蹤和釋放 IDisposable / using 語句
記憶體洩漏風險 高(缺少ReleaseGdPictureImage 無(編譯器強制通過using
外部資源資料夾 需要(_ocr.ResourceFolder = path 不需要—打包在包中
圖像OCR
PDF OCR 是(需要PDF插件) 內建,無需額外授權
多頁TIFF 手動框架迴圈+逐框ID清理 input.LoadImageFrames()
流輸入 通過GdPictureImaging流重載 input.LoadImage(stream)
可搜尋的PDF輸出 pdf.OcrPage() + pdf.SaveToFile() result.SaveAsSearchablePdf()
去偏斜預處理 需要文件影像插件 input.Deskew()—內建
噪點去除 需要文件影像插件 input.DeNoise()—內建
語言 資料夾中的Tesseract基礎訓練資料文件 125+ 透過NuGet包
多語言OCR OcrLanguage.French + OcrLanguage.German
執行緒安全 手動實例管理 設計上的執行緒安全
異步OCR 未內建 ReadAsync()
條碼識別 單獨條碼插件 ocr.Configuration.ReadBarCodes = true
結構化輸出 基於索引的區塊/行/單字存取 型化.Characters
信心評估 GetOCRResultConfidence(resultId) result.Confidence
跨平台 Windows, Linux, macOS Windows、Linux、macOS、Docker、AWS、Azure
起步成本(從PDF中進行OCR) ~$8,000(核心+OCR+PDF插件) $999–$2,999
價格模型 基於插件的永久 + 20%/年維護 固定永久,年度更新可選
商業支持

快速入門:GdPicture.NET到IronOCR的遷移

步驟1:替換NuGet包

移除GdPicture套件:

dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
SHELL

NuGet包頁面安裝IronOCR:

dotnet add package IronOcr

對於英語以外的語言,安裝相應的語言包:

dotnet add package IronOcr.Languages.French, IronOcr.Languages.German

步驟2:更新命名空間

將GdPicture命名空間替換為IronOCR命名空間:

// Before (GdPicture)
using GdPicture14;

// After (IronOCR)
using IronOcr;
// Before (GdPicture)
using GdPicture14;

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

步驟3:初始化許可證

將此行放在Startup.cs中,在任何OCR呼叫之前:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

完全移除GdPicture授權註冊塊:

// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
$vbLabelText   $csharpLabel

免費試用密鑰可於IronOCR產品頁面獲取,以便在購買前進行評估。

程式碼遷移範例

多頁面TIFF框架處理

在GdPicture中處理多頁面TIFF文件需要通過PDF/影像API選擇每個框架,將其渲染到新圖像ID,運行OCR,並釋放ID。 取決於DPI,未在finally塊中釋放的單個框架洩露10–50 MB。

GdPicture.NET方法:

using GdPicture14;

public class GdPictureTiffProcessor
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public string ExtractTextFromTiff(string tiffPath)
    {
        var text = new StringBuilder();

        // Load TIFF through the imaging component
        int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);

        if (tiffId == 0)
            throw new Exception($"TIFF load failed: {_imaging.GetStat()}");

        // Outer try: release the original TIFF handle
        try
        {
            int frameCount = _imaging.GetPageCount(tiffId);

            for (int i = 1; i <= frameCount; i++)
            {
                // Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i);

                // Clone frame to a new image ID for OCR
                int frameId = _imaging.CloneImage(tiffId);

                if (frameId == 0) continue;

                // Inner try: release each cloned frame ID
                try
                {
                    _ocr.SetImage(frameId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (!string.IsNullOrEmpty(resultId))
                    {
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
                    }
                }
                finally
                {
                    // Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId);
                }
            }
        }
        finally
        {
            // Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId);
        }

        return text.ToString();
    }
}
using GdPicture14;

public class GdPictureTiffProcessor
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public string ExtractTextFromTiff(string tiffPath)
    {
        var text = new StringBuilder();

        // Load TIFF through the imaging component
        int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);

        if (tiffId == 0)
            throw new Exception($"TIFF load failed: {_imaging.GetStat()}");

        // Outer try: release the original TIFF handle
        try
        {
            int frameCount = _imaging.GetPageCount(tiffId);

            for (int i = 1; i <= frameCount; i++)
            {
                // Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i);

                // Clone frame to a new image ID for OCR
                int frameId = _imaging.CloneImage(tiffId);

                if (frameId == 0) continue;

                // Inner try: release each cloned frame ID
                try
                {
                    _ocr.SetImage(frameId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (!string.IsNullOrEmpty(resultId))
                    {
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
                    }
                }
                finally
                {
                    // Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId);
                }
            }
        }
        finally
        {
            // Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId);
        }

        return text.ToString();
    }
}
Imports GdPicture14
Imports System.Text

Public Class GdPictureTiffProcessor
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR

    Public Function ExtractTextFromTiff(tiffPath As String) As String
        Dim text As New StringBuilder()

        ' Load TIFF through the imaging component
        Dim tiffId As Integer = _imaging.CreateGdPictureImageFromFile(tiffPath)

        If tiffId = 0 Then
            Throw New Exception($"TIFF load failed: {_imaging.GetStat()}")
        End If

        ' Outer try: release the original TIFF handle
        Try
            Dim frameCount As Integer = _imaging.GetPageCount(tiffId)

            For i As Integer = 1 To frameCount
                ' Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i)

                ' Clone frame to a new image ID for OCR
                Dim frameId As Integer = _imaging.CloneImage(tiffId)

                If frameId = 0 Then Continue For

                ' Inner try: release each cloned frame ID
                Try
                    _ocr.SetImage(frameId)
                    _ocr.Language = "eng"

                    Dim resultId As String = _ocr.RunOCR()

                    If Not String.IsNullOrEmpty(resultId) Then
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}")
                    End If
                Finally
                    ' Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId)
                End Try
            Next
        Finally
            ' Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId)
        End Try

        Return text.ToString()
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public class IronOcrTiffProcessor
{
    public string ExtractTextFromTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // all frames loaded, all cleanup automatic

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

        // Per-frame text is available on result.Pages
        foreach (var page in result.Pages)
            Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");

        return result.Text;
    }
}
using IronOcr;

public class IronOcrTiffProcessor
{
    public string ExtractTextFromTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // all frames loaded, all cleanup automatic

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

        // Per-frame text is available on result.Pages
        foreach (var page in result.Pages)
            Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");

        return result.Text;
    }
}
Imports IronOcr

Public Class IronOcrTiffProcessor
    Public Function ExtractTextFromTiff(tiffPath As String) As String
        Using input As New OcrInput()
            input.LoadImageFrames(tiffPath) ' all frames loaded, all cleanup automatic

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

            ' Per-frame text is available on result.Pages
            For Each page In result.Pages
                Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}")
            Next

            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

using區塊處理範圍終了時所用的全部框架相關的記憶體。 無需維護try/finally區塊。 TIFF和GIF輸入指南詳細說明了框架選擇和多格式處理。

基於流的輸入替換插件初始化

伺服器應用程式經常從HTTP上傳、消息隊列或資料庫blob中以流而非文件路徑接收文件。 GdPicture要求通過GdPictureImaging載入流,而它本身需要組件初始化序列和資源資料夾配置,這些在每次操作前都需要。

GdPicture.NET方法:

using GdPicture14;

public class GdPictureStreamOcr : IDisposable
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public GdPictureStreamOcr()
    {
        // Plugin initialization required before stream loading is possible
        var lm = new LicenseManager();
        lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

        _imaging = new GdPictureImaging();
        _ocr = new GdPictureOCR();
        _ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
    }

    public string ExtractTextFromStream(Stream documentStream)
    {
        // Load stream into imaging component to get an image ID
        int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);

        if (imageId == 0)
            throw new Exception($"Stream load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            return _ocr.GetOCRResultText(resultId);
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }
    }

    public void Dispose()
    {
        _ocr?.Dispose();
        _imaging?.Dispose();
    }
}
using GdPicture14;

public class GdPictureStreamOcr : IDisposable
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public GdPictureStreamOcr()
    {
        // Plugin initialization required before stream loading is possible
        var lm = new LicenseManager();
        lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

        _imaging = new GdPictureImaging();
        _ocr = new GdPictureOCR();
        _ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
    }

    public string ExtractTextFromStream(Stream documentStream)
    {
        // Load stream into imaging component to get an image ID
        int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);

        if (imageId == 0)
            throw new Exception($"Stream load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            return _ocr.GetOCRResultText(resultId);
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }
    }

    public void Dispose()
    {
        _ocr?.Dispose();
        _imaging?.Dispose();
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public class IronOcrStreamOcr
{
    public string ExtractTextFromStream(Stream documentStream)
    {
        using var input = new OcrInput();
        input.LoadImage(documentStream);  // stream accepted directly — no imaging component

        return new IronTesseract().Read(input).Text;
    }
}
using IronOcr;

public class IronOcrStreamOcr
{
    public string ExtractTextFromStream(Stream documentStream)
    {
        using var input = new OcrInput();
        input.LoadImage(documentStream);  // stream accepted directly — no imaging component

        return new IronTesseract().Read(input).Text;
    }
}
Imports IronOcr

Public Class IronOcrStreamOcr
    Public Function ExtractTextFromStream(documentStream As Stream) As String
        Using input As New OcrInput()
            input.LoadImage(documentStream) ' stream accepted directly — no imaging component

            Return New IronTesseract().Read(input).Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

GdPicture方法要求構建三個物件並配置檔案系統路徑後,第一個流才能被消耗。 IronOCR直接在OcrInput上接收流,無需事先設置。流輸入指南涵盖了管道結構中無需臨時文件寫入的字節陣列、FileStream模式。

異步OCR替代狀態程式碼輪詢

GdPicture OCR是同步的。 在ASP.NET Core端點或背景服務中處理文件的應用程式必須在Task.Run以避免阻塞請求執行緒,然後在執行緒邊界內管理圖像ID生命周期。 IronOCR通過ReadAsync提供一流的異步支持。

GdPicture.NET方法:

using GdPicture14;
using System.Threading.Tasks;

public class GdPictureAsyncWrapper
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // Must acquire lock: GdPictureOCR is not thread-safe
        await _lock.WaitAsync();

        try
        {
            return await Task.Run(() =>
            {
                int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);

                if (imageId == 0)
                    throw new Exception($"Load failed: {_imaging.GetStat()}");

                try
                {
                    _ocr.SetImage(imageId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (string.IsNullOrEmpty(resultId))
                        throw new Exception($"OCR failed: {_ocr.GetStat()}");

                    return _ocr.GetOCRResultText(resultId);
                }
                finally
                {
                    _imaging.ReleaseGdPictureImage(imageId);
                }
            });
        }
        finally
        {
            _lock.Release();
        }
    }
}
using GdPicture14;
using System.Threading.Tasks;

public class GdPictureAsyncWrapper
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // Must acquire lock: GdPictureOCR is not thread-safe
        await _lock.WaitAsync();

        try
        {
            return await Task.Run(() =>
            {
                int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);

                if (imageId == 0)
                    throw new Exception($"Load failed: {_imaging.GetStat()}");

                try
                {
                    _ocr.SetImage(imageId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (string.IsNullOrEmpty(resultId))
                        throw new Exception($"OCR failed: {_ocr.GetStat()}");

                    return _ocr.GetOCRResultText(resultId);
                }
                finally
                {
                    _imaging.ReleaseGdPictureImage(imageId);
                }
            });
        }
        finally
        {
            _lock.Release();
        }
    }
}
Imports GdPicture14
Imports System.Threading.Tasks

Public Class GdPictureAsyncWrapper
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR
    Private ReadOnly _lock As New SemaphoreSlim(1, 1)

    Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
        ' Must acquire lock: GdPictureOCR is not thread-safe
        Await _lock.WaitAsync()

        Try
            Return Await Task.Run(Function()
                                      Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(imagePath)

                                      If imageId = 0 Then
                                          Throw New Exception($"Load failed: {_imaging.GetStat()}")
                                      End If

                                      Try
                                          _ocr.SetImage(imageId)
                                          _ocr.Language = "eng"

                                          Dim resultId As String = _ocr.RunOCR()

                                          If String.IsNullOrEmpty(resultId) Then
                                              Throw New Exception($"OCR failed: {_ocr.GetStat()}")
                                          End If

                                          Return _ocr.GetOCRResultText(resultId)
                                      Finally
                                          _imaging.ReleaseGdPictureImage(imageId)
                                      End Try
                                  End Function)
        Finally
            _lock.Release()
        End Try
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public class IronOcrAsyncService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // ReadAsync is natively async — no Task.Run wrapper, no lock required
        var result = await _ocr.ReadAsync(imagePath);
        return result.Text;
    }

    public async Task<string> ExtractFromStreamAsync(Stream stream)
    {
        using var input = new OcrInput();
        input.LoadImage(stream);

        var result = await _ocr.ReadAsync(input);
        return result.Text;
    }
}
using IronOcr;

public class IronOcrAsyncService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // ReadAsync is natively async — no Task.Run wrapper, no lock required
        var result = await _ocr.ReadAsync(imagePath);
        return result.Text;
    }

    public async Task<string> ExtractFromStreamAsync(Stream stream)
    {
        using var input = new OcrInput();
        input.LoadImage(stream);

        var result = await _ocr.ReadAsync(input);
        return result.Text;
    }
}
Imports IronOcr
Imports System.IO
Imports System.Threading.Tasks

Public Class IronOcrAsyncService
    Private ReadOnly _ocr As New IronTesseract()

    Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
        ' ReadAsync is natively async — no Task.Run wrapper, no lock required
        Dim result = Await _ocr.ReadAsync(imagePath)
        Return result.Text
    End Function

    Public Async Function ExtractFromStreamAsync(stream As Stream) As Task(Of String)
        Using input As New OcrInput()
            input.LoadImage(stream)

            Dim result = Await _ocr.ReadAsync(input)
            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

GdPicture方法需要Task.Run將同步阻塞工作移出調用執行緒,再加上lambda中的完整圖像ID生命週期。 IronOCR的ReadAsync真正無阻塞且執行緒安全。 異步OCR指南涵蓋了ASP.NET Core中介軟體和託管背景服務整合。

執行緒安全的並行批處理

盡可能快地處理掃描文件的資料夾需要並行執行。 GdPicture要求每個執行緒一個GdPictureOCR實例,共享單個實例會引起非確定性故障。 每個執行緒實例還需要自身的GdPictureImaging組件和資源資料夾配置,這使得沒有工廠模式的執行緒池方法難以實現。

GdPicture.NET方法:

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

public class GdPictureParallelBatch
{
    private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";

    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Each thread must have its own component instances
        Parallel.ForEach(imagePaths, imagePath =>
        {
            // Create per-thread instances — shared instances cause failures
            using var threadImaging = new GdPictureImaging();
            using var threadOcr = new GdPictureOCR();
            threadOcr.ResourceFolder = _resourceFolder;

            // Re-register license per thread (may be required depending on SDK version)
            var lm = new LicenseManager();
            lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

            int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);

            if (imageId == 0)
            {
                results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
                return;
            }

            try
            {
                threadOcr.SetImage(imageId);
                threadOcr.Language = "eng";

                string resultId = threadOcr.RunOCR();
                results[imagePath] = string.IsNullOrEmpty(resultId)
                    ? $"ERROR: {threadOcr.GetStat()}"
                    : threadOcr.GetOCRResultText(resultId);
            }
            finally
            {
                threadImaging.ReleaseGdPictureImage(imageId);
            }
        });

        return results;
    }
}
using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class GdPictureParallelBatch
{
    private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";

    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Each thread must have its own component instances
        Parallel.ForEach(imagePaths, imagePath =>
        {
            // Create per-thread instances — shared instances cause failures
            using var threadImaging = new GdPictureImaging();
            using var threadOcr = new GdPictureOCR();
            threadOcr.ResourceFolder = _resourceFolder;

            // Re-register license per thread (may be required depending on SDK version)
            var lm = new LicenseManager();
            lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

            int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);

            if (imageId == 0)
            {
                results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
                return;
            }

            try
            {
                threadOcr.SetImage(imageId);
                threadOcr.Language = "eng";

                string resultId = threadOcr.RunOCR();
                results[imagePath] = string.IsNullOrEmpty(resultId)
                    ? $"ERROR: {threadOcr.GetStat()}"
                    : threadOcr.GetOCRResultText(resultId);
            }
            finally
            {
                threadImaging.ReleaseGdPictureImage(imageId);
            }
        });

        return results;
    }
}
Imports GdPicture14
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class GdPictureParallelBatch
    Private ReadOnly _resourceFolder As String = "C:\GdPicture\Resources\OCR"

    Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' Each thread must have its own component instances
        Parallel.ForEach(imagePaths, Sub(imagePath)
            ' Create per-thread instances — shared instances cause failures
            Using threadImaging As New GdPictureImaging()
                Using threadOcr As New GdPictureOCR()
                    threadOcr.ResourceFolder = _resourceFolder

                    ' Re-register license per thread (may be required depending on SDK version)
                    Dim lm As New LicenseManager()
                    lm.RegisterKEY("GDPICTURE-LICENSE-KEY")

                    Dim imageId As Integer = threadImaging.CreateGdPictureImageFromFile(imagePath)

                    If imageId = 0 Then
                        results(imagePath) = $"ERROR: {threadImaging.GetStat()}"
                        Return
                    End If

                    Try
                        threadOcr.SetImage(imageId)
                        threadOcr.Language = "eng"

                        Dim resultId As String = threadOcr.RunOCR()
                        results(imagePath) = If(String.IsNullOrEmpty(resultId), $"ERROR: {threadOcr.GetStat()}", threadOcr.GetOCRResultText(resultId))
                    Finally
                        threadImaging.ReleaseGdPictureImage(imageId)
                    End Try
                End Using
            End Using
        End Sub)

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR方法:

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

public class IronOcrParallelBatch
{
    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance handles all threads
        var ocr = new IronTesseract();

        Parallel.ForEach(imagePaths, imagePath =>
        {
            try
            {
                results[imagePath] = ocr.Read(imagePath).Text;
            }
            catch (Exception ex)
            {
                results[imagePath] = $"ERROR: {ex.Message}";
            }
        });

        return results;
    }
}
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class IronOcrParallelBatch
{
    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance handles all threads
        var ocr = new IronTesseract();

        Parallel.ForEach(imagePaths, imagePath =>
        {
            try
            {
                results[imagePath] = ocr.Read(imagePath).Text;
            }
            catch (Exception ex)
            {
                results[imagePath] = $"ERROR: {ex.Message}";
            }
        });

        return results;
    }
}
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class IronOcrParallelBatch
    Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' IronTesseract is thread-safe — one instance handles all threads
        Dim ocr As New IronTesseract()

        Parallel.ForEach(imagePaths, Sub(imagePath)
            Try
                results(imagePath) = ocr.Read(imagePath).Text
            Catch ex As Exception
                results(imagePath) = $"ERROR: {ex.Message}"
            End Try
        End Sub)

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

GdPicture並行實現為每個執行緒建立三個物件,並且需要執行緒許可註冊。 IronOCR無需同步開銷即可從單IronTesseract實例處理並行讀取。 多執行緒範例展示了吞吐量基準測試和Parallel.ForEach模式,以满足高容量文件加工工作負荷。

字節陣列輸入及結構段落提取

從資料庫或物件儲存檢索文件的應用程式通常使用字節陣列而非文件路徑。 GdPicture要求將字節陣列轉換為流,並通過GdPictureImaging載入。 從結果中提取結構化段落級別資料需要導航區塊/行索引層次結構。

GdPicture.NET方法:

using GdPicture14;

public class GdPictureByteArrayOcr
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        var paragraphs = new List<string>();

        // Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        using var ms = new MemoryStream(imageBytes);
        int imageId = _imaging.CreateGdPictureImageFromStream(ms);

        if (imageId == 0)
            throw new Exception($"Byte array load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            // Paragraph-level data requires iterating block structure
            int blockCount = _ocr.GetOCRResultBlockCount(resultId);

            for (int b = 0; b < blockCount; b++)
            {
                var blockText = new StringBuilder();
                int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);

                for (int l = 0; l < lineCount; l++)
                {
                    int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);

                    for (int w = 0; w < wordCount; w++)
                    {
                        blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
                        blockText.Append(" ");
                    }
                }

                string text = blockText.ToString().Trim();
                if (!string.IsNullOrEmpty(text))
                    paragraphs.Add(text);
            }
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }

        return paragraphs;
    }
}
using GdPicture14;

public class GdPictureByteArrayOcr
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        var paragraphs = new List<string>();

        // Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        using var ms = new MemoryStream(imageBytes);
        int imageId = _imaging.CreateGdPictureImageFromStream(ms);

        if (imageId == 0)
            throw new Exception($"Byte array load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            // Paragraph-level data requires iterating block structure
            int blockCount = _ocr.GetOCRResultBlockCount(resultId);

            for (int b = 0; b < blockCount; b++)
            {
                var blockText = new StringBuilder();
                int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);

                for (int l = 0; l < lineCount; l++)
                {
                    int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);

                    for (int w = 0; w < wordCount; w++)
                    {
                        blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
                        blockText.Append(" ");
                    }
                }

                string text = blockText.ToString().Trim();
                if (!string.IsNullOrEmpty(text))
                    paragraphs.Add(text);
            }
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }

        return paragraphs;
    }
}
Imports GdPicture14
Imports System.IO
Imports System.Text

Public Class GdPictureByteArrayOcr
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR

    Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
        Dim paragraphs As New List(Of String)()

        ' Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        Using ms As New MemoryStream(imageBytes)
            Dim imageId As Integer = _imaging.CreateGdPictureImageFromStream(ms)

            If imageId = 0 Then
                Throw New Exception($"Byte array load failed: {_imaging.GetStat()}")
            End If

            Try
                _ocr.SetImage(imageId)
                _ocr.Language = "eng"

                Dim resultId As String = _ocr.RunOCR()

                If String.IsNullOrEmpty(resultId) Then
                    Throw New Exception($"OCR failed: {_ocr.GetStat()}")
                End If

                ' Paragraph-level data requires iterating block structure
                Dim blockCount As Integer = _ocr.GetOCRResultBlockCount(resultId)

                For b As Integer = 0 To blockCount - 1
                    Dim blockText As New StringBuilder()
                    Dim lineCount As Integer = _ocr.GetOCRResultBlockLineCount(resultId, b)

                    For l As Integer = 0 To lineCount - 1
                        Dim wordCount As Integer = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l)

                        For w As Integer = 0 To wordCount - 1
                            blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w))
                            blockText.Append(" "c)
                        Next
                    Next

                    Dim text As String = blockText.ToString().Trim()
                    If Not String.IsNullOrEmpty(text) Then
                        paragraphs.Add(text)
                    End If
                Next
            Finally
                _imaging.ReleaseGdPictureImage(imageId)
            End Try
        End Using

        Return paragraphs
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public class IronOcrByteArrayOcr
{
    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        using var input = new OcrInput();
        input.LoadImage(imageBytes);  // byte array accepted directly

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

        // Paragraphs are a first-class typed collection
        return result.Paragraphs
            .Select(p => p.Text)
            .Where(t => !string.IsNullOrWhiteSpace(t))
            .ToList();
    }
}
using IronOcr;

public class IronOcrByteArrayOcr
{
    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        using var input = new OcrInput();
        input.LoadImage(imageBytes);  // byte array accepted directly

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

        // Paragraphs are a first-class typed collection
        return result.Paragraphs
            .Select(p => p.Text)
            .Where(t => !string.IsNullOrWhiteSpace(t))
            .ToList();
    }
}
Imports IronOcr

Public Class IronOcrByteArrayOcr
    Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
        Using input As New OcrInput()
            input.LoadImage(imageBytes) ' byte array accepted directly

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

            ' Paragraphs are a first-class typed collection
            Return result.Paragraphs _
                .Select(Function(p) p.Text) _
                .Where(Function(t) Not String.IsNullOrWhiteSpace(t)) _
                .ToList()
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR直接接受MemoryStream。 結果將.Paragraphs暴露為一個型化的LINQ可查詢集合——不需要區塊/行/單詞三重迴圈。 讀取結果指南涵蓋了坐標存取、信心過濾,及适用于發票和表單處理工作流的結構化輸出模式。 對於掃描特定文件區域,請參見基於區域的OCR

GdPicture.NET API到IronOCR映射參考

GdPicture.NET IronOCR 等效
using GdPicture14; using IronOcr;
LicenseManager.RegisterKEY("key") IronOcr.License.LicenseKey = "key"
new GdPictureImaging() 不需要——內部於OcrInput
new GdPictureOCR() new IronTesseract()
new GdPicturePDF() 不需要——由OcrInput.LoadPdf()處理
_ocr.ResourceFolder = path 不需要——資源捆綁在NuGet中
imaging.CreateGdPictureImageFromFile(path) input.LoadImage(path)
imaging.CreateGdPictureImageFromStream(stream) input.LoadImage(stream)
imaging.CreateGdPictureImageFromBytes(bytes) input.LoadImage(bytes)
imaging.CloneImage(tiffId) 每幀 input.LoadImageFrames(tiffPath)
imaging.ReleaseGdPictureImage(imageId) using var input = new OcrInput()——自動
ocr.SetImage(imageId) 不需要——OcrInput保存圖像
ocr.Language = "eng" ocr.Language = OcrLanguage.English
ocr.RunOCR()resultId字串 ocr.Read(input) → 型化OcrResult
ocr.GetOCRResultText(resultId) result.Text
ocr.GetOCRResultConfidence(resultId) result.Confidence
ocr.GetOCRResultBlockCount(resultId) result.Pages[i].Paragraphs.Count
ocr.GetOCRResultBlockLineWordText(resultId, b, l, w) result.Words[i].Text
imaging.GetStat() / ocr.GetStat() 標準.NET異常
每次調用後檢查GdPictureStatus.OK 不需要——例外會傳播
pdf.OcrPage("eng", resourcePath, "", 200) result.SaveAsSearchablePdf(outputPath)
pdf.RenderPageToGdPictureImage(200, false) 不需要——IronOCR內部渲染
pdf.SelectPage(i) 不需要——預設情況下處理所有頁面
pdf.GetPageCount() result.Pages.Count
Task.Run(() => ocr.RunOCR()) + SemaphoreSlim await ocr.ReadAsync(input)

常見的遷移問題与解決方案

問題1:重構後程式碼中遺留的圖像ID變數

GdPicture.NET:現有程式碼在方法頂部聲明int imageId,通過try/finally追蹤,並將其傳遞到多個GdPicture調用。 更換GdPicture調用後,這些變數及其ReleaseGdPictureImage調用成為孤立死程式碼。

解決方案:刪除整個圖像ID模式。 用finally及釋放調用。 使用Grep查找ReleaseGdPictureImage來找到必須刪除的每個清理調用:

grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
SHELL
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
    _ocr.SetImage(imageId);
    string resultId = _ocr.RunOCR();
    return _ocr.GetOCRResultText(resultId);
}
finally
{
    _imaging.ReleaseGdPictureImage(imageId);
}

// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
    _ocr.SetImage(imageId);
    string resultId = _ocr.RunOCR();
    return _ocr.GetOCRResultText(resultId);
}
finally
{
    _imaging.ReleaseGdPictureImage(imageId);
}

// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
' Remove all of this
Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(path)
Try
    _ocr.SetImage(imageId)
    Dim resultId As String = _ocr.RunOCR()
    Return _ocr.GetOCRResultText(resultId)
Finally
    _imaging.ReleaseGdPictureImage(imageId)
End Try

' Replace with
Using input As New OcrInput()
    input.LoadImage(path)
    Return New IronTesseract().Read(input).Text
End Using
$vbLabelText   $csharpLabel

問題2:部署環境中找不到ResourceFolder路徑

GdPicture.NET:_ocr.ResourceFolder設置的路徑在開發機上解析,但在生產中失效。 常見於OCR靜默失敗返回空結果,或不命名缺少文件的通用GdPictureStatus錯誤。

解決方案:完全移除ResourceFolder分配。 英語支持嵌入在IronOCR NuGet包中。 附加語言作為NuGet包安裝。 不需要配置或部署文件系統路徑:

# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
SHELL

問題3:GdPictureStatus錯誤處理被例外取代

GdPicture.NET:每個操作返回或設置必須立即檢查的GdPictureStatus枚舉值。 程式碼中充斥著if (status != GdPictureStatus.OK)保駕護航。 一些狀態程式碼是通用的(例如InvalidParameter),需要查看文件以確定根本原因。

解決方案:IronOCR拋出型化的.NET例外。 用try/catch塊替換狀態檢查。 標準FileNotFoundException覆盖了輸入失敗; IronOcr.Exceptions.OcrException覆蓋OCR特定錯誤。 參見IronTesseract設置指南,爲推薦的錯誤處理模式提供參考:

try
{
    var result = new IronTesseract().Read(imagePath);
    return result.Text;
}
catch (FileNotFoundException ex)
{
    _logger.LogError("Input file missing: {Path}", ex.FileName);
    throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
    _logger.LogError("OCR processing failed: {Message}", ex.Message);
    throw;
}
try
{
    var result = new IronTesseract().Read(imagePath);
    return result.Text;
}
catch (FileNotFoundException ex)
{
    _logger.LogError("Input file missing: {Path}", ex.FileName);
    throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
    _logger.LogError("OCR processing failed: {Message}", ex.Message);
    throw;
}
Imports IronOcr
Imports System.IO

Try
    Dim result = New IronTesseract().Read(imagePath)
    Return result.Text
Catch ex As FileNotFoundException
    _logger.LogError("Input file missing: {Path}", ex.FileName)
    Throw
Catch ex As IronOcr.Exceptions.OcrException
    _logger.LogError("OCR processing failed: {Message}", ex.Message)
    Throw
End Try
$vbLabelText   $csharpLabel

問題4:多文件中的GdPicture14命名空間

GdPicture.NET:命名空間中的版本號意味著在數十個文件中存在項目範圍內的using GdPicture14;指令。 在遷移後,這些必須全部替換為using IronOcr;

解決方案:在所有.cs文件上進行全域查找並替換,然後驗證沒有留下GdPicture引用:

# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .

# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .

# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
SHELL

問題5:TIFF框架計數邏輯

GdPicture.NET:迭代TIFF框架的程式碼經常根據文件載入方式將調用混合於GdPicturePDF.GetPageCount()。 幀索引基於1。

解決方案:input.LoadImageFrames(path)自動處理所有框架。 如果現有程式碼僅處理特定框架,請使用input.LoadImageFrames(path, frameNumbers)並使用以零為基準的索引陣列。 通過result.Pages存取每幀結果,它也是零索引的。 在TIFF輸入指南中明確記錄了索引行為。

問題6:預處理需要文件影像插件

GdPicture.NET:去偏斜和去斑操作屬於GdPictureDocumentImaging插件,這需要另外購買許可。 跳過插件的團隊常常在處理帶偏移或噪聲的掃描文件時遇到OCR準確性問題。

解決方案:IronOCR預處理方法是基礎包的一部分。 在DeNoise()圖像質量校正指南涵蓋了所有可用的濾鏡,包括DeepCleanBackgroundNoise(),專為嚴重退化的掃描而設計。

using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew();        // no separate plugin license
input.DeNoise();
input.Contrast();

var result = new IronTesseract().Read(input);
using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew();        // no separate plugin license
input.DeNoise();
input.Contrast();

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

Using input As New OcrInput()
    input.LoadImage("scanned-document.tiff")
    input.Deskew() ' no separate plugin license
    input.DeNoise()
    input.Contrast()

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

GdPicture.NET遷移檢查表

遷移前

在進行更改之前,審核程式碼庫以查找每個GdPicture依賴項:

# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .

# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .

# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .

# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .

# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .

# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .

# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .

# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .

# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .

# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .

# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .

# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .

# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
SHELL

在修改程式碼之前,記錄以下內容:

  • 哪些文件包含GdPicturePDF引用
  • 存在多少不同的圖像ID建立/釋放對
  • 是否使用文件影像插件(去偏斜、去斑)
  • 資源資料夾中的語言traineddata文件
  • 哪些部署腳本或Docker文件引用了資源資料夾路徑

程式碼遷移

  1. 從項目文件中移除所有GdPicture NuGet包
  2. 通過NuGet安裝IronOcr
  3. 為資源資料夾中以前的每一種語言安裝IronOcr.Languages.*
  4. Startup.cs
  5. 移除LicenseManager.RegisterKEY()調用和許可管理物件
  6. 移除所有GdPictureImaging字段聲明和構造器初始化
  7. 移除所有ResourceFolder賦值
  8. 移除用於OCR工作流的所有GdPicturePDF字段聲明
  9. using var input = new OcrInput();替換每個int imageId = _imaging.CreateGdPictureImage*(...)區塊 input.Load*(...)`
  10. 替換每個_ocr.SetImage(imageId); _ocr.Language = "...";string resultId = _ocr.RunOCR(); with var result = new IronTesseract().Read(input);
  11. result.Text
  12. 移除所有_imaging.ReleaseGdPictureImage(imageId)調用
  13. 用try/catch塊替換GdPictureStatus檢查
  14. input.LoadImageFrames(path)替換TIFF幀迴圈
  15. pdf.SaveToFile(...) 16.從部署腳本和Docker鏡像中移除此資源資料夾路徑。
  16. 在所有受影響的文件中將using IronOcr;

遷移後

完成所有程式碼更改後,請在部署到生產環境之前再次驗證以下內容:

  • 單個圖像OCR返回預期的文字,且沒有來自已刪除組件的NullReferenceException
  • 多頁面TIFF處理覆蓋所有框架,並生成逐頁文字透過result.Pages
  • PDF OCR在50+文件的批量中處理所有頁面且不會導致記憶體增長
  • 流輸入接受FileStream而無需中介文件寫入
  • 異步OCR與ASP.NET Core請求處理程式整合且不會阻塞執行緒池
  • Parallel.ForEach的並行批處理在所有執行緒上產生精確結果
  • 所有語言包(法語、德語等)透過NuGet包正確激活
  • 預處理濾鏡(去偏、去噪)提升了掃描文件上的准確性
  • 可搜索PDF輸出可被PDF查看器和文字搜索應用程式讀取
  • 遷移後沒有GdPicture命名空間引用保留於任何.cs文件
  • 在穩定負載下顯示記憶體配置文件使用穩定(沒有圖像分配洩漏)
  • 部署在Linux和Docker目標上成功且無文件系統路徑錯誤

遷移至IronOCR的主要好處

編譯器強制記憶體安全。 GdPicture要求開發人員手動維護的圖像ID生命週期完全消失。 OcrInput 實現了using塊確保在每個範圍結尾時進行清理——包括異常路徑。 無需維護finally塊,沒有因為漏掉釋放調用而引發的生產記憶體事故。

單包適用於每個OCR場景。 圖像OCR,PDF OCR,多頁面TIFF處理,可搜索PDF生成,預處理濾鏡,條碼識別,和125+語言包均可從IronOcr NuGet包及其語言夥伴中獲得。 沒有需要額外或三重購買的功能門檻,通常的工作流成為可行。 參看IronOCR功能概述了解完整的能力清單。

本地異步和執行緒安全。 Task.Run包裝。 IronTesseract 在各個執行緒間可安全使用,無需同步。 以前需要每執行緒元件初始化和同步通行證的文件處理服務因Parallel.ForEach而縮減為單共享實例。 异步OCR指南涵蓋了ASP.NET Core和托管服務模式。

零部屬配置。IronOCR不需要文件系統路徑,不需要外部語言文件,不需要本機二進制放置,也不需要部署腳本。 NuGet 還原步驟提供了應用程式所需的一切。 Docker映像、Azure App Service部署和Linux伺服器的工作方式完全與開發機相同。 Docker 部署指南Azure 部署指南演示可投入生產的配置。

版本穩定命名空間。 using IronOcr 在主要版本發布中未發生變化。 NuGet 版本號根據標準包管理模型進行版本化。 未來的主要升級不需要在程式碼庫中對命名空間進行全域找尋和替換。

可預測的永久授權。IronOCR定價為$999(Lite),$1,499(Plus),$2,999(Professional),和$5,999(Unlimited)——一次性永久購買,包括一年的更新,並可選擇年度續訂。 所有功能均在每一層可用。 第一年之後沒有每項功能插件、每頁成本和維護義務。 以前吸收了GdPicture插件授權費$8,000+的團隊在第一個許可周期內即可追回這個差距。 完整的定價細節可在IronOCR授權頁面中查看。

請注意GdPicture.NET 和 Tesseract 是其各自擁有者的註冊商標。 此網站與Google、Nutrient或ORPALIS無關,未獲得支持或贊助。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供資訊用途,並反映撰寫時獲得的公開資訊。

常見問題

為什麼我要從GdPicture.NET OCR遷移到IronOCR?

常見的驅動因素包括消除COM互操作複雜性、更換基於文件的許可證管理、避免按頁收費、啟用Docker/容器部署,以及採取與標準.NET工具整合的NuGet本地工作流。

從GdPicture.NET OCR遷移到IronOCR時,主要的程式碼更改有哪些?

用IronTesseract實例化替換GdPicture.NET初始化序列,移除COM生命週期管理(明確的Create/Load/Close模式),並更新結果屬性名稱。結果是顯著減少樣板程式碼行數。

如何安裝IronOCR以開始遷移?

在套件管理器控制台中運行 'Install-Package IronOcr' 或在CLI中運行 'dotnet add package IronOcr'。語言包是單獨的包:例如 'dotnet add package IronOcr.Languages.French' 安裝法語支持。

IronOCR是否能達到與GdPicture.NET OCR在標準商業文件上相同的OCR準確性?

IronOCR在包括發票、合同、收據和鍵入的表單等標準業務內容上達到高準確性。圖像預處理過濾器(糾偏、噪音去除、對比度增強)進一步提高了變質輸入的識別。

IronOCR如何處理GdPicture.NET OCR單獨安裝的語言資料?

IronOCR中的語言資料分發為NuGet包。'dotnet add package IronOcr.Languages.German' 安裝德語支持。不涉及手動文件放置或目錄路徑。

從GdPicture.NET OCR遷移到IronOCR是否需要對部署基礎設施進行更改?

IronOCR比GdPicture.NET OCR需要更少的基礎設施更改。沒有SDK二進位路徑、授權檔案放置或授權伺服器配置。NuGet套件包含完整的OCR引擎,授權金鑰是設在應用程式程式碼中的字串。

遷移後如何配置IronOCR許可證?

在應用啟動程式碼中分配IronOcr.License.LicenseKey = "YOUR-KEY"。在Docker或Kubernetes中,將金鑰儲存為環境變數並在啟動時讀取。在接受流量之前,使用License.IsValidLicense驗證。

IronOCR能否以與GdPicture.NET相同的方式處理PDF?

是的。IronOCR能讀取本地和掃描的PDF。實例化IronTesseract,調用ocr.Read(input),其中input是PDF路徑或OcrPdfInput,並迭代OcrResult頁面。不需要單獨的PDF渲染管道。

IronOCR如何處理大批量處理中的多執行緒?

IronTesseract可以安全地在每個執行緒中實例化。在Parallel.ForEach或Task池中為每個執行緒建立一個實例,並發併運行OCR,當完成時處置每個實例。不需要全域狀態或鎖定。

IronOCR在文字提取後支持哪些輸出格式?

IronOCR返回結構化結果,包括文字、單詞坐標、信心分數和頁面結構。導出選項包括純文字、可搜索PDF以及下游處理的結構化結果物件。

IronOCR的定價是否比GdPicture.NET OCR更具可預測性以應對擴展工作負載?

IronOCR使用固定費率的永久性許可證,沒有按頁或按量收費。無論您處理10000頁還是1000萬頁,許可證費用保持不變。團隊和批量許可證選項可在IronOCR定價頁面上找到。

從GdPicture.NET OCR遷移到IronOCR後,我現有的測試會怎麼樣?

遷移後,斷言提取的文字內容的測試應繼續通過。需要更新的測試是驗證API調用模式或COM物件生命週期,這需要反映IronOCR較簡單的初始化和結果模型。

Kannaopat Udonpant
軟體工程師
在成為軟體工程師之前,Kannapat在日本北海道大學完成了環境資源博士學位。在攻讀學位期間,Kannapat還成為車輛機器人實驗室的一員,該實驗室隸屬於生產工程系。在2022年,他憑藉C#技能加入了Iron Software的工程團隊,專注於IronPDF。Kannapat珍視他的工作,因為他能直接向撰寫大部分IronPDF程式碼的開發者學習。除了同儕學習,Kannapat還喜歡在Iron Software工作的社交方面。不寫程式碼或文件時,Kannapat通常在他的PS5上玩遊戲或重看The Last of Us。

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話