Azure OCR 与 IronOCR:哪种光学字符识别解决方案最适合 .NET 项目?
Windows.Media.Ocr 随每个 Windows 10 和 Windows 11 安装包免费提供,这使其颇具吸引力,但当你尝试将同一应用程序部署到Linux服务器、Docker 容器或AWS Lambda函数时,问题就出现了——此时 API 根本不存在。平台锁定并非此库的个例; 这是决定性限制因素。 选择 Windows.Media.Ocr 之后的所有架构决策都受到以下要求的影响:主机操作系统必须是 Windows 10 或 Windows 11 桌面版或消费级服务器。 不支持 Linux、macOS、Docker、Linux 上的 Azure Functions 和 AWS Lambda。 对于开发内部 Windows 工具且完全没有计划跨越该边界的开发人员来说,0 美元的价格很难让人拒绝。 对于其他人来说,隐藏的成本是,当部署要求发生变化时,需要将 OCR 完全重写成一个不同的系统。
了解 Windows.Media.Ocr
Windows.Media.Ocr 是 Windows Runtime (WinRT) API 表面的一部分,该表面在 Windows 8.1 中引入,并在 Windows 10 和 11 中进行了改进。它在OcrEngine 类中公开了一个 Windows.Media.Ocr 命名空间,该命名空间接受一个 SoftwareBitmap—本身是来自 Windows.Graphics.Imaging 的 WinRT 类型—并返回一个 OcrResult,其中包含识别的文本和行几何。
该 API 是围绕 WinRT 的 async/await 协议构建的。 每个操作都通过由 WinRT IAsyncOperation 机制支持的 async Task 调用流动:加载一个 StorageFile,打开一个流,创建一个 BitmapDecoder,获取一个 SoftwareBitmap,然后才调用 RecognizeAsync。 从 .NET 6 开始,使用 WinRT API 需要一个特定于 Windows 的目标框架标识符 (TFM),例如 net8.0-windows10.0.19041.0。 没有该 TFM 的项目文件根本无法编译引用 Windows.Media.Ocr 的代码—这些类型在程序集图中不存在。
主要架构特征:
-仅限 Windows 10/11 — 在所有配置下,未启用桌面体验的Windows 服务器均无法使用 WinRT API,而Linux和MacOS上则完全没有 WinRT API。
- WinRT 异步模型—所有识别都通过由
IAsyncOperation支持的异步调用进行; 不存在同步路径 - 来自操作系统的语言包—
OcrEngine.TryCreateFromLanguage和TryCreateFromUserProfileLanguages解决了用户或 IT 管理员在特定机器上安装的 Windows 语言包中的可用语言;没有捆绑或便携的语言模型 - 仅限图像输入 — API 直接接受
SoftwareBitmap; API 的任何层级都不存在 PDF 输入路径。 -没有预处理流程——直接将原始位图传递给识别器; 旋转校正、降噪、对比度增强和分辨率缩放是开发人员使用单独的 Windows 图像处理 API 负责实现的功能。 -没有可搜索的 PDF 输出— 识别的文本以纯字符串数据的形式返回,并带有线条几何形状; 不提供导出为 PDF 的功能 - 需要特定于 Windows 的 TFM—项目文件必须以一个
net*-windows*TFM 为目标,这样防止相同的项目跨平台编译
WinRT异步堆栈
using Windows.Media.Ocr 进行的每个基本 OCR 操作都需要先遍历 WinRT API 接口的多个层,然后才能开始识别:
// Windows.Media.Ocr: 6+ async steps before receiving any text
// Requires net8.0-windows10.0.19041.0 TFM — will not compile cross-platform
public async Task<string> ExtractTextAsync(string imagePath)
{
// Step 1: WinRT file system access
var file = await StorageFile.GetFileFromPathAsync(imagePath);
// Step 2: Open WinRT stream
using var stream = await file.OpenAsync(FileAccessMode.Read);
// Step 3: Create bitmap decoder
var decoder = await BitmapDecoder.CreateAsync(stream);
// Step 4: Decode to SoftwareBitmap
var bitmap = await decoder.GetSoftwareBitmapAsync();
// Step 5: Check language availability — null if not installed on this machine
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("en-US"));
if (engine == null)
throw new Exception("OCR engine not available for this language");
// Step 6: Recognize
var result = await engine.RecognizeAsync(bitmap);
return result.Text;
}
// Windows.Media.Ocr: 6+ async steps before receiving any text
// Requires net8.0-windows10.0.19041.0 TFM — will not compile cross-platform
public async Task<string> ExtractTextAsync(string imagePath)
{
// Step 1: WinRT file system access
var file = await StorageFile.GetFileFromPathAsync(imagePath);
// Step 2: Open WinRT stream
using var stream = await file.OpenAsync(FileAccessMode.Read);
// Step 3: Create bitmap decoder
var decoder = await BitmapDecoder.CreateAsync(stream);
// Step 4: Decode to SoftwareBitmap
var bitmap = await decoder.GetSoftwareBitmapAsync();
// Step 5: Check language availability — null if not installed on this machine
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("en-US"));
if (engine == null)
throw new Exception("OCR engine not available for this language");
// Step 6: Recognize
var result = await engine.RecognizeAsync(bitmap);
return result.Text;
}
Imports System.Threading.Tasks
Imports Windows.Media.Ocr
Imports Windows.Storage
Imports Windows.Graphics.Imaging
Imports Windows.Storage.Streams
Imports Windows.Globalization
Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
' Step 1: WinRT file system access
Dim file As StorageFile = Await StorageFile.GetFileFromPathAsync(imagePath)
' Step 2: Open WinRT stream
Using stream As IRandomAccessStream = Await file.OpenAsync(FileAccessMode.Read)
' Step 3: Create bitmap decoder
Dim decoder As BitmapDecoder = Await BitmapDecoder.CreateAsync(stream)
' Step 4: Decode to SoftwareBitmap
Dim bitmap As SoftwareBitmap = Await decoder.GetSoftwareBitmapAsync()
' Step 5: Check language availability — Nothing if not installed on this machine
Dim engine As OcrEngine = OcrEngine.TryCreateFromLanguage(New Language("en-US"))
If engine Is Nothing Then
Throw New Exception("OCR engine not available for this language")
End If
' Step 6: Recognize
Dim result As OcrResult = Await engine.RecognizeAsync(bitmap)
Return result.Text
End Using
End Function
对 engine 的空值检查不是可选的。 如果目标语言包没有安装在运行代码的机器上,TryCreateFromLanguage 返回空值,并且无法进行识别。 没有退路; 应用程序必须向用户显示错误信息,或者静默失败。
了解IronOCR
IronOCR是一个商业.NET OCR 库,它基于优化的 Tesseract 5 引擎构建,并具有托管 API 层,可处理预处理、PDF 读取、多语言解析和结构化数据输出。 它以单个NuGet包的形式安装,无需单独部署外部本机二进制文件,无需管理 tessdata 文件夹,也无需特定于平台的 TFM。
主要特点:
-跨平台设计——无需修改代码即可在 Windows、Linux、macOS、Docker、Azure 应用服务(Windows 或 Linux)、AWS Lambda 和 GCP Cloud Run 上运行
- 自动预处理—在质量不佳的输入上,自动应用倾斜校正、去噪、对比度增强、二值化和分辨率缩放,可通过
OcrInput过滤方法进行显式控制 - 本地 PDF 输入 —
IronTesseract.Read直接接受 PDF 路径; 无需转换步骤,无需外部库 - 125+ 种捆绑语言— 语言包是随应用程序一起部署的NuGet包; 不依赖操作系统安装的语言数据
- 可搜索的 PDF 输出—
OcrResult.SaveAsSearchablePdf从任何扫描输入创建文本层 PDF - 结构化结果模型—
OcrResult显示Words,以及每个单词的可信度和边界框 - 线程安全—
IronTesseract实例支持并行工作负载,无需额外同步 - 永久许可 — $999 Lite 到 $5,999 Unlimited,一次性购买,处理无限文档
功能对比
| 特征 | Windows.Media.Ocr | IronOCR |
|---|---|---|
| 平台 | 仅限视窗 10/11 | Windows、Linux、macOS、Docker、云 |
| 价格 | 免费 | $5,999 永久 |
| PDF 输入 | 否 | 本地 |
| 语言模型 | 操作系统安装的软件包 | 通过NuGet打包的 125 多个软件包 |
| 预处理 | None | 自动+显式过滤器 |
| 可搜索的 PDF 输出 | 否 | 是 |
| API模型 | WinRT异步 | 标准 .NET |
详细功能对比
| 特征 | Windows.Media.Ocr | IronOCR |
|---|---|---|
| 平台支持 | ||
| 视窗 10/11 | 是 | 是 |
| Windows 服务器 | 有限的 | 是 |
| Linux | 否 | 是 |
| MacOS | 否 | 是 |
| 多克 | 否 | 是 |
| Azure Functions(Linux) | 否 | 是 |
| AWS Lambda | 否 | 是 |
| 输入格式 | ||
| JPEG / PNG / BMP | 是的(通过 WinRT 管道) | 是 |
| PDF(扫描版) | 否 | 是 |
| PDF(受密码保护) | 否 | 是 |
| TIFF/多页 | 否 | 是 |
| 流/字节数组 | 否(仅限 WinRT StorageFile) | 是 |
| 网址 | 否 | 是 |
| 语言支持 | ||
| 语言来源 | 操作系统自带语言包 | 125+ 个捆绑的NuGet包 |
| 无需操作系统管理员权限即可安装 | 否 | 是的(NuGet) |
| 多语言同步 | 否 | 是 |
| 跨机器的语言可移植性 | 否 | 是 |
| 预处理 | ||
| 德斯丘 | 否 | 是 (input.Deskew()) |
| 降噪 | 否 | 是 (input.DeNoise()) |
| 对比度增强 | 否 | 是 (input.Contrast()) |
| 二值化 | 否 | 是 (input.Binarize()) |
| 分辨率缩放 | 否 | 是 (input.EnhanceResolution(300)) |
| 输出 | ||
| 纯文本 | 是 | 是 |
| 可搜索的PDF | 否 | 是 |
| hOCR / HTML | 否 | 是 |
| 词级边界框 | 局部(线几何) | 是 |
| 逐词置信度得分 | 否 | 是 |
| API 设计 | ||
| TFM限制 | net*-windows* 必需 |
None |
| 同步路径 | 否 | 是 |
| OCR过程中的条形码读取 | 否 | 是 |
| 基于区域的OCR | 否 | 是 |
平台锁定与跨平台部署
这两个库之间最重要的区别不是准确性、预处理或 PDF 支持,而是部署拓扑结构。 Windows.Media.Ocr 在视窗 10/11之外并不存在。这不是配置问题,也不是缺少NuGet包; 在其他所有操作系统中,支持该 API 的 WinRT 运行时都不存在。
Windows.Media.Ocr 方法
WinRT 依赖项在项目文件中出现,甚至在运行任何一行代码之前就已经存在。 TargetFramework 必须指定 Windows 平台版本:
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
</PropertyGroup>
有了该 TFM,该项目就无法在Linux容器中使用。 基于 mcr.microsoft.com/dotnet/aspnet:8.0 的多克镜像—ASP.NET 部署的标准Linux基础镜像—没有 WinRT 运行时。在一个以 net8.0 为目标的项目中尝试引用 Windows.Media.Ocr 类型会产生编译错误,而不是运行错误。 锁定机制在构建时强制执行。
当 OCR 需求出现在运行在Linux上的微服务架构中,或者出现在生成跨平台多克镜像的 CI/CD 管道中时,Windows.Media.Ocr 就不是一个值得评估的选择——在第一次需求高峰到来之前就被淘汰了。
IronOCR方法
IronOCR 以 net8.0 和 net9.0 为目标,无需特定于平台的 TFM。 同一个NuGet包和同一个应用程序二进制文件可以在 Windows、Linux 和MacOS上运行。 在多克上部署 IronOCR 只需在Linux基础镜像上执行一行 apt-get,无需其他操作:
FROM mcr.microsoft.com/dotnet/aspnet:8.0
#Linuxdependency for System.Drawing
RUN apt-get update && apt-get install -y libgdiplus
COPY --from=build /app/publish /app
WORKDIR /app
ENTRYPOINT ["dotnet", "YourApp.dll"]
Windows 和Linux部署之间的应用程序代码本身没有变化:
// Same code — Windows, Linux, macOS, Docker, AWS Lambda
// 否 platform TFM, no WinRT, no conditional compilation
using IronOcr;
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read("document.jpg").Text;
// Same code — Windows, Linux, macOS, Docker, AWS Lambda
// 否 platform TFM, no WinRT, no conditional compilation
using IronOcr;
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read("document.jpg").Text;
Imports IronOcr
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read("document.jpg").Text
IronOCR可在 AWS Lambda 、 Linux 上的 Azure Functions以及Linux 服务器上直接运行,无需修改代码。 部署目标是配置问题,而不是架构限制。
语言支持:操作系统依赖型与捆绑包型
Windows.Media.Ocr 将语言可用性完全委托给主机。应用程序可以识别的语言集取决于用户(或 IT 管理员)在该特定 Windows 系统上安装了哪些语言包。 这会造成一类与你的代码无关的生产故障。
Windows.Media.Ocr 方法
OcrEngine.TryCreateFromLanguage 请求的语言未安装时返回空值。 TryCreateFromUserProfileLanguages 根本不存在具有 OCR 功能的语言包时,返回空值。 这两种方法都需要处理空值,而且都没有提供优雅的恢复路径——无法从代码中安装语言,也无法将语言与应用程序捆绑在一起:
// Windows.Media.Ocr: language availability is a runtime unknown
// Returns null if the language pack is not installed on this machine
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("fr-FR"));
if (engine == null)
{
// French OCR is simply unavailable — no recovery path
// User must go to Windows Settings > Language to install French
throw new InvalidOperationException(
"French OCR unavailable. Install the French language pack in Windows Settings.");
}
var result = await engine.RecognizeAsync(bitmap);
// Windows.Media.Ocr: language availability is a runtime unknown
// Returns null if the language pack is not installed on this machine
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("fr-FR"));
if (engine == null)
{
// French OCR is simply unavailable — no recovery path
// User must go to Windows Settings > Language to install French
throw new InvalidOperationException(
"French OCR unavailable. Install the French language pack in Windows Settings.");
}
var result = await engine.RecognizeAsync(bitmap);
Imports Windows.Globalization
Imports Windows.Media.Ocr
' Windows.Media.Ocr: language availability is a runtime unknown
' Returns Nothing if the language pack is not installed on this machine
Dim engine = OcrEngine.TryCreateFromLanguage(New Language("fr-FR"))
If engine Is Nothing Then
' French OCR is simply unavailable — no recovery path
' User must go to Windows Settings > Language to install French
Throw New InvalidOperationException("French OCR unavailable. Install the French language pack in Windows Settings.")
End If
Dim result = Await engine.RecognizeAsync(bitmap)
using Windows.Media.Ocr 部署多语言文档处理应用程序需要协调部署目标中每台计算机上的 Windows 语言包安装。 在由组策略管理的共享服务器或用户计算机上,这不在开发人员的控制范围内。
IronOCR方法
IronOCR将语言模型作为专用NuGet包提供,与应用程序二进制文件一起部署。 语言数据随构建产物一起传输,而不是随操作系统配置一起传输。 支持 125+ 种语言 是一个 dotnet add package 操作:
dotnet add package IronOcr.Languages.French, IronOcr.Languages.German, IronOcr.Languages.Arabic, IronOcr.Languages.ChineseSimplified
// IronOCR: language availability is a deploy-time guarantee, not a runtime unknown
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
ocr.AddSecondaryLanguage(OcrLanguage.German);
// Works on any machine, any OS, zero OS configuration required
var result = ocr.Read("multilingual-document.jpg");
Console.WriteLine(result.Text);
// IronOCR: language availability is a deploy-time guarantee, not a runtime unknown
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
ocr.AddSecondaryLanguage(OcrLanguage.German);
// Works on any machine, any OS, zero OS configuration required
var result = ocr.Read("multilingual-document.jpg");
Console.WriteLine(result.Text);
Imports IronOcr
' IronOCR: language availability is a deploy-time guarantee, not a runtime unknown
Dim ocr As New IronTesseract()
ocr.Language = OcrLanguage.French
ocr.AddSecondaryLanguage(OcrLanguage.German)
' Works on any machine, any OS, zero OS configuration required
Dim result = ocr.Read("multilingual-document.jpg")
Console.WriteLine(result.Text)
完整的语言目录涵盖拉丁文、CJK、阿拉伯文、希伯来文、梵文、西里尔文以及包括数学符号在内的特殊语言集。 每个语言包版本都与IronOCR包版本绑定,因此生产环境中的语言模型与本地测试的语言模型一致。
预处理缺失
低质量的扫描件——例如页面轻微旋转、复印文本带有斑点噪声、米白色纸张上的墨迹褪色——任何引擎如果直接接收这些扫描件,都会产生较差的 OCR 识别精度。 预处理会在识别运行之前纠正这些缺陷。 Windows.Media.Ocr 不提供任何类型的预处理层。
Windows.Media.Ocr 方法
API 接受一个 SoftwareBitmap 并返回文本。 这两个点之间的图像质量变化是无法配置的。 需要提高次优输入准确性的开发者必须在构建 SoftwareBitmap 之前使用 Windows Imaging Component API 手动实现预处理。 这是一个独立的代码库,有其自身的维护负担,而且它仍然是 Windows 特有的,原因与 OCR API 本身相同:
// Windows.Media.Ocr: no preprocessing — what you pass is what gets recognized
// Skewed, noisy, or low-resolution images degrade accuracy with no remedy
// Manual preprocessing via separate Windows Imaging APIs is the only option
var bitmap = await decoder.GetSoftwareBitmapAsync();
// bitmap goes directly to recognition with no quality improvement
var result = await engine.RecognizeAsync(bitmap);
// Windows.Media.Ocr: no preprocessing — what you pass is what gets recognized
// Skewed, noisy, or low-resolution images degrade accuracy with no remedy
// Manual preprocessing via separate Windows Imaging APIs is the only option
var bitmap = await decoder.GetSoftwareBitmapAsync();
// bitmap goes directly to recognition with no quality improvement
var result = await engine.RecognizeAsync(bitmap);
Imports System.Threading.Tasks
' Windows.Media.Ocr: no preprocessing — what you pass is what gets recognized
' Skewed, noisy, or low-resolution images degrade accuracy with no remedy
' Manual preprocessing via separate Windows Imaging APIs is the only option
Dim bitmap = Await decoder.GetSoftwareBitmapAsync()
' bitmap goes directly to recognition with no quality improvement
Dim result = Await engine.RecognizeAsync(bitmap)
对于标准的、干净的文档扫描(受控的扫描环境、一致的照明、最低 300 DPI、正确的方向),这种限制是可以接受的。 对于接收来自手机摄像头、自动进纸错位的平板扫描仪、传真文档或复印材料的文档处理流程而言,这意味着要么从头开始构建预处理层,要么接受精度下降。
IronOCR方法
IronOCR 的 OcrInput 类提供了一个预处理管道,其中的单个过滤方法按顺序应用。 图像质量校正滤镜可以解决生产文档处理中最常见的精度杀手:
// IronOCR: explicit preprocessing pipeline
// Each filter targets a specific quality defect
using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");
input.Deskew(); // Correct page rotation up to ~40 degrees
input.DeNoise(); // Remove scanner speckle and compression artifacts
input.Contrast(); // Boost contrast on faded or washed-out text
input.Binarize(); // Convert to black/white with optimal threshold
input.EnhanceResolution(300); // Scale image to 300 DPI for recognition
var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
// IronOCR: explicit preprocessing pipeline
// Each filter targets a specific quality defect
using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");
input.Deskew(); // Correct page rotation up to ~40 degrees
input.DeNoise(); // Remove scanner speckle and compression artifacts
input.Contrast(); // Boost contrast on faded or washed-out text
input.Binarize(); // Convert to black/white with optimal threshold
input.EnhanceResolution(300); // Scale image to 300 DPI for recognition
var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr
' IronOCR: explicit preprocessing pipeline
' Each filter targets a specific quality defect
Using input As New OcrInput()
input.LoadImage("low-quality-scan.jpg")
input.Deskew() ' Correct page rotation up to ~40 degrees
input.DeNoise() ' Remove scanner speckle and compression artifacts
input.Contrast() ' Boost contrast on faded or washed-out text
input.Binarize() ' Convert to black/white with optimal threshold
input.EnhanceResolution(300) ' Scale image to 300 DPI for recognition
Dim result = New IronTesseract().Read(input)
Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
对于常见情况,IronOCR 在直接调用 Read 时对文件路径应用自动预处理—引擎检测出质量问题并在无需显式过滤配置的情况下进行修正。 图像过滤器教程 涵盖了包括 Invert 和 ToGrayScale 在内的完整过滤器集,用于特定场景。 颜色校正滤镜和方向校正进一步扩展了流程,适用于具有非标准颜色配置文件或多角度旋转的文档。
PDF 支持缺失
PDF是Enterprise环境中最主要的文档格式。 合同、发票、扫描的档案和政府表格均以 PDF 格式发送。 Windows.Media.Ocr 没有 PDF 的概念——它只接受图像数据。 对 PDF 文档进行 OCR 需要单独的 PDF 渲染库、逐页光栅化和手动组装结果。
Windows.Media.Ocr 方法
API中没有PDF路径。 要使用 Windows.Media.Ocr 扫描 PDF,开发者必须:使用一个单独的 PDF 渲染库渲染每一页到 SoftwareBitmap (这些库均未内置于 Windows),遍历页面,每页调用 RecognizeAsync,并手动连接结果。 该渲染库本身还涉及额外的许可和部署方面的考虑。 Windows.Media.Ocr 代码只是整个实现中较小的一部分:
// Windows.Media.Ocr: no PDF support
// Requires external PDF renderer to rasterize pages before OCR
// Conceptual pattern — a PDF rendering library is not provided by Windows APIs
// Step 1: Use external PDF library to render page to bitmap (not shown)
// Step 2: Pass rendered bitmap to Windows OCR
// var bitmap = RenderPdfPageToBitmap(pdfPath, pageIndex); // external library required
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new Exception("No OCR language available");
// Step 3: Recognize the rasterized page
// var result = await engine.RecognizeAsync(bitmap);
// Step 4: Collect and concatenate results across all pages manually
// Windows.Media.Ocr: no PDF support
// Requires external PDF renderer to rasterize pages before OCR
// Conceptual pattern — a PDF rendering library is not provided by Windows APIs
// Step 1: Use external PDF library to render page to bitmap (not shown)
// Step 2: Pass rendered bitmap to Windows OCR
// var bitmap = RenderPdfPageToBitmap(pdfPath, pageIndex); // external library required
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new Exception("No OCR language available");
// Step 3: Recognize the rasterized page
// var result = await engine.RecognizeAsync(bitmap);
// Step 4: Collect and concatenate results across all pages manually
' Windows.Media.Ocr: no PDF support
' Requires external PDF renderer to rasterize pages before OCR
' Conceptual pattern — a PDF rendering library is not provided by Windows APIs
' Step 1: Use external PDF library to render page to bitmap (not shown)
' Step 2: Pass rendered bitmap to Windows OCR
' Dim bitmap = RenderPdfPageToBitmap(pdfPath, pageIndex) ' external library required
Dim engine = OcrEngine.TryCreateFromUserProfileLanguages()
If engine Is Nothing Then
Throw New Exception("No OCR language available")
End If
' Step 3: Recognize the rasterized page
' Dim result = Await engine.RecognizeAsync(bitmap)
' Step 4: Collect and concatenate results across all pages manually
仅外部 PDF 渲染步骤就增加了依赖项、单独的学习曲线以及额外的故障面,而原本是一个"免费且内置"的解决方案。
IronOCR方法
IronOCR可以直接读取 PDF 文件。 无需外部渲染器,无需光栅化步骤,无需手动页面组装。 接受图像路径的相同 IronTesseract.Read 方法也接受 PDF 路径。 .NET中的 PDF OCR是一行代码:
// IronOCR: native PDF support — no external renderer needed
var text = new IronTesseract().Read("scanned-document.pdf").Text;
// Password-protected PDFs
using var input = new OcrInput();
input.LoadPdf("encrypted.pdf", Password: "secret");
var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
// 可搜索的PDF output: make a scanned PDF text-searchable
var ocrResult = new IronTesseract().Read("scanned-archive.pdf");
ocrResult.SaveAsSearchablePdf("searchable-output.pdf");
// IronOCR: native PDF support — no external renderer needed
var text = new IronTesseract().Read("scanned-document.pdf").Text;
// Password-protected PDFs
using var input = new OcrInput();
input.LoadPdf("encrypted.pdf", Password: "secret");
var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
// 可搜索的PDF output: make a scanned PDF text-searchable
var ocrResult = new IronTesseract().Read("scanned-archive.pdf");
ocrResult.SaveAsSearchablePdf("searchable-output.pdf");
Imports IronOcr
' IronOCR: native PDF support — no external renderer needed
Dim text As String = New IronTesseract().Read("scanned-document.pdf").Text
' Password-protected PDFs
Using input As New OcrInput()
input.LoadPdf("encrypted.pdf", Password:="secret")
Dim result = New IronTesseract().Read(input)
Console.WriteLine(result.Text)
End Using
' 可搜索的PDF output: make a scanned PDF text-searchable
Dim ocrResult = New IronTesseract().Read("scanned-archive.pdf")
ocrResult.SaveAsSearchablePdf("searchable-output.pdf")
可搜索 PDF 功能在原始扫描图像上嵌入文本层,生成 PDF 文件,既能保持视觉保真度,又能实现全文搜索和复制粘贴。 这是文档管理系统和合规性档案的常见要求。 Windows.Media.Ocr 在其 API 的任何层都无法生成此输出。
API 映射参考
| 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) |
OcrResult.Text |
OcrResult.Text |
OcrResult.Lines |
OcrResult.Lines (带扩展元数据) |
OcrLine.Text |
OcrResult.Lines[i].Text |
OcrLine.Words |
OcrResult.Words (带边界框和可信度) |
OcrWord.BoundingRect |
OcrResult.Words[i].X, .Y, .Width, .Height |
BitmapDecoder.CreateAsync(stream) |
input.LoadImage(stream) 通过 OcrInput |
StorageFile.GetFileFromPathAsync(path) |
ocr.Read("path") 直接 |
| 没有等效项(不支持 PDF) | ocr.Read("document.pdf") |
| 没有等效项(不支持 PDF) | input.LoadPdf("file.pdf", Password: "x") |
| 没有等效版本(没有可搜索的PDF) | result.SaveAsSearchablePdf("output.pdf") |
| 无等效项(无预处理) | input.Deskew(), input.DeNoise(), input.Contrast() |
| 没有等效版本(没有多语言版本) | ocr.AddSecondaryLanguage(OcrLanguage.X) |
| 没有等效物(没有信心) | result.Confidence, word.Confidence |
当团队考虑从 Windows.Media.OCR 迁移到IronOCR
该应用程序的功能已超出 Windows 桌面的限制
最常见的触发因素是需求变更,引入了非 Windows 部署目标。 最初作为 Windows 内部工具诞生的桌面实用程序,可以升级为 Web 服务、基于多克的微服务或云函数。 一旦发生这种情况,Windows.Media.Ocr 就会成为阻碍因素。 由于目标平台上不存在 API,因此 OCR 组件需要完全重写——没有移植版本,没有兼容性垫片,也没有条件编译标志可以解决该问题。 提前使用IronOCR进行规划的团队不会遇到此次重写。
语言需求超出已安装的软件包数量
文档处理流程通常会扩展范围。 一个原本用于处理英文发票的系统,现在需要能够处理法文、德文、阿拉伯文或日文文档。 使用 Windows.Media.Ocr 时,要支持这些语言,需要在每个部署目标(开发人员机器、测试虚拟机、生产服务器以及其中的任何容器)上协调操作系统语言包的安装。 在由组策略管理的环境中或在操作系统占用空间最小的云虚拟机中,这种协调是不切实际的。IronOCR基于 NuGet 的语言包随应用程序一起部署,无需操作系统协调。
PDF 处理已纳入范围
当最初的要求是"从平板扫描仪读取图像 OCR"时,Windows.Media.Ocr 可以满足需求。 当需求扩展到"还要处理我们档案库中积压的扫描 PDF 文件"时,第二个库就进入了堆栈。 该库增加了一个依赖项,增加了一个许可方面的考虑因素,也增加了一个故障点。 对于需要在统一 API 上同时进行图像 OCR 和 PDF OCR 的团队来说, IronOCR从一开始就消除了双库架构。
实际输入数据准确率会降低
受控的扫描环境可产生清晰的图像。 现实世界中的输入——手机拍摄的照片、轻微倾斜的平板扫描仪扫描件、较旧的传真接收文档、复印材料——会导致精度下降,而 Windows.Media.Ocr 无法解决这个问题。 当客户开始投诉短信未送达时,团队才发现他们跳过的预处理步骤变得必不可少了。 使用 Windows Imaging API 进行预处理改造是一项巨大的开发工作,这使得该解决方案仅适用于 Windows。 IronOCR的预处理流程已经就绪。
服务器部署问题由此产生
Windows.Media.Ocr 文档明确定义了客户端应用程序的 API 定位。 在服务器环境中运行它(例如,处理用户上传文档的ASP.NET应用程序,或使用文档队列的 Windows 服务)需要安装桌面体验的Windows 服务器环境,这比Linux容器更耗费资源,成本也更高。 当基础架构团队询问 OCR 工作程序是否可以在Linux实例上运行以降低托管成本时,Windows.Media.Ocr 的答案是否定的。
常见迁移注意事项
项目文件 TFM 变更
Windows.Media.Ocr 在项目文件中需要 Windows 特定的 TFM (net8.0-windows10.0.19041.0 或类似)。 要移除对跨平台目标的支持,就意味着要移除 TFM 后缀。IronOCR以 net8.0 和 net9.0 为目标,没有 Windows 特定后缀。 迁移时,请确认项目中没有其他 WinRT API 依赖项需要 Windows TFM – 其他 Windows 平台功能(shell 集成、Windows 通知等)可能需要通过平台检查进行抽象。
异步到同步迁移
Windows.Media.Ocr 完全异步—RecognizeAsync 返回 IAsyncOperation<OcrResult>,通过 WinRT 互操作映射到 Task<OcrResult>。IronOCR 提供同步和异步路径。 同步 ocr.Read("file.jpg") 直接替换了多步 await 链。 对于 OCR 调用位于后台服务或基于任务的管道中的服务器应用程序,也可以使用异步路径。 无论哪种方式,从 6 个以上的异步步骤过渡到 1 个调用都很简单:
// Before: Windows.Media.Ocr — 6+ await operations
var file = await StorageFile.GetFileFromPathAsync(imagePath);
using var stream = await file.OpenAsync(FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var bitmap = await decoder.GetSoftwareBitmapAsync();
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
var winResult = await engine.RecognizeAsync(bitmap);
string text = winResult.Text;
// After:IronOCR— 1 call, same result, any platform
string text = new IronTesseract().Read(imagePath).Text;
// Before: Windows.Media.Ocr — 6+ await operations
var file = await StorageFile.GetFileFromPathAsync(imagePath);
using var stream = await file.OpenAsync(FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var bitmap = await decoder.GetSoftwareBitmapAsync();
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
var winResult = await engine.RecognizeAsync(bitmap);
string text = winResult.Text;
// After:IronOCR— 1 call, same result, any platform
string text = new IronTesseract().Read(imagePath).Text;
Imports Windows.Storage
Imports Windows.Graphics.Imaging
Imports Windows.Media.Ocr
' Before: Windows.Media.Ocr — 6+ await operations
Dim file As StorageFile = Await StorageFile.GetFileFromPathAsync(imagePath)
Using stream = Await file.OpenAsync(FileAccessMode.Read)
Dim decoder As BitmapDecoder = Await BitmapDecoder.CreateAsync(stream)
Dim bitmap = Await decoder.GetSoftwareBitmapAsync()
Dim engine = OcrEngine.TryCreateFromUserProfileLanguages()
Dim winResult = Await engine.RecognizeAsync(bitmap)
Dim text As String = winResult.Text
End Using
' After: IronOCR— 1 call, same result, any platform
Dim text As String = New IronTesseract().Read(imagePath).Text
语言包替换
对于之前通过 OcrEngine.TryCreateFromLanguage(new Windows.Globalization.Language("fr-FR")) 解析的每一种语言,安装相应的IronOCR语言包并设置 ocr.Language = OcrLanguage.French。 IronOCR语言目录列出了所有 125 多个可用的语言包。 语言代码从 BCP-47 标签直接映射到 OcrLanguage 枚举。
空引擎操控移除
Windows.Media.Ocr 要求对每次引擎创建调用进行空值检查。 IronOCR在配置或初始化失败时会抛出结构化异常,而不是返回 null。 移除空值检查保护条款,并在需要时替换为标准异常处理。 其结果是调用站点更加简洁,不会出现"语言无法静默使用"的故障模式。
其他IronOCR功能
除了直接替代 Windows.Media.Ocr 功能的特性之外, IronOCR还涵盖了 Windows.Media.Ocr 没有的等效功能:
-扫描文档处理— 专为处理多页扫描文档而设计,包括 TIFF 和多页 PDF 输入 -表格提取——对文档中的表格数据进行结构化检测,包括发票明细、报表网格和表单矩阵。 -特殊文件类型——护照磁条区、MICR 校验行、车牌和手写文本均有专门的处理路径。 -进度跟踪——批量操作通过事件报告进度,从而在应用程序用户界面中启用进度条和处理速率监控
.NET兼容性和未来准备情况
IronOCR支持标准 TFM 上的.NET 6、 .NET 7、 .NET 8 和.NET 9(无平台特定后缀),同时还支持.NET Framework 4.6.2 至 4.8,以支持旧版应用程序。 该库会定期更新,以跟踪.NET 的发布节奏,并计划在 2026 年实现对.NET 10 的支持。Windows.Media.Ocr 可在任何支持 WinRT 互操作的.NET版本(从.NET 5 开始)中使用,但 Windows TFM 要求永久限制了其在面向 Windows 的项目中的适用性。 随着 .NET 的跨平台发展日趋成熟——越来越多的团队将Linux容器和云函数作为首选部署目标——Windows.Media.Ocr 的 TFM 限制不再是一个次要的缺陷,而是一个更加明显的架构缺陷。
结论
Windows.Media.Ocr 占据了一个特定且合理的市场定位:一款面向视窗 10/11的桌面应用程序,它没有任何跨平台开发的目标,仅满足基本的图像 OCR 需求,且预算为零。在这个细分市场中,它表现出色。 除了上述特定场景之外——例如部署目标为Linux容器、云函数、具有多种语言要求的服务器或处理 PDF 的文档管道——目标平台上不存在 API,必须替换代码。
更深层次的问题是,Windows.Media.Ocr 的局限性是架构上的,而不是偶然的。 平台锁定不是一个可以关闭的配置选项; 它是集成到 API 所依赖的 WinRT 运行时环境中的。 语言可用性不是在构建时需要包含的软件包;它委托给操作系统管理员。 PDF 支持并不是NuGet包需要添加的缺失功能; 它完全没有出现在 API 接口中。 每个限制都需要一个单独的系统来弥补,而每个弥补系统都会重新引入平台依赖性。
IronOCR在一个软件包中解决了平台、语言、预处理和 PDF 这四个限制条件。 $999 入门价格不是 $0,对于具有可控输入和仅限英语文档的 Windows 唯一桌面工具来说,Windows.Media.Ocr 依然是一个有效选择。对于任何具有更广泛需求的项目来说,在项目进入首次生产部署之前,围绕 Windows.Media.Ocr 约束构建的成本可能会超过IronOCR许可证成本。
实际测试很简单:如果部署目标可能是 Linux、Docker 或云函数,并且输入文档可能是 PDF 或使用默认操作系统包之外的语言,那么 Windows.Media.Ocr 就不是合适的基础。 在项目进行到一半时才发现问题,比一开始就选择合适的工具要昂贵得多。 在做出决定之前,根据您的具体要求评估IronOCR 的功能集是做出决定的最有效方法。
常见问题解答
Windows.Media.Ocr是什么?
Windows.Media.Ocr 是一款 OCR 解决方案,开发人员和企业使用它从图像和文档中提取文本。它是与 IronOCR 一起评估的几种用于 .NET 应用程序开发的 OCR 选项之一。
对于 .NET 开发人员来说,IronOCR 与 Windows.Media.Ocr 相比有何不同?
IronOCR 是一个基于 NuGet 的 .NET OCR 库,它使用 IronTesseract 作为其核心引擎。与 Windows.Media.Ocr 相比,它提供了更简单的部署方式(无需 SDK 安装程序)、统一的定价模式以及简洁的 C# API,无需 COM 互操作或云依赖。
IronOCR 比 Windows.Media.Ocr 更容易设置吗?
IronOCR 通过单个 NuGet 包进行安装。无需 SDK 安装程序、复制许可证文件、注册 COM 组件或管理单独的运行时二进制文件。整个 OCR 引擎都打包在包中。
Windows.Media.OCR 和 IronOCR 在准确率方面存在哪些差异?
IronOCR 对标准商务文档、发票、收据和扫描表格的识别准确率很高。对于严重损坏的文档或不常见的文字,识别准确率会因源文件质量而异。IronOCR 包含图像预处理滤镜,可提高低质量输入文件的识别率。
IronOCR是否支持PDF文本提取?
是的。IronOCR只需一次调用即可从原生PDF和扫描的PDF图像中提取文本。它还支持多页TIFF文件、图像和流。对于扫描的PDF,OCR逐页进行处理,并为每个页面生成一个结果对象。
Windows.Media.Ocr 的许可方式与 IronOCR 相比有何不同?
IronOCR采用永久统一费率许可,不按页或扫描次数收费。处理大量文档的机构无论处理量多少,都只需支付相同的许可费用。详情及批量定价请访问IronOCR许可页面。
IronOCR支持哪些语言?
IronOCR 通过独立的 NuGet 语言包支持 127 种语言。添加语言只需一条命令“dotnet add package IronOcr.Languages.{Language}”。无需手动放置文件或配置路径。
如何在.NET项目中安装IronOCR ?
通过 NuGet 安装:在程序包管理器控制台中运行“Install-Package IronOcr”命令,或在命令行界面 (CLI) 中运行“dotnet add package IronOcr”命令。其他语言包的安装方式相同。无需使用原生 SDK 安装程序。
与 Windows.Media.Ocr 不同,IronOCR 是否适用于 Docker 和容器化部署?
是的。IronOCR 通过 NuGet 包在 Docker 容器中运行。许可证密钥通过环境变量设置。OCR 引擎本身不需要任何许可证文件、SDK 路径或卷挂载。
我可以在购买前试用 IronOCR,并将其与 Windows.Media.Ocr 进行比较吗?
是的。IronOCR 试用模式可以处理文档,并在输出结果上添加水印,从而生成 OCR 结果。您可以在购买许可证之前,先在自己的文档上验证其准确性。
IronOCR是否支持条形码读取和文本提取?
IronOCR专注于文本提取和OCR识别。对于条形码读取,Iron Software提供了配套库IronBarcode。两者都可单独购买,也可作为Iron Suite套装的一部分购买。
从 Windows.Media.OCR 迁移到 IronOCR 容易吗?
从 Windows.Media.Ocr 迁移到 IronOCR 通常涉及将初始化序列替换为 IronTesseract 实例化、移除 COM 生命周期管理以及更新 API 调用。大多数迁移都能显著降低代码复杂度。

