從Windows.Media.Ocr遷移至IronOCR
本指南提供 .NET 開發人員從 Windows.Media.Ocr 遷移到 IronOCR 的逐步遷移路徑。 它涵蓋了名稱空間移除、項目文件更改、遷移過程中最常出現的模式的程式碼遷移範例,以及驗證完成過渡的實際清單。
為什麼要從 Windows.Media.Ocr (UWP/WinRT OCR) 遷移
Windows.Media.Ocr 在其邊界內運作良好。 那些邊界很狹窄,項目通常會超出這些邊界。 團隊遷移的原因可預測地分為幾類。
Windows TFM 阻止所有非 Windows 目標。 項目文件必須聲明一個 net*-windows* 目標框架標識符,才能在編譯時解析 Windows.Media.Ocr 名稱空間。該聲明不是運行時標誌,而是構建約束,傳遞給引用您的每個項目。 共享的 OCR 服務庫、Web API、部署到 Linux 的後台工作程式——它們都繼承了這一約束。 移除它意味著要移除 Windows.Media.Ocr。
語言可用性在運行時由操作系統決定,而不是在編譯時由開發人員決定。 當主機機器上缺少所需的語言包時,OcrEngine.TryCreateFromLanguage 返回空值。開發人員無法從程式碼中安裝語言包,無法將其捆綁到應用程式二進位檔案中,也無法提供後備模式。 在自動化環境中——構建代理、CI 運行器、最小化的雲 VM、容器——很少安裝語言包。 因缺少語言包而導致的生產故障無法通過查看程式碼復現; 它們需要檢查目標機器的操作系統配置。
無預處理意味著對於次優輸入沒有恢復路徑。 API 接受 SoftwareBitmap 並生成文字。 從那兩個點改善影像品質完全是開發人員的責任,使用的是Windows Imaging Component APIs ,這些 API 本身也是僅限於 Windows 使用。 手機照片、不對齊的平板掃描和影印文件無聲地降低準確性,沒有內建機制來診斷或改進結果。
PDF 是企業工作流程中最常見的文件格式。 Windows.Media.Ocr 沒有 PDF 輸入路徑。 要處理掃描的 PDF 需要一個外部渲染器、按頁的光柵化,以及手動結果組合。 渲染器增加了一個依賴性、許可考量和一個獨立的故障表面——這正是 "免費內建的" 庫要避免的複雜性。
伺服器端部署在結構上不支持。 Windows.Media.Ocr 針對客戶端應用程式。 在 Windows Server 上運行它需要桌面體驗功能包,這會增加 VM 成本和基礎設施複雜性。 Docker 部署是不可能的。 基於 Linux 的 Azure Functions、AWS Lambda 和任何基於 Linux 的容器負載無法引用 API。
WinRT 非同步堆疊與標準 .NET 模式不相容。 在開始讀取單個字元之前,需要六個或更多鏈式的 await 呼叫——RecognizeAsync。 將該鏈整合到後台服務中、平行.ForEach 迴圈或標準 ASP.NET 控制器中都是笨拙的。 WinRT IAsyncOperation 機械坐在其下,而與 .NET 的 Task 模型的互動在非 UI 上下文中建立了微妙的邊界情況。
根本問題
Windows.Media.Ocr 中的語言可用性是一個運行時未知數,無法在部署時解決:
// Windows.Media.Ocr: language availability decided by OS admin, not the developer
// Returns null on any machine without the language pack installed
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("ja-JP"));
if (engine == null)
throw new InvalidOperationException(
"Japanese OCR unavailable — install the Japanese language pack in Windows Settings.");
//不是recovery path.不是bundled model.不是fallback.
// IronOCR: language availability is a NuGet package, not an OS configuration
// dotnet add package IronOcr.Languages.Japanese
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.Japanese;
var result = ocr.Read("invoice.jpg"); // Works on any OS, any machine
Console.WriteLine(result.Text);
##IronOCR與 Windows.Media.Ocr (UWP/WinRT OCR):功能比較
下表涵蓋了與遷移決策相關的完整功能面。
| 功能 | Windows.Media.Ocr | IronOCR |
|---|---|---|
| 平台:Windows 10/11 | 是 | 是 |
| 平台:Windows Server | 有限 (需要桌面體驗) | 是 |
| 平台:Linux | 不是 | 是 |
| 平台:macOS | 不是 | 是 |
| 平台:Docker 容器 | 不是 | 是 |
| 平台:Azure Functions (Linux) | 不是 | 是 |
| 平台:AWS Lambda | 不是 | 是 |
| 項目 TFM 要求 | 需要 net*-windows* | 無 (標準 TFM) |
| 安裝 | Windows 內建 (無 NuGet) | 單一 NuGet 包 (IronOcr) |
| 影像輸入 (JPG, PNG, BMP) | 是 (經由 WinRT pipeline) | 是 |
| PDF輸入 | 不是 | 是(本地) |
| 多頁 TIFF 輸入 | 不是 | 是 |
| 流和字節陣列輸入 | 否 (僅限 StorageFile) | 是 |
| 語言來源 | 系統安裝的語言包 | 125+ 捆綁的 NuGet 包 |
| 語言便攜性 | 否 (機器依賴) | 是 (和應用程式一起部署) |
| 多語言同時支援 | 不是 | 是 |
| 預處理:自動校正傾斜 | 不是 | 是 (input.Deskew()) |
| 預處理:去噪 | 不是 | 是 (input.DeNoise()) |
| 預處理:對比度 | 不是 | 是 (input.Contrast()) |
| 預處理:二維化 | 不是 | 是 (input.Binarize()) |
| 可搜尋的PDF輸出 | 不是 | 是 (result.SaveAsSearchablePdf()) |
| 每單字信心水準 | 不是 | 是 (word.Confidence) |
| 結構化輸出 (段,行,字) | 僅限行級 | 頁、段落、行、字、字元 |
| OCR 過程中的條碼讀取 | 不是 | 是 |
| 基於區域的OCR | 不是 | 是 (CropRectangle) |
| 同步 OCR 路徑 | 不是 | 是 |
| 執行緒安全的並行處理 | 有限 | 全部 |
| 商業支持 | 否 (Windows 平台團隊) | 是 |
| 許可模式 | 免費 (Windows 內建) | 永久 ($999 Lite, $1,499 Pro, $2,999 Enterprise) |
快速開始:從 Windows.Media.Ocr (UWP/WinRT OCR) 到IronOCR遷移
步驟1:替換NuGet包
Windows.Media.Ocr 沒有 NuGet 套件——它是 Windows Runtime 的一部分,通過 Windows TFM 解析。 移除它意味著要從項目文件中移除特定於 Windows 的名稱空間引用和可能的 Windows TFM。
從所有源文件中移除 Windows.Media.Ocr 名稱空間:
# Audit all files referencing Windows OCR namespaces
grep -r "Windows.Media.Ocr\|Windows.Graphics.Imaging\|Windows.Storage" --include="*.cs" .
安裝 IronOCR:
IronOCR NuGet 套件 針對 net8.0 和 net9.0,沒有特定於平台的 TFM。 在移除 Windows OCR 名稱空間後,將項目文件中的 <TargetFramework> 從 net8.0-windows10.0.19041.0 更新為 net8.0 (或適當的版本),前提是項目中沒有其他 WinRT API。
步驟2:更新命名空間
用單個IronOCR名稱空間替換三個 Windows OCR 名稱空間:
// Before (Windows.Media.Ocr)
using Windows.Media.Ocr;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Globalization;
// After (IronOCR)
using IronOcr;
步驟3:初始化許可證
在應用程式啟動時新增許可初始化呼叫——在 Startup.cs 或應用程式主機構建器中:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"免費試用密鑰可以從 IronOCR 許可頁面 獲得,並可移除試用水印以便於評估。
程式碼遷移範例
在後台服務中替換 WinRT 非同步鏈
Windows.Media.Ocr 在識別開始之前需要至少六個鏈式非同步操作。 在進程文件隊列的後台服務中,該鏈在迴圈中運行——SoftwareBitmap 處理、空值檢查和 WinRT IAsyncOperation 互操作在每次迭代中都會增加摩擦。
Windows.Media.Ocr 方法:
// Windows.Media.Ocr: full async chain required per document
// Requires net8.0-windows10.0.19041.0 TFM — cannot deploy to Linux workers
public async Task<List<string>> ProcessQueueAsync(IEnumerable<string> imagePaths)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language pack installed on this machine.");
var results = new List<string>();
foreach (var path in imagePaths)
{
// Each document: 4 async steps before RecognizeAsync
var file = await StorageFile.GetFileFromPathAsync(path);
using var stream = await file.OpenAsync(FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var bitmap = await decoder.GetSoftwareBitmapAsync();
var ocrResult = await engine.RecognizeAsync(bitmap);
results.Add(ocrResult.Text);
bitmap.Dispose();
}
return results;
}
IronOCR方法:
// IronOCR: one call per document, no WinRT, no SoftwareBitmap, no null checks
// Runs on Windows, Linux, macOS, Docker — same binary, no TFM change
public List<string> ProcessQueue(IEnumerable<string> imagePaths)
{
var results = new List<string>();
foreach (var path in imagePaths)
{
var result = new IronTesseract().Read(path);
results.Add(result.Text);
}
return results;
}
IronOCR 版本消除了 StorageFile 回合、SoftwareBitmap 生命週期和空值檢查防護。 對於非同步原生服務,IronOCR 提供非同步路徑,可以幹淨地整合進 Task 為基礎的管道中,無需 WinRT 互操作開銷。 IronTesseract 設置指南涵蓋了高吞吐量隊列場景中的實例生命週期建議。
消除軟體位圖轉換以進行記憶體中影像資料
已經具有記憶體中影像資料的應用程式——來自網路下載、資料庫 blob 或相機捕捉回調——必須將該資料轉換為 SoftwareBitmap 才能讓 Windows.Media.Ocr 進行處理。 該轉換路徑通過 BitmapDecoder,需要一個流,這意味著將字節陣列複製到 MemoryStream 中。IronOCR直接接受字節陣列和流。
Windows.Media.Ocr 方法:
// Windows.Media.Ocr: byte array must travel through WinRT stream → BitmapDecoder → SoftwareBitmap
public async Task<string> RecognizeFromBytesAsync(byte[] imageBytes)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language available.");
// Copy byte array into InMemoryRandomAccessStream (WinRT type)
using var ras = new Windows.Storage.Streams.InMemoryRandomAccessStream();
using var writer = new Windows.Storage.Streams.DataWriter(ras);
writer.WriteBytes(imageBytes);
await writer.StoreAsync();
ras.Seek(0);
var decoder = await BitmapDecoder.CreateAsync(ras);
var bitmap = await decoder.GetSoftwareBitmapAsync();
var result = await engine.RecognizeAsync(bitmap);
bitmap.Dispose();
return result.Text;
}
IronOCR方法:
// IronOCR: byte array loads directly into OcrInput — no conversion, no WinRT types
public string RecognizeFromBytes(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // direct byte array load
var result = new IronTesseract().Read(input);
return result.Text;
}
Windows.Media.Ocr 路徑需要 InMemoryRandomAccessStream——這是一個無法在 Windows 之外實例化的 WinRT 型別,還有 BitmapDecoder 和 SoftwareBitmap。 而IronOCR路徑使用 OcrInput.LoadImage(byte[]) 並在兩行中產生結果。 流輸入指南涵蓋基於 Stream 的載入模式,其簡單性與字節陣列輸入相同。
無需操作系統協調的多語言文件處理
必須在單次通過中識別英語、法語和德語文字的多語言發票管道在 Windows.Media.Ocr 中面臨架構死衚衕。 API 允許每個引擎實例僅使用一種語言。 處理混合語言文件要麼需要一個最擬合的單語言引擎,要麼進行三次識別並合併結果——這兩者都不會產生可靠的輸出。
Windows.Media.Ocr 方法:
// Windows.Media.Ocr: one language per engine, no simultaneous multi-language support
// Each language requires a separate language pack installed on the machine
public async Task<string> RecognizeMultiLanguageAsync(SoftwareBitmap bitmap)
{
// Must pick ONE language — no simultaneous recognition
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("en-US"));
if (engine == null)
throw new InvalidOperationException("English language pack not installed.");
// French and German text on the same document will be misrecognized
var result = await engine.RecognizeAsync(bitmap);
return result.Text;
}
IronOCR方法:
// IronOCR: simultaneous multi-language recognition in a single pass
// Language packs are NuGet packages — no OS coordination required
// dotnet add package IronOcr.Languages.French
// dotnet add package IronOcr.Languages.German
public string RecognizeMultiLanguage(string documentPath)
{
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German;
var result = ocr.Read(documentPath);
// Structured output: walk paragraphs with location data
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"[{paragraph.X},{paragraph.Y}] {paragraph.Text}");
}
}
return result.Text;
}
IronOCR 將語言模型結合在單次識別中,消除了猜測給定區域使用哪種語言的需求。 多語言 OCR 指南涵蓋語言包安裝和所有 125+ 支援語言的 OcrLanguage 枚舉值。 語言索引列表包括 CJK 脚本、阿拉伯語、希伯來語、天城文和西里爾文。
透過平行處理啟用伺服器端 OCR
Windows.Media.Ocr 無法在 Linux 伺服器上下文中運行,無法從跨平台主機上的標準 ASP.NET Core 控制器調用,並且在伺服器場景中從非 UI 執行緒調用時行為不確定。 將 OCR 端點從僅限 Windows 的桌面應用程式移動到可擴展的 Web API 團隊同時面臨所有三個約束。
Windows.Media.Ocr 方法:
// Windows.Media.Ocr: cannot run on Linux, Docker, or Azure Functions on Linux
// UWP/WinRT assumptions about thread context cause failures in ASP.NET pipelines
// The entire approach below is non-deployable outside Windows with Desktop Experience
[HttpPost("ocr")]
public async Task<IActionResult> RecognizeDocument(IFormFile file)
{
// WinRT requires STA thread context in some scenarios — not guaranteed in ASP.NET
// Cannot deploy this controller to a Linux App Service plan
using var stream = file.OpenReadStream();
// InMemoryRandomAccessStream is a WinRT type — does not exist on Linux
// var ras = new InMemoryRandomAccessStream(); // compile error on net8.0 TFM
return StatusCode(503, "Windows-only — cannot deploy cross-platform.");
}
IronOCR方法:
// IronOCR: ASP.NET Core controller running on Linux, Docker, or Windows — same code
[HttpPost("ocr")]
public async Task<IActionResult> RecognizeDocument(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file provided.");
using var memoryStream = new MemoryStream();
await file.CopyToAsync(memoryStream);
var imageBytes = memoryStream.ToArray();
using var input = new OcrInput();
input.LoadImage(imageBytes);
input.Deskew(); // straighten uploaded scans automatically
input.DeNoise(); // remove mobile camera noise
var result = new IronTesseract().Read(input);
return Ok(new
{
Text = result.Text,
Confidence = result.Confidence,
Pages = result.Pages.Count
});
}
此控制器部署到 Linux 應用服務、Docker 和 AWS Lambda,無需更改任何東西。 Docker 部署指南涵蓋了在 Linux 基礎映像上所需的單一 apt-get 依賴性。 Azure 部署指南和 AWS 指南展示了特定於雲的配置。
從掃描的歸檔生成可搜尋的 PDF
Windows.Media.Ocr 生成純文字字串。 除了 OcrResult.Text 和 OcrResult.Lines 中的行幾何之外,它沒有其他輸出格式。 將掃描的歸檔轉換為可搜尋的 PDF——這是文件管理系統和合規性工作流中的常見要求——需要第三方庫來構建 PDF 輸出層。IronOCR本身就能生成可搜尋的 PDF。
Windows.Media.Ocr 方法:
// Windows.Media.Ocr: plain text output only
// Searchable PDF requires external PDF library + manual text layer construction
public async Task<string> GetTextOnlyAsync(SoftwareBitmap bitmap)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language available.");
var result = await engine.RecognizeAsync(bitmap);
// result.Text is all you get
// Producing a searchable PDF requires an entirely separate library
return result.Text;
}
IronOCR方法:
// IronOCR: searchable PDF output is one method call on OcrResult
public void ProcessScannedArchive(IEnumerable<string> pdfPaths, string outputDirectory)
{
foreach (var sourcePdf in pdfPaths)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(sourcePdf); // native PDF input — no external renderer
input.Deskew(); // correct scan misalignment per page
input.DeNoise(); // remove scanner speckle
var result = ocr.Read(input);
var outputFileName = Path.Combine(
outputDirectory,
Path.GetFileNameWithoutExtension(sourcePdf) + "-searchable.pdf");
result.SaveAsSearchablePdf(outputFileName);
Console.WriteLine($"Processed: {sourcePdf} → {outputFileName} " +
$"({result.Pages.Count} pages, {result.Confidence:F1}% confidence)");
}
}
SaveAsSearchablePdf 呼叫在原始掃描影像上嵌入了一個文字層,保存了視覺保真度,同時使全文字搜尋和在任何 PDF 檢視器中的 Ctrl+F 成為可能。 可搜尋 PDF 如何實現指南涵蓋字體嵌入、文字層定位和多頁輸出選項。 PDF 輸入指南涵蓋密碼保護的 PDF 和大型歸檔的頁面範圍選擇。
使用字級座標提取結構化資料
Windows.Media.Ocr 曝露 OcrResult.Lines 與行級文字和邊界矩形。 字級幾何存在於具有 OcrLine.Words 和 OcrWord.BoundingRect 的 Pages 中,但沒有段落、信心分數,也沒有字元級資料。 對於表單字段提取或發票行項解析,行幾何是不足的——需要段落邊界和字信心分數來區分結構化字段與周圍的文字。
Windows.Media.Ocr 方法:
// Windows.Media.Ocr: line-level geometry, no paragraph grouping, no confidence scores
public async Task<List<string>> ExtractLineTextAsync(SoftwareBitmap bitmap)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language available.");
var result = await engine.RecognizeAsync(bitmap);
var lineTexts = new List<string>();
foreach (var line in result.Lines)
{
// Line text + word bounding rects — no paragraph grouping, no confidence
lineTexts.Add(line.Text);
}
return lineTexts;
}
IronOCR方法:
// IronOCR: full hierarchy — pages, paragraphs, lines, words, characters
// Each element carries coordinates and confidence for downstream validation
public void ExtractStructuredData(string documentPath)
{
var result = new IronTesseract().Read(documentPath);
Console.WriteLine($"Overall confidence: {result.Confidence:F1}%");
foreach (var page in result.Pages)
{
Console.WriteLine($"\n--- Page {page.PageNumber} ---");
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"Paragraph at ({paragraph.X},{paragraph.Y}): {paragraph.Text}");
// Filter words below confidence threshold for validation workflows
var lowConfidence = paragraph.Words
.Where(w => w.Confidence < 70)
.ToList();
if (lowConfidence.Any())
{
Console.WriteLine($" Low-confidence words: " +
string.Join(", ", lowConfidence.Select(w => $"'{w.Text}' ({w.Confidence:F0}%)")));
}
}
}
}
結構化結果模型——Characters——提供了表單字段提取、發票解析和文件布局分析所需的座標和信心資料。 讀取結果指南記錄了完整的 OcrResult 物件圖。 信心分數指南解釋了如何使用每字的信心值標記不確定的提取,以供人工審核。
Windows.Media.Ocr API 到IronOCR映射參考
| Windows.Media.Ocr | IronOCR |
|---|---|
OcrEngine.TryCreateFromLanguage(lang) | new IronTesseract() + ocr.Language = OcrLanguage.X |
OcrEngine.TryCreateFromUserProfileLanguages() | new IronTesseract() (預設為英語; 無空值返回) |
engine.RecognizeAsync(softwareBitmap) | ocr.Read("image.jpg") 或 ocr.Read(ocrInput) |
StorageFile.GetFileFromPathAsync(path) | ocr.Read("path") 直接 (不需要文件句柄) |
file.OpenAsync(FileAccessMode.Read) | 已消除——OcrInput 直接載入 |
BitmapDecoder.CreateAsync(stream) | input.LoadImage(stream) 透過 OcrInput |
decoder.GetSoftwareBitmapAsync() | 已消除——IronOCR 中沒有 SoftwareBitmap |
SoftwareBitmap (WinRT 型別) | 已消除——OcrInput 接受字節、流、文件路徑 |
InMemoryRandomAccessStream (WinRT 型別) | new MemoryStream() + input.LoadImage(stream) |
OcrResult.Text | OcrResult.Text |
OcrResult.Lines | OcrResult.Lines (也有 Pages, Paragraphs, Words, Characters) |
OcrLine.Text | OcrResult.Lines[i].Text |
OcrLine.Words | OcrResult.Words 或 page.Paragraphs[i].Words |
OcrWord.BoundingRect | word.X, word.Y, word.Width, word.Height |
| 無相應物件 | result.Confidence (總體) / word.Confidence (每字) |
| 無相應物件 | result.SaveAsSearchablePdf("output.pdf") |
| 無相應物件 | input.LoadPdf("document.pdf") |
| 無相應物件 | input.Deskew(), input.DeNoise(), input.Contrast() |
| 無相應物件 | ocr.Language = OcrLanguage.A + OcrLanguage.B (同時) |
| 無相應物件 | ocr.Configuration.ReadBarCodes = true |
| 無相應物件 | input.LoadImage(byteArray) |
常見的遷移問題与解決方案
問題 1:遷移後項目文件仍需 Windows TFM
Windows.Media.Ocr: 需要聲明 <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework> 優化解決 WinRT 型別。 不檢查同一項目中的其他 WinRT 相依性而移除 Windows.Media.Ocr 引用,可能會使 TFM 保持不變,從而阻止跨平台構建。
解決方案: 在移除 Windows OCR 名稱空間引用後,在更改 TFM 之前搜尋項目中是否存在其他 WinRT API使用:
# Find remaining WinRT API usage before removing the Windows TFM
grep -r "Windows\." --include="*.cs" .
grep -r "WinRT\|IAsyncOperation\|StorageFile\|SoftwareBitmap" --include="*.cs" .
如果沒有剩餘的 WinRT 參考,請更新項目文件:
<!-- Before -->
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<!-- After -->
<TargetFramework>net8.0</TargetFramework>
如果其他 WinRT 功能 (Windows 通知、Shell 整合、XAML) 仍在使用,請在介面後抽象 OCR 調用,並提供平台特定的實現,而不是刪除整個項目的 TFM。
問題 2:空引擎檢查沒有IronOCR等價物
Windows.Media.Ocr: 每次調用 TryCreateFromLanguage 和 TryCreateFromUserProfileLanguages 都可能返回空。 所有現有程式碼都包含空值檢查保護語句,在引擎為空值時擲或分支。
**解決方案:**IronOCR在初始化失敗時拋出結構化異常,而不是返回空值。 刪除空值檢查保護語句。 如果您需要將初始化錯誤呈現給調用者,請包裹在標準的 try/catch 中:
// Before: null-check pattern
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("OCR unavailable.");
// After: no null — IronTesseract throws if misconfigured
try
{
var result = new IronTesseract().Read("document.jpg");
}
catch (IronOcr.Exceptions.OcrException ex)
{
// structured exception with diagnostic message
logger.LogError("OCR failed: {Message}", ex.Message);
}
問題 3:現有方法簽名中的 SoftwareBitmap 參數
Windows.Media.Ocr: 實用方法、服務和回購類可能接受 SoftwareBitmap 作為參數型別。 當移除 Windows TFM 時,這些方法簽名無法編譯。
解決方案: 用 byte[] 或 Stream 替換 SoftwareBitmap 參數。IronOCR的 OcrInput 直接接受兩者。 先前構建 SoftwareBitmap 的呼叫位置可以傳遞其底層資料:
// Before: SoftwareBitmap parameter — cannot compile cross-platform
public async Task<string> RecognizeAsync(SoftwareBitmap bitmap) { ... }
// After: byte array parameter — compiles on all platforms
public string Recognize(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes);
return new IronTesseract().Read(input).Text;
}
問題 4:非同步僅限定調用者無法直接使用同步 IronOCR
Windows.Media.Ocr: 每次識別呼叫都是 async。 由於調用者在整個程式碼庫中使用 await 並返回 Task<string>。 在 async 方法內部切換到IronOCR的同步 Read 方法有效,但可能會在 async 在架構下阻塞。
**解決方案:**IronOCR為需要的調用者提供非同步路徑。 在現有的非同步方法中使用 Task.Run 進行 CPU 負載包裝,或使用原生的非同步 API:
// Option A: wrap synchronous call in Task.Run for async callers
public async Task<string> RecognizeAsync(string imagePath)
{
return await Task.Run(() => new IronTesseract().Read(imagePath).Text);
}
// Option B:IronOCRasync path
// See: https://ironsoftware.com/csharp/ocr/how-to/async/
非同步 OCR 指南記錄了內建的非同步 API,適用於需要火即忘或進度報告模式的上下文。
問題 5:Windows 語言標籤格式無對應
Windows.Media.Ocr: 使用 BCP-47 字串標籤傳遞到 Windows.Globalization.Language("fr-FR") 來指定語言。 這些字串標籤在IronOCR中沒有直接對應。
解決方案: 將 BCP-47 語言標籤映射到 OcrLanguage 枚舉。 對於常見語言,映射是直接的:
// Before: BCP-47 string tags
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("fr-FR"));
// After: OcrLanguage enum
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
// Also: OcrLanguage.German, OcrLanguage.Japanese, OcrLanguage.Arabic, etc.
IronOCR 語言目錄中提供了完整的映射。 對於未包含在主枚舉中的語言,自定義語言包支持 涵蓋直接載入 .traineddata 文件。
問題 6:FileAccessMode.Read 無替代方案
Windows.Media.Ocr: file.OpenAsync(FileAccessMode.Read) 是 WinRT 特定的文件開啟模式。 FileAccessMode 枚舉在標準 .NET 中不存在。
解決方案: 替換為標準 System.IO.File.ReadAllBytes 或 FileStream。 OcrInput 接受兩者:
// Before: WinRT file access
using var stream = await file.OpenAsync(FileAccessMode.Read);
// After: standard .NET
var imageBytes = File.ReadAllBytes(imagePath);
using var input = new OcrInput();
input.LoadImage(imageBytes);
Windows.Media.Ocr (UWP/WinRT OCR) 遷移檢查清單
遷移前
在更改之前稽核程式碼庫:
# Find all Windows OCR namespace usages
grep -rn "using Windows.Media.Ocr" --include="*.cs" .
grep -rn "using Windows.Graphics.Imaging" --include="*.cs" .
grep -rn "using Windows.Storage" --include="*.cs" .
grep -rn "using Windows.Globalization" --include="*.cs" .
# Find WinRT type usages
grep -rn "OcrEngine\|SoftwareBitmap\|BitmapDecoder\|StorageFile" --include="*.cs" .
grep -rn "TryCreateFromLanguage\|TryCreateFromUserProfileLanguages\|RecognizeAsync" --include="*.cs" .
grep -rn "InMemoryRandomAccessStream\|DataWriter\|FileAccessMode" --include="*.cs" .
# Find project files with Windows TFM
grep -rn "net.*-windows" --include="*.csproj" .
# Count files requiring changes
grep -rl "Windows.Media.Ocr\|Windows.Graphics.Imaging\|SoftwareBitmap" --include="*.cs" . | wc -l
記錄受影響的文件數量、使用的語言標籤 ("en-US", "fr-FR",等等),以及公眾方法簽名中是否存在任何 WinRT 型別物件(這些需要 API 表面更改以及內部重寫)。
程式碼遷移
- 安裝
IronOcrNuGet 套件:dotnet add package IronOcr - 在
Program.cs或Startup.cs中新增許可初始化呼叫:IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; - 從所有源文件中移除
using Windows.Media.Ocr; - 從所有源文件中移除
using Windows.Graphics.Imaging; - 從所有源文件中移除
using Windows.Storage; - 從所有源文件中移除
using Windows.Globalization; - 向所有執行 OCR 的文件中新增
using IronOcr; - 用
new IronTesseract()替換每個OcrEngine.TryCreateFromLanguage(new Language("xx-XX"))呼叫並設置ocr.Language = OcrLanguage.X - 用
new IronTesseract()替換每個OcrEngine.TryCreateFromUserProfileLanguages()呼叫 - 刪除引擎建立結果上的所有空值檢查保護語句
- 用
byte[]或Stream替換方法簽名中的SoftwareBitmap參數 - 用
OcrInput.LoadImage(bytes)或OcrInput.LoadImage(stream)替換BitmapDecoder和SoftwareBitmap構造鏈 - 用
ocr.Read(path)或ocr.Read(input)替換engine.RecognizeAsync(bitmap) - 用
MemoryStream替換InMemoryRandomAccessStream和DataWriter使用 - 用
OcrLanguage規範值替換 Windows 的 BCP-47 語言標籤字串; 安裝所需的語言 NuGet 套件 - 更新
<TargetFramework>,從.csproj文件中移除-windowsX.Y.Z後綴,無其他 WinRT API 留存
遷移後
- 確認項目在沒有 Windows TFM 後綴的情況下針對
net8.0(或您目標版本) 編譯 - 確認項目在 Linux 環境或 Docker 容器中使用
mcr.microsoft.com/dotnet/aspnet:8.0編譯和運行 - 驗證 OCR 輸出文字是否符合測試套件中每種文件型別的預期結果
- 檢查所有先前支援的語言是否使用IronOCR語言 NuGet 套件產生正確的輸出
- 驗證多語言檔案是否在單次識別中產生正確的結果
- 確保在沒有安裝 Windows 語言包的機器上引擎初始化不會出現
NullReferenceException或InvalidOperationException - 驗證
result.Confidence值是否在乾淨和低質量輸入文件的預期範圍內 - 如果應用程式產生文件,驗證
SaveAsSearchablePdf輸出在 PDF 檢視器中正確打開並支持文字搜尋 - 運行任何現有的平行或多執行緒處理通道,並在負載下確認執行緒安全性
- 部署到目標環境 (Docker, Azure 應用服務, AWS, Linux 伺服器) 並執行至少一次完整的端到端 OCR 操作
遷移至IronOCR的主要好處
跨平台部署成為配置決定,而不是程式碼重寫。 遷移之後,OCR 組件在 Windows、Linux、macOS、Docker 和每個主要雲供應商上運行相同。 將 OCR 工作量從 Windows VM 移動到 Linux 容器以降低託管成本是一個部署操作。 Linux 部署指南 和 Docker 部署指南 涵蓋了在 Linux 基本映像上所需的一行依賴性新增。
語言支持隨著應用程式二進位文件移動。 語言包安裝為 NuGet 套件並與IronOCR包版本鎖定。 您應用程式可識別的語言集在項目文件中定義,並且在每台機器上都是相同的——開發者工作站、CI 運行器、預發伺服器和生產主機。 無需操作系統管理員協調,無需求例政策例外,無運行時空值檢查。
OCR 準確性在沒有外部工具的情況下得到提升。 在識別引擎看到影像之前,預處理流水線——Scale——在IronOCR內運行。 由於掃描不對齊或噪音而在 Windows.Media.Ocr 中產生劣質結果的文件,在不新增外部影像處理依賴項的情況下得到改進。 影像品質修正指南 和 過濾嚮導 幫助識別每種文件型別的正確過濾器組合。
PDF 工作流整合到單一庫。 將 Windows.Media.Ocr 和 PDF 輸入連接所需的外部 PDF 渲染器已不再需要。 掃描 PDF 歸檔可以通過與影像相同的 IronTesseract.Read 呼叫進行處理。 可搜尋的 PDF 輸出是結果物件上的一種方法。 兩庫架構消失了,隨之而來的是其版本管理、許可開銷和部署面。
結構化輸出啟用文件智慧管道。 OcrResult 階層——Pages, Paragraphs, Lines, Words, Characters——具有每個元素的座標和信心分數,提供了進行發票字段提取、表單解析和文件分類所需的資料。 Windows.Media.Ocr 的行級輸出對於這些工作流程不夠充分。 使用 IronOCR,信心篩選的詞語提取、段落邊界檢測和基於座標的字段映射是第一級功能,不需要其他庫。
永久許可取代了無界基礎設施依賴。 保持 Windows 語言包在異構大型機上安裝的成本、Windows Server 桌面體驗許可,以及僅供 Windows 使用的 CI 基礎設施是實際的但分散的代價——它會出現在 IT 工單和基礎設施預算中,而不是 OCR 預算中的行項。 一個 $999IronOCRLite 許可消除了單一開發者項目的常見管理成本。 $1,499 的專業許可覆蓋了十個開發人員。 兩者都是一次性購買,包含一年更新。
