如何使用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
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
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
從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
步驟3:初始化許可證
將此行放在Startup.cs中,在任何OCR呼叫之前:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
完全移除GdPicture授權註冊塊:
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
免費試用密鑰可於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
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
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
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
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
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
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
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
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
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
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" .
// 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
問題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
問題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
問題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" .
問題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
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
在修改程式碼之前,記錄以下內容:
- 哪些文件包含
GdPicturePDF引用 - 存在多少不同的圖像ID建立/釋放對
- 是否使用文件影像插件(去偏斜、去斑)
- 資源資料夾中的語言
traineddata文件 - 哪些部署腳本或Docker文件引用了資源資料夾路徑
程式碼遷移
- 從項目文件中移除所有GdPicture NuGet包
- 通過NuGet安裝
IronOcr - 為資源資料夾中以前的每一種語言安裝
IronOcr.Languages.*包 - 將
Startup.cs - 移除
LicenseManager.RegisterKEY()調用和許可管理物件 - 移除所有
GdPictureImaging字段聲明和構造器初始化 - 移除所有
ResourceFolder賦值 - 移除用於OCR工作流的所有
GdPicturePDF字段聲明 - 用
using var input = new OcrInput();替換每個int imageId = _imaging.CreateGdPictureImage*(...)區塊 input.Load*(...)` - 替換每個
_ocr.SetImage(imageId);_ocr.Language = "...";string resultId = _ocr.RunOCR();withvar result = new IronTesseract().Read(input); - 將
result.Text - 移除所有
_imaging.ReleaseGdPictureImage(imageId)調用 - 用try/catch塊替換
GdPictureStatus檢查 - 用
input.LoadImageFrames(path)替換TIFF幀迴圈 - 用
pdf.SaveToFile(...)16.從部署腳本和Docker鏡像中移除此資源資料夾路徑。 - 在所有受影響的文件中將
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 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較簡單的初始化和結果模型。

