跳至頁尾內容
與其他組件的比較

using IronOCR 的 Acrobat DC OCR 替代方案

在Google Cloud Vision從影像讀取任何一個字元之前,您需要先建立GCP專案,啟用Vision API,建立服務帳戶,下載包含RSA私鑰的JSON金鑰檔案,設置每個將運行您的程式的伺服器上的StatusCode.ResourceExhausted,以防1,800請求每分鐘的預設配額耗盡。 然後您會發現PDF處理需要第二個NuGet套件(Google.Cloud.Storage.V1),一個GCS儲存桶,一個非同步輪詢迴圈,JSON輸出解析,以及從雲儲存中刪除物件的清理步驟。 Google Cloud Vision的真正優勢在於其機器學習支持的模型在中文、日文和韓文文字上的準確性強,但在您處理單一生產文件之前,操作表面積已經相當龐大。

了解 Google Cloud Vision

Google Cloud Vision是一個由Google的機器學習基礎設施支持的雲端托管圖像分析API。 在OCR中,它提供了兩種不同的功能型別:DOCUMENT_TEXT_DETECTION,優化用於密集文件,具有段落、表格和多欄佈局。 此服務通過Google.Cloud.Vision.V1 NuGet套件調用,該套件包裝了一個gRPC傳輸層並返回Protobuf生成的響應物件。

關鍵架構特徵:

  • 僅限雲端處理:每個文件都被傳輸到並處理於Google的基礎設施上。 沒有本地模式。
  • 服務帳戶驗證:身份驗證需要一個包含RSA私鑰、使用者端電子郵件和專案ID的JSON金鑰檔案。 該檔案必須部署到每一個主機上並通過GOOGLE_APPLICATION_CREDENTIALS環境變數或Google應用程式預設憑證引用。
  • PDF需要GCS和非同步:處理PDF文件不是直接的API調用。 PDF必須上傳到Google Cloud Storage,通過AsyncBatchAnnotateFilesAsync提交,輪詢直到完成,然後從GCS下載並解析JSON輸出檔案。
  • Protobuf響應層次結構:TextAnnotation Protobuf物件,具有PagesBlocksParagraphsWordsSymbols的層次結構。 提取段落文字需要迭代四個層次並串聯單個符號字串。
  • 速率限制:預設配額為每分鐘1,800請求。 超過此閾值的批量處理需要為StatusCode.ResourceExhausted響應實施重試邏輯。
  • FedRAMP狀態:Google Cloud Vision未獲得FedRAMP授權,不符合在聯邦機構使用的用例,可用的替代方案包括Azure Computer Vision(FedRAMP High)或AWS Textract(FedRAMP High)。
  • 定價:每1,000張圖片的費率適用於DOCUMENT_TEXT_DETECTION,每月前1,000單位免費; PDF非同步處理按頁計費。 請參照Google Cloud Vision定價頁面查詢當前利率。

服務帳戶憑證設置

以下來自google-vision-vs-ironocr-examples.cs的程式碼說明了客戶端初始化模式。 實例化行所隱藏的是前提條件:GOOGLE_APPLICATION_CREDENTIALS環境變數必須已經指向當前機器上的有效服務帳戶JSON金鑰文件:

using Google.Cloud.Vision.V1;

public class GoogleVisionService
{
    private readonly ImageAnnotatorClient _client;

    public GoogleVisionService()
    {
        // Requires GOOGLE_APPLICATION_CREDENTIALS env var
        // pointing to a service account JSON key file
        _client = ImageAnnotatorClient.Create();
    }

    public string DetectText(string imagePath)
    {
        // WARNING: Image uploaded to Google Cloud
        var image = Image.FromFile(imagePath);
        var response = _client.DetectText(image);

        if (response.Count > 0)
        {
            return response[0].Description;
        }

        return string.Empty;
    }
}
using Google.Cloud.Vision.V1;

public class GoogleVisionService
{
    private readonly ImageAnnotatorClient _client;

    public GoogleVisionService()
    {
        // Requires GOOGLE_APPLICATION_CREDENTIALS env var
        // pointing to a service account JSON key file
        _client = ImageAnnotatorClient.Create();
    }

    public string DetectText(string imagePath)
    {
        // WARNING: Image uploaded to Google Cloud
        var image = Image.FromFile(imagePath);
        var response = _client.DetectText(image);

        if (response.Count > 0)
        {
            return response[0].Description;
        }

        return string.Empty;
    }
}
Imports Google.Cloud.Vision.V1

Public Class GoogleVisionService
    Private ReadOnly _client As ImageAnnotatorClient

    Public Sub New()
        ' Requires GOOGLE_APPLICATION_CREDENTIALS env var
        ' pointing to a service account JSON key file
        _client = ImageAnnotatorClient.Create()
    End Sub

    Public Function DetectText(imagePath As String) As String
        ' WARNING: Image uploaded to Google Cloud
        Dim image = Image.FromFile(imagePath)
        Dim response = _client.DetectText(image)

        If response.Count > 0 Then
            Return response(0).Description
        End If

        Return String.Empty
    End Function
End Class
$vbLabelText   $csharpLabel

JSON金鑰文件包含RSA私鑰、客戶端電子郵件和項目標識符。 它絕不能提交到源控制,必須從Docker映像中排除,必須定期輪換,並必須通過適當的文件系統權限進行保護。 受損的密鑰將授予API存取權,直到在GCP控制台上手動撤銷它。

理解 IronOCR

IronOCR 是一個商業化的在本地運行的.NET用OCR庫,基於優化的Tesseract 5引擎。它處理所有文件本地的-無需雲傳輸、無需互聯網、無需第三方資料處理。 單次NuGet包安裝(IronOcr)即可提供所有功能:OCR引擎、自動預處理過濾器、內製PDF支持以及125多個語言包作為單獨的NuGet包可用。

關鍵特徵:

  • 本地處理:文件永遠不會離開您的基礎設施。 適用於空隙環境、保密網路,及無出站連接的Docker容器。
  • 單次NuGet部署:無需tessdata文件夾,無需本地庫管理,除了授權金鑰字串外不需要環境變數。
  • 自動預處理:在低質量輸入上,自動應用去斜、降噪、對比度、二值化及增強解析度過濾器,且可單獨獲得控制。
  • 原生PDF輸入:PDF透過input.LoadPdf()直接載入並進行同步處理。 受密碼保護的PDF需一個參數。
  • 結構化:Text, Confidence, Pages, Paragraphs, Lines, Barcodes暴露為型別化的.NET物件-無需Protobuf反序列化,無需符號串聯。
  • 執行緒安全:IronTesseract實例可安全並行使用。 批處理工作負載可使用Parallel.ForEach而不需額外同步。
  • 永久許可:$999 Lite、$1,499 Plus、$2,999 Professional、$5,999 Unlimited-一次性購買,無交易成本。

功能比較

功能 Google Cloud Vision IronOCR
處理模型 僅限雲端 僅限本地
PDF處理 透過GCS + 非同步API 直接,同步
身份驗證 服務帳戶JSON金鑰 授權密鑰字串
FedRAMP授權 未授權 不適用(本地)
按文件費用 按頁(參見Google Cloud Vision定價 None
離線 / 空隙 不是

詳細功能比較

類別 功能 Google Cloud Vision IronOCR
輸入 圖像OCR
PDF OCR 透過GCS + 非同步(50+行) input.LoadPdf()(3行)
受密碼保護的 PDF 不支持 LoadPdf(path, Password: "...")
流輸入
URL輸入 不是 input.LoadImageFromUrl()
TIFF / GIF多幀 有限
身份驗證 憑證型別 JSON金鑰文件 + env變數 授權密鑰字串
憑證輪換 需要(手動) 不需要
CI/CD需要秘密 是(密鑰檔案) 是(僅限授權字串)
處理 離線 / 空隙 不是
同步處理 僅圖片 圖片和PDF
速率限制 1,800每分鐘預設 無(CPU限制)
預處理(自動) 無(基於ML) 去斜、降噪、對比度、二值化、增強解析度
輸出 純文字
結構化結果(型別化) Protobuf層次結構 OcrResult(.NET物件)
置信分數 每符號/字 每字和整體
可搜尋的 PDF 輸出 不是 result.SaveAsSearchablePdf()
條碼讀取 獨立的API功能 ocr.Configuration.ReadBarCodes = true
基於區域的OCR 無原生區域裁剪 CropRectangle在輸入上
語言 語言數量 ~50 125+通過NuGet包
CJK準確性 強(機器學習支持) 好(Tesseract 5 LSTM)
合規性 FedRAMP 未授權 不適用(本地)
HIPAA / ITAR BAA + 複雜審核 無第三方處理
GDPR第28條 需要DPA 不適用(本地)
成本 定價模型 聯絡Google獲取當前定價 永久($5,999)

身份驗證複雜性和憑證管理

Google Cloud Vision最被低估的成本不是每張圖片的費用。 而是在您的應用程式運行的每個環境中管理服務帳戶憑證的操作開銷。

Google Cloud Vision的方法

初始化客戶端看起來像單行,但該行會拋出StatusCode.PermissionDenied,除非七個前提條件都存在。 來自google-cloud-vision-migration-examples.cs,憑證設置講述了完整的故事:

public GoogleVisionCredentialSetup()
{
    // BEFORE: Requires GOOGLE_APPLICATION_CREDENTIALS environment variable
    // pointing to a service account JSON key file:
    // export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
    //
    // The JSON file contains sensitive data:
    // - private_key: RSA private key
    // - client_email: service account email
    // - project_id: GCP project identifier
    //
    // Security concerns:
    // - Key file must never be committed to source control
    // - Key file must be rotated periodically
    // - Key file must be protected with file system permissions
    // - Key file compromise grants API access until revoked

    _client = ImageAnnotatorClient.Create();
}
public GoogleVisionCredentialSetup()
{
    // BEFORE: Requires GOOGLE_APPLICATION_CREDENTIALS environment variable
    // pointing to a service account JSON key file:
    // export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
    //
    // The JSON file contains sensitive data:
    // - private_key: RSA private key
    // - client_email: service account email
    // - project_id: GCP project identifier
    //
    // Security concerns:
    // - Key file must never be committed to source control
    // - Key file must be rotated periodically
    // - Key file must be protected with file system permissions
    // - Key file compromise grants API access until revoked

    _client = ImageAnnotatorClient.Create();
}
Public Sub New()
    ' BEFORE: Requires GOOGLE_APPLICATION_CREDENTIALS environment variable
    ' pointing to a service account JSON key file:
    ' export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
    '
    ' The JSON file contains sensitive data:
    ' - private_key: RSA private key
    ' - client_email: service account email
    ' - project_id: GCP project identifier
    '
    ' Security concerns:
    ' - Key file must never be committed to source control
    ' - Key file must be rotated periodically
    ' - Key file must be protected with file system permissions
    ' - Key file compromise grants API access until revoked

    _client = ImageAnnotatorClient.Create()
End Sub
$vbLabelText   $csharpLabel

在基於Docker的部署中,JSON金鑰文件必須掛載為祕密卷或通過Kubernetes祕密注入。 在多區域設置中,每個區域都需要相同的憑證配置。 密鑰輪換是一個手動過程,需要同步更新每個部署,或者接受一個窗口,其中舊的和新的密鑰都有效。 錯誤處理層成比例增長——生產程式碼需要StatusCode.DeadlineExceeded的不同捕獲塊。

IronOCR方法

IronOCR的設置是一串授權金鑰。 無需部署文件,除了密鑰本身的環境變數就不再需要其他,無需輪換計劃:

public IronOcrCredentialSetup()
{
    // Simple license key - no key files, no environment variables required
    IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
        ?? "YOUR-LICENSE-KEY";

    //不是service accounts, no key rotation, no IAM configuration
    _ocr = new IronTesseract();
}
public IronOcrCredentialSetup()
{
    // Simple license key - no key files, no environment variables required
    IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
        ?? "YOUR-LICENSE-KEY";

    //不是service accounts, no key rotation, no IAM configuration
    _ocr = new IronTesseract();
}
Public Sub New()
    ' Simple license key - no key files, no environment variables required
    IronOcr.License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONOCR_LICENSE"), "YOUR-LICENSE-KEY")

    '不是service accounts, no key rotation, no IAM configuration
    _ocr = New IronTesseract()
End Sub
$vbLabelText   $csharpLabel

在CI/CD中,授權金鑰是一個單一的管道秘密。 在Docker中,它是一個單一的環境變數。 無需掛載JSON文件,無需分配IAM角色,無需與GCP控制台互動。 當一名開發者加入團隊時,他們只會收到一個字串。 與身份驗證相關的故障的完整錯誤面是:密鑰無效,或試用期已過。

PDF處理:GCS管道vs直接載入

PDF處理是兩者之間運行操作差距的具體表現。 Google Cloud Vision不接受PDF作為直接API輸入,文件必須作為中介通過Google Cloud Storage傳遞。

Google Cloud Vision的方法

DownloadAndParseResultsAsync實施之前超過了40行 - 此本身需要解析GCS輸出URI,列出結果物件,下載JSON文件,並跨頁面拼接文字:

public async Task<string> ProcessPdfAsync(string pdfPath)
{
    // Step 1: Create storage client
    var storageClient = StorageClient.Create();
    var objectName = $"ocr-input/{Guid.NewGuid()}.pdf";

    // Step 2: Upload PDF to GCS (document leaves your infrastructure)
    using (var stream = File.OpenRead(pdfPath))
    {
        await storageClient.UploadObjectAsync(
            _bucketName, objectName, "application/pdf", stream);
    }

    // Step 3: Build async annotation request
    var asyncRequest = new AsyncAnnotateFileRequest
    {
        InputConfig = new InputConfig
        {
            GcsSource = new GcsSource { Uri = $"gs://{_bucketName}/{objectName}" },
            MimeType = "application/pdf"
        },
        Features = { new功能{ Type = Feature.Types.Type.DocumentTextDetection } },
        OutputConfig = new OutputConfig
        {
            GcsDestination = new GcsDestination { Uri = $"gs://{_bucketName}/ocr-output/" },
            BatchSize = 1
        }
    };

    // Step 4: Submit and wait for async operation
    var operation = await _visionClient.AsyncBatchAnnotateFilesAsync(
        new[] { asyncRequest });
    var completedOperation = await operation.PollUntilCompletedAsync();

    // Step 5: Download and parse results from GCS output
    var outputUri = completedOperation.Result.Responses[0]
        .OutputConfig.GcsDestination.Uri;
    var text = await DownloadAndParseResultsAsync(storageClient, outputUri);

    // Step 6: Clean up input file from GCS
    await storageClient.DeleteObjectAsync(_bucketName, objectName);

    return text;
}
public async Task<string> ProcessPdfAsync(string pdfPath)
{
    // Step 1: Create storage client
    var storageClient = StorageClient.Create();
    var objectName = $"ocr-input/{Guid.NewGuid()}.pdf";

    // Step 2: Upload PDF to GCS (document leaves your infrastructure)
    using (var stream = File.OpenRead(pdfPath))
    {
        await storageClient.UploadObjectAsync(
            _bucketName, objectName, "application/pdf", stream);
    }

    // Step 3: Build async annotation request
    var asyncRequest = new AsyncAnnotateFileRequest
    {
        InputConfig = new InputConfig
        {
            GcsSource = new GcsSource { Uri = $"gs://{_bucketName}/{objectName}" },
            MimeType = "application/pdf"
        },
        Features = { new功能{ Type = Feature.Types.Type.DocumentTextDetection } },
        OutputConfig = new OutputConfig
        {
            GcsDestination = new GcsDestination { Uri = $"gs://{_bucketName}/ocr-output/" },
            BatchSize = 1
        }
    };

    // Step 4: Submit and wait for async operation
    var operation = await _visionClient.AsyncBatchAnnotateFilesAsync(
        new[] { asyncRequest });
    var completedOperation = await operation.PollUntilCompletedAsync();

    // Step 5: Download and parse results from GCS output
    var outputUri = completedOperation.Result.Responses[0]
        .OutputConfig.GcsDestination.Uri;
    var text = await DownloadAndParseResultsAsync(storageClient, outputUri);

    // Step 6: Clean up input file from GCS
    await storageClient.DeleteObjectAsync(_bucketName, objectName);

    return text;
}
Imports System
Imports System.IO
Imports System.Threading.Tasks

Public Class PdfProcessor
    Private _bucketName As String
    Private _visionClient As VisionClient

    Public Async Function ProcessPdfAsync(pdfPath As String) As Task(Of String)
        ' Step 1: Create storage client
        Dim storageClient = StorageClient.Create()
        Dim objectName = $"ocr-input/{Guid.NewGuid()}.pdf"

        ' Step 2: Upload PDF to GCS (document leaves your infrastructure)
        Using stream = File.OpenRead(pdfPath)
            Await storageClient.UploadObjectAsync(_bucketName, objectName, "application/pdf", stream)
        End Using

        ' Step 3: Build async annotation request
        Dim asyncRequest = New AsyncAnnotateFileRequest With {
            .InputConfig = New InputConfig With {
                .GcsSource = New GcsSource With {.Uri = $"gs://{_bucketName}/{objectName}"},
                .MimeType = "application/pdf"
            },
            .Features = {New Feature With {.Type = Feature.Types.Type.DocumentTextDetection}},
            .OutputConfig = New OutputConfig With {
                .GcsDestination = New GcsDestination With {.Uri = $"gs://{_bucketName}/ocr-output/"},
                .BatchSize = 1
            }
        }

        ' Step 4: Submit and wait for async operation
        Dim operation = Await _visionClient.AsyncBatchAnnotateFilesAsync({asyncRequest})
        Dim completedOperation = Await operation.PollUntilCompletedAsync()

        ' Step 5: Download and parse results from GCS output
        Dim outputUri = completedOperation.Result.Responses(0).OutputConfig.GcsDestination.Uri
        Dim text = Await DownloadAndParseResultsAsync(storageClient, outputUri)

        ' Step 6: Clean up input file from GCS
        Await storageClient.DeleteObjectAsync(_bucketName, objectName)

        Return text
    End Function

    Private Async Function DownloadAndParseResultsAsync(storageClient As StorageClient, outputUri As String) As Task(Of String)
        ' Implementation for downloading and parsing results
        Return String.Empty
    End Function
End Class

Public Class StorageClient
    Public Shared Function Create() As StorageClient
        Return New StorageClient()
    End Function

    Public Async Function UploadObjectAsync(bucketName As String, objectName As String, mimeType As String, stream As Stream) As Task
        ' Implementation for uploading object
    End Function

    Public Async Function DeleteObjectAsync(bucketName As String, objectName As String) As Task
        ' Implementation for deleting object
    End Function
End Class

Public Class VisionClient
    Public Async Function AsyncBatchAnnotateFilesAsync(requests As AsyncAnnotateFileRequest()) As Task(Of Operation)
        ' Implementation for async batch annotate files
        Return New Operation()
    End Function
End Class

Public Class Operation
    Public Async Function PollUntilCompletedAsync() As Task(Of OperationResult)
        ' Implementation for polling until completed
        Return New OperationResult()
    End Function
End Class

Public Class OperationResult
    Public Property Responses As Response()
End Class

Public Class Response
    Public Property OutputConfig As OutputConfig
End Class

Public Class AsyncAnnotateFileRequest
    Public Property InputConfig As InputConfig
    Public Property Features As Feature()
    Public Property OutputConfig As OutputConfig
End Class

Public Class InputConfig
    Public Property GcsSource As GcsSource
    Public Property MimeType As String
End Class

Public Class GcsSource
    Public Property Uri As String
End Class

Public Class Feature
    Public Property Type As Feature.Types.Type

    Public Class Types
        Public Enum Type
            DocumentTextDetection
        End Enum
    End Class
End Class

Public Class OutputConfig
    Public Property GcsDestination As GcsDestination
    Public Property BatchSize As Integer
End Class

Public Class GcsDestination
    Public Property Uri As String
End Class
$vbLabelText   $csharpLabel

這是最低可行的實施,並非經生產硬化的。 生產程式碼增加了重試邏輯以應對GCS上傳失敗,超時處理以應對緩慢的非同步操作,輸出物件的清理(不僅僅是輸入物件),如果操作在空中失敗則進行錯誤處理,以及中間狀態的日誌記錄。 任何複雜程度的密碼保護PDF都不受支持。

IronOCR方法

IronOCR的PDF支持直接載入文件並同步處理:

public string ProcessPdf(string pdfPath)
{
    // DirectPDF處理- no GCS, no async, no cleanup
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return _ocr.Read(input).Text;
}

public string ProcessPdfPages(string pdfPath, int startPage, int endPage)
{
    // Process specific page range
    using var input = new OcrInput();
    input.LoadPdfPages(pdfPath, startPage, endPage);
    return _ocr.Read(input).Text;
}

public string ProcessEncryptedPdf(string pdfPath, string password)
{
    // Password-protected PDFs - not possible with Google Cloud Vision
    using var input = new OcrInput();
    input.LoadPdf(pdfPath, Password: password);
    return _ocr.Read(input).Text;
}
public string ProcessPdf(string pdfPath)
{
    // DirectPDF處理- no GCS, no async, no cleanup
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return _ocr.Read(input).Text;
}

public string ProcessPdfPages(string pdfPath, int startPage, int endPage)
{
    // Process specific page range
    using var input = new OcrInput();
    input.LoadPdfPages(pdfPath, startPage, endPage);
    return _ocr.Read(input).Text;
}

public string ProcessEncryptedPdf(string pdfPath, string password)
{
    // Password-protected PDFs - not possible with Google Cloud Vision
    using var input = new OcrInput();
    input.LoadPdf(pdfPath, Password: password);
    return _ocr.Read(input).Text;
}
Imports System

Public Class PdfProcessor
    Public Function ProcessPdf(pdfPath As String) As String
        ' DirectPDF處理- no GCS, no async, no cleanup
        Using input As New OcrInput()
            input.LoadPdf(pdfPath)
            Return _ocr.Read(input).Text
        End Using
    End Function

    Public Function ProcessPdfPages(pdfPath As String, startPage As Integer, endPage As Integer) As String
        ' Process specific page range
        Using input As New OcrInput()
            input.LoadPdfPages(pdfPath, startPage, endPage)
            Return _ocr.Read(input).Text
        End Using
    End Function

    Public Function ProcessEncryptedPdf(pdfPath As String, password As String) As String
        ' Password-protected PDFs - not possible with Google Cloud Vision
        Using input As New OcrInput()
            input.LoadPdf(pdfPath, Password:=password)
            Return _ocr.Read(input).Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

無需第二個NuGet套件。 無需提供或維護GCS儲存桶。 無清理步驟、無非同步狀態機。受密碼保護的變體僅增加一個參數。 對於需要從掃描輸入生成可搜尋PDF的團隊,result.SaveAsSearchablePdf("output.pdf")在一行附加行中處理可搜尋PDF輸出——Google Cloud Vision在任何API複雜程度下都未提供的功能。

Protobuf響應解析 vs 平面OcrResult

DOCUMENT_TEXT_DETECTION調用獲取結構化資料需要導航Protobuf響應層次結構。 從API調用到段落文字的路徑通過五個巢狀迭代的層次。

Google Cloud Vision的方法

從密集文件中提取段落文字需要遍歷頁面,然後是塊,然後是段落,然後從每個詞中串聯符號——因為Protobuf設計將文字儲存在符號層,而不是詞或段落層:

public DocumentStructure ExtractDocumentStructure(string imagePath)
{
    var image = Image.FromFile(imagePath);
    var annotation = _client.DetectDocumentText(image);

    var structure = new DocumentStructure
    {
        FullText = annotation.Text,
        Pages = new List<PageInfo>()
    };

    // Navigate: Pages -> Blocks -> Paragraphs -> Words -> Symbols
    foreach (var page in annotation.Pages)
    {
        var pageInfo = new PageInfo
        {
            Confidence = page.Confidence,
            Paragraphs = new List<ParagraphInfo>()
        };

        foreach (var block in page.Blocks)
        {
            foreach (var paragraph in block.Paragraphs)
            {
                // Must concatenate symbols to get paragraph text
                var text = string.Join("", paragraph.Words
                    .SelectMany(w => w.Symbols)
                    .Select(s => s.Text));

                pageInfo.Paragraphs.Add(new ParagraphInfo
                {
                    Text = text,
                    Confidence = paragraph.Confidence
                });
            }
        }
        structure.Pages.Add(pageInfo);
    }

    return structure;
}
public DocumentStructure ExtractDocumentStructure(string imagePath)
{
    var image = Image.FromFile(imagePath);
    var annotation = _client.DetectDocumentText(image);

    var structure = new DocumentStructure
    {
        FullText = annotation.Text,
        Pages = new List<PageInfo>()
    };

    // Navigate: Pages -> Blocks -> Paragraphs -> Words -> Symbols
    foreach (var page in annotation.Pages)
    {
        var pageInfo = new PageInfo
        {
            Confidence = page.Confidence,
            Paragraphs = new List<ParagraphInfo>()
        };

        foreach (var block in page.Blocks)
        {
            foreach (var paragraph in block.Paragraphs)
            {
                // Must concatenate symbols to get paragraph text
                var text = string.Join("", paragraph.Words
                    .SelectMany(w => w.Symbols)
                    .Select(s => s.Text));

                pageInfo.Paragraphs.Add(new ParagraphInfo
                {
                    Text = text,
                    Confidence = paragraph.Confidence
                });
            }
        }
        structure.Pages.Add(pageInfo);
    }

    return structure;
}
Imports System.Drawing

Public Function ExtractDocumentStructure(imagePath As String) As DocumentStructure
    Dim image = Image.FromFile(imagePath)
    Dim annotation = _client.DetectDocumentText(image)

    Dim structure As New DocumentStructure With {
        .FullText = annotation.Text,
        .Pages = New List(Of PageInfo)()
    }

    ' Navigate: Pages -> Blocks -> Paragraphs -> Words -> Symbols
    For Each page In annotation.Pages
        Dim pageInfo As New PageInfo With {
            .Confidence = page.Confidence,
            .Paragraphs = New List(Of ParagraphInfo)()
        }

        For Each block In page.Blocks
            For Each paragraph In block.Paragraphs
                ' Must concatenate symbols to get paragraph text
                Dim text = String.Join("", paragraph.Words _
                    .SelectMany(Function(w) w.Symbols) _
                    .Select(Function(s) s.Text))

                pageInfo.Paragraphs.Add(New ParagraphInfo With {
                    .Text = text,
                    .Confidence = paragraph.Confidence
                })
            Next
        Next
        structure.Pages.Add(pageInfo)
    Next

    Return structure
End Function
$vbLabelText   $csharpLabel

符號級串聯不是可選的——paragraph.Text不存在於Protobuf響應中的直接屬性。 使用此API的每個團隊都編寫了自己版本的相同巢狀迴圈聚合。 字級置信度需要第六級迭代以存取word.Confidence值,然後將它們映射回符號串聯結果。

IronOCR方法

IronOCR的OcrResult提供平面型別化API。 Height都已準備好使用:

public DocumentStructure ExtractDocumentStructure(string imagePath)
{
    var result = _ocr.Read(imagePath);

    // Direct access - no symbol concatenation, no nested loops
    return new DocumentStructure
    {
        FullText = result.Text,
        Confidence = result.Confidence,
        Paragraphs = result.Paragraphs.Select(p => new ParagraphInfo
        {
            Text = p.Text,
            Confidence = p.Confidence
        }).ToList(),
        Lines = result.Lines.Select(l => new LineInfo
        {
            Text = l.Text,
            X = l.X,
            Y = l.Y
        }).ToList()
    };
}
public DocumentStructure ExtractDocumentStructure(string imagePath)
{
    var result = _ocr.Read(imagePath);

    // Direct access - no symbol concatenation, no nested loops
    return new DocumentStructure
    {
        FullText = result.Text,
        Confidence = result.Confidence,
        Paragraphs = result.Paragraphs.Select(p => new ParagraphInfo
        {
            Text = p.Text,
            Confidence = p.Confidence
        }).ToList(),
        Lines = result.Lines.Select(l => new LineInfo
        {
            Text = l.Text,
            X = l.X,
            Y = l.Y
        }).ToList()
    };
}
Public Function ExtractDocumentStructure(imagePath As String) As DocumentStructure
    Dim result = _ocr.Read(imagePath)

    ' Direct access - no symbol concatenation, no nested loops
    Return New DocumentStructure With {
        .FullText = result.Text,
        .Confidence = result.Confidence,
        .Paragraphs = result.Paragraphs.Select(Function(p) New ParagraphInfo With {
            .Text = p.Text,
            .Confidence = p.Confidence
        }).ToList(),
        .Lines = result.Lines.Select(Function(l) New LineInfo With {
            .Text = l.Text,
            .X = l.X,
            .Y = l.Y
        }).ToList()
    }
End Function
$vbLabelText   $csharpLabel

讀取結果指南涵蓋口結構化資料API的完整結構。 result.Words[i].Confidence中可用單詞級定位和置信度分數,無需導航中間層次結構。 對於區域特定提取,基於區域的OCR使用OcrInput上,當僅需要標題行或特定字段時,可以避免處理整個圖像。

成本模型:每圖片計費vs永久授權

成本比較在很大程度上取決於批量和時間範圍。

Google Cloud Vision的方法

Google Cloud Vision定價基於使用量,並根據功能型別和批量而有所差異。 請參照Google Cloud Vision定價頁面查詢當前利率。 請注意,總成本還可能包括PDF工作流的GCS儲存和操作費用、網路出口成本,以及憑證管理和密鑰輪換的工程時間。

在高文件量的情況下,每張圖片費用顯著累積,隨著批量增長而線性增長,除非您協商了一份承諾使用協議。

IronOCR方法

IronOCR定價為一次性永久購買:$999 Lite(1名開發者)、$1,499 Plus(3名開發者)、$2,999 Professional(10名開發者)、$5,999 Unlimited。 許可涵蓋無限文件處理,無需計量。 第二年成本為零。 第三年成本為零。 在高文件量的情況下,IronOCR永久授權的成本效益快速超過每圖片雲端定價。 請參閱IronOCR授權頁面獲取當前層級詳情。

IronOCR比Google Cloud Vision便宜的交叉點取決於您的量和Google的當前定價。 對於大多數在生產中持續處理文件的團隊來說,IronOCR的永久授權在使用的前幾個月內即已回本。

API 地圖參考

Google Cloud Vision IronOCR 注意事項
ImageAnnotatorClient.Create() new IronTesseract() 客戶端初始化
_client.DetectText(image) _ocr.Read(imagePath).Text 基本文字提取
_client.DetectDocumentText(image) _ocr.Read(imagePath) 密集文件OCR
AsyncBatchAnnotateFilesAsync() input.LoadPdf(); _ocr.Read(input) PDF處理
StorageClient.Create() 不需要 IronOCR中不需要GCS
storageClient.UploadObjectAsync() 不需要 PDF直接載入
operation.PollUntilCompletedAsync() 不需要 處理是同步的
TextAnnotation OcrResult 結果容器
annotation.Text result.Text 完整文件文字
annotation.Pages[i] result.Pages[i] 逐頁存取
page.Blocks[i].Paragraphs[j] result.Paragraphs[i] 段落存取
paragraph.Words.SelectMany(w => w.Symbols).Select(s => s.Text) paragraph.Text 直接文字屬性
word.Confidence word.Confidence 每字信心
page.Confidence result.Confidence 整體信心
Feature.Types.Type.DocumentTextDetection 自動 IronOCR自動選擇模式
Image.FromFile(path) input.LoadImage(path) 圖像載入
response[0].Description result.Text 全部文字提取
annotation.BoundingPoly.Vertices word.X, word.Y, word.Width, word.Height 邊界坐標
RpcException (StatusCode.ResourceExhausted) 不適用 本地無速率限制
RpcException (StatusCode.PermissionDenied) 不適用 運行時無驗證

當團隊考慮從Google Cloud Vision轉移到IronOCR時

合規要求阻止雲處理

最常見的遷移觸發點不是成本,而是合規審核。 政府承包商遭遇ITAR限制,發現將受控技術資料傳輸到Google Cloud是禁止的。 構建文件處理管道的醫療保健機構發現,他們的HIPAA安全官需要對每個資料處理器進行企業夥伴協議審查,而對Google雲操作範圍的評估超出了他們風險承受能力。 處理託管客戶文件的法律部門認為,律師與客戶之間的特權問題超過了雲計算的便利性。 國防承包商遇到將任何資料從公司邊界轉移視為安全風險的CMMC要求。 在所有這些場景中,Google的ML模型的技術品質是無關緊要的——架構本身就是不合格的原因。 IronOCR的本地模型消除了整個第三方資料處理器合規性類別,因為在處理過程中沒有第三方參與。

PDF 工作流在規模下變得無法管理

從Google Cloud Vision開始圖像OCR的團隊通常會發現當需要擴展範圍時的PDF複雜性。 使用GCS非同步管道處理每天200個PDF是可行的,但痛苦的。 每天處理10,000個PDF需要對整個管道進行強化:GCS上傳失敗的重試邏輯、從未完成的操作的死信隊列、應用程式在中途崩潰時孤立GCS物件的清理工作,以及Vision API成本和GCS儲存成本的監控。 在這種規模上運作的團隊一致認為IronOCR的遷移是直接的——整個非同步GCS管道崩潰為直接本地文件載入,之後進行單次讀取調用,故障模式從網路超時、驗證故障、GCS配額錯誤和JSON解析異常縮減為僅本地文件I/O異常。

預算可預測性比每圖片靈活性更重要

早期階段的專案經常選擇Google Cloud Vision,因為免費層吸收了初始開發成本,並且當沒有任何處理時,每圖片模型按需擴展到零。 一旦產品達到穩定的生產量——通常超過每月50,000份文件——財務團隊注意到定期的支出。 不同於隨業務增長的SaaS訂閱,IronOCR的永久授權將OCR從可變的運營成本轉變為固定的資本支出。 對於處理文件的受監管行業的10名開發者團隊來說,Professional授權在$2,999一次性,通常在與持續的每圖片雲定價比較的生產量的第一季就得到了正當化。

批處理達到速率限制

文件密集化的工作流——法律發現、財務文件數字化、保險索賠處理——通常需要每小時處理數千個文件。 Google Cloud Vision每分鐘1,800請求的預設配額意味著3,000份文件的爆發會觸發速率限制,並且需要通過GCP控制台請求配額增加(涉及等待Google的批准),或實施隨機抖動的指數退避。 單次配額超限會讓整個處理流程停滯,需等候60秒後才可重試。 IronOCR的本地處理僅受限於可用的CPU核心,並平行處理不需要外部批准。

需要空隙部署

有些環境在設計上不具備出站互聯網連接:機密軍事網路、工業控制系統、金融清算的安全資料中心。 在任何架構創造力層面,Google Cloud Vision都無法在這些環境中運行——API需要與Googler的端點進行網路互通。 IronOCR的Docker部署無需出站連接即可運行。 第一次使用後,授權金鑰將被驗證並快取; 隨後使用不需要網路存取。

常見的遷移考量

移除GCS依賴

遷移時最重要的結構變更是完全消除GCS管道。 在移除Google包之前,記錄為OCR輸入和輸出的每個GCS儲存桶,並清理它們以避免持續的儲存費用。 應從所有部署配置、CI/CD秘密及開發者機上刪除GOOGLE_APPLICATION_CREDENTIALS環境變數和JSON金鑰文件。 在確認沒有其他服務依賴後,GCP控制台中的IAM服務帳戶可以被禁用或刪除。

在移除LoadPdf。 錯誤處理合約變化:網路異常、驗證異常和速率限制異常全部消失。 剩餘的例外是文件I/O例外(文件未找到、文件被鎖定)和OcrException處理失敗。 IronOCR圖像輸入指南PDF輸入指南涵蓋了完整的輸入API,包括流、字節陣列和URL載入。

Protobuf符號串聯到直接文字存取

在程式碼庫中,您寫了.SelectMany(w => w.Symbols).Select(s => s.Text)以從Protobuf層次結構提取段或單詞文字的每個位置都成為直接屬性存取。 word.Text作為IronOCR結果物件上的型別化字串屬性存在。 檢討所有結構化資料提取程式碼,並移除中介聚合邏輯。 如何閱讀結果指南映射出OcrResult.Word上可用的每個屬性。

非同步到同步的PDF工作流過渡

Google Cloud Vision的PDF處理是僅非同步的,因為操作需要通過GCS的往返。 IronOCR的Read方法是同步的。 如果您的應用的PDF處理層構建在Task.Run包裝:

public async Task<string> ProcessPdfAsync(string pdfPath)
{
    return await Task.Run(() =>
    {
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);
        return _ocr.Read(input).Text;
    });
}
public async Task<string> ProcessPdfAsync(string pdfPath)
{
    return await Task.Run(() =>
    {
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);
        return _ocr.Read(input).Text;
    });
}
Imports System.Threading.Tasks

Public Async Function ProcessPdfAsync(pdfPath As String) As Task(Of String)
    Return Await Task.Run(Function()
                              Using input As New OcrInput()
                                  input.LoadPdf(pdfPath)
                                  Return _ocr.Read(input).Text
                              End Using
                          End Function)
End Function
$vbLabelText   $csharpLabel

這保留了呼叫者的非同步接口,同時在執行緒池上執行OCR工作。 對於高吞吐量場景,IronOCR的內建非同步OCR支持原生處理此模式,而不需要Task.Run包裝。

針對Google的ML處理的圖像的預處理

Google Cloud Vision的ML支持模型在某些圖像質量問題——低對比度、小偏斜、中等噪聲——上無需顯式預處理配置即可處理。 包括IronOCR在內的Tesseract基引擎受益於在降質輸入上的明確預處理。 如果您的文件集包括低質量掃描,新增input.EnhanceResolution(300)到輸入管道。IronOCR的自動預處理會在檢查到圖像質量問題時智能應用這些過濾器,但對於已知問題的掃描來源,顯式過濾器應用可提供確定性結果。 圖像質量校正指南涵蓋完整過濾器API,圖像色彩校正指南為光照不均或墨水褪色的掃描提供對比度和二值化的處理措施。

其他IronOCR功能

以上比較中所覆蓋功能之外,IronOCR提供Google Cloud Vision的OCR表面完全無可匹敵的能力:

  • hOCR匯出:將結果保存為hOCR文件,result.SaveAsHocrFile()可供下游使用hOCR格式的工具使用。
  • 批次作業的進度追蹤:可透過進度追蹤API回報每份文件的完成情況,無需輪詢隊列或解析日誌輸出至長期運行的批次工作負載。
  • 特定文件型別:IronOCR包括為護照、車牌、MICR支票和手寫文件的預調整配置——這些文件型別需要超出一般OCR之外的特定引擎調整。
  • 從文件中提取表格:可以將掃描文件中的結構化表格資料提取為行列輸出,無需對原始文字流進行後處理。
  • 圖像色彩校正:對比度正規化、二值化閾值調整和灰階轉換可作為掃描光線不均或墨水褪色的顯式預處理步驟。

.NET 相容性和未來準備

IronOCR專注於.NET 8和.NET 9,擁有主動支持,並支持.NET Framework 4.6.2至4.8和.NET Standard 2.0的舊版程式碼庫。 部署指南覆蓋WindowsLinuxmacOSDockerAzureAWS Lambda—同一NuGet包在所有這些中進行部署,無需特定於平臺的配置。 作為一個REST/gRPC API,Google Cloud Vision本身沒有.NET版本依賴關係,但Google.Cloud.Vision.V1客戶端庫專門支持.NET Standard 2.0及更高版本,其依賴樹(gRPC,Protobuf)則隨著這些庫每個主要版本的增加而增長NuGet包管理介面。

結論

Google Cloud Vision是一個技術能力強大的OCR服務,具有真正優勢:其ML支持的模型在CJK文字、手寫和自然場景圖像上表現良好,DOCUMENT_TEXT_DETECTION功能的分層Protobuf輸出為需要它的用例提供精細的符號級別資料。 這些優勢在適當的上下文中很重要,但架構約束——強制雲傳輸、JSON密鑰文件憑證管理、GCS依賴的PDF處理、每圖片計費、1,800每分鐘請求的速率限制,以及FedRAMP授權的缺失——不是可配置的旋鈕能消除的。 這些是雲API的基本屬性。

IronOCR的本地模型幾乎顛覆了其中每一個限制。 文件絕不會離開處理伺服器。 授權金鑰代替JSON密鑰文件和服務帳戶IAM配置。 PDF處理是一個三行同步操作。 沒有速率限制,無需提供GCS儲存桶,無需非同步輪詢迴圈,也無需Protobuf反序列化。 OcrResult物件將結構化資料顯露為型別化.NET屬性,而不是作為需要符號串聯以閱讀段落文字的Protobuf層次結構。

決策減少到單個關於架構的問題。 如果您的文件可以移動到Google的基礎設施而不涉及合規性、法規或合同問題,且您的數量低到每圖片成本是可接受的,Google Cloud Vision的ML精度和託管基礎設施就是正確的優點。 如果文件必須保留在本地——出於HIPAA、ITAR、CMMC、政府承包商要求、空隙部署或資料主權政策——在評估任何其他功能之前,該問題已經有了答案。 IronOCR的永久授權還將OCR從隨文件量擴大的可變成本轉換為固定預算項目,這在生產規模上大大簡化了預算規劃。

對於評估遷移的團隊,IronOCR文件和教程中心提供完整的API範圍覆蓋,包括超出Google Cloud Vision的OCR範圍外的預處理、結構化資料和專門文件功能。

請注意AWS Textract,Azure Computer Vision,Google Cloud Vision和Tesseract是各自所有者的注冊商標。 此網站與Amazon Web Services、Google或Microsoft無關,也未受到其認可或贊助。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供資訊用途,並反映撰寫時獲得的公開資訊。

常見問題

什麼是Google Cloud Vision API?

Google Cloud Vision API是一個OCR解決方案,供開發人員和企業用來從影像和文件中提取文字。它是與IronOCR一同評估的多個OCR選項之一,用於.NET應用程式開發。

IronOCR如何與Google Cloud Vision API為.NET開發人員比較?

IronOCR是一個NuGet原生的.NET OCR程式庫,使用IronTesseract作為其核心引擎。相比Google Cloud Vision API,它提供更簡單的部署(無需SDK安裝程式)、固定價格,以及乾淨的C# API,無需COM互操作或雲端依賴。

IronOCR是否比Google Cloud Vision API更容易設置?

IronOCR 通過一個單一的 NuGet 套件安裝。無需 SDK 安裝程式、複製授權文件、註冊 COM 元件或管理單獨的運行時二進位檔案。整個 OCR 引擎都打包在套件中。

Google Cloud Vision API和IronOCR之間的準確性有什麼不同?

IronOCR 在標準商業文件、發票、收據和掃描表單上達到了高識別準確度。對於極度退化的文件或罕見文字,準確度會根據來源品質變化。IronOCR 包含影像預處理篩選器,以改善低品質輸入的識別。

IronOCR 支援 PDF 文字提取嗎?

是的。IronOCR 能從原生 PDF 和掃描的 PDF 圖像中一次性提取文字。它還支持多頁 TIFF 檔案、影像和流。對於掃描的 PDF,OCR 會逐頁應用並生成每頁的結果物件。

Google Cloud Vision API的授權模式如何與IronOCR相比?

IronOCR 採用固定費率的永久授權,無須為每頁或每次掃描支付費用。處理大量文件的組織無論數量多少都支付相同的授權費用。詳細資訊和批量定價在 IronOCR 授權頁面上。

IronOCR 支援哪些語言?

IronOCR 透過單獨的 NuGet 語言包支持 127 種語言。新增一種語言只需一個 'dotnet add package IronOcr.Languages.{Language}' 命令。無需手動放置文件或配置路徑。

如何在.NET專案中安裝IronOCR?

通過 NuGet 安裝:在套件管理員控制台或 CLI 中分別使用 'Install-Package IronOcr' 或 'dotnet add package IronOcr'。其他語言包也是這樣安裝的。無需本地 SDK 安裝程式。

IronOCR是否適合Docker和容器化部署,而不像Google Cloud Vision那樣?

是的。IronOCR 通過其 NuGet 載於 Docker 容器中運行。授權金鑰通過環境變數設置。無需授權文件、SDK 路徑或量掛載來執行 OCR 引擎。

我可以在購買之前試用IronOCR,相比Google Cloud Vision嗎?

是的。IronOCR 試用模式中處理文件並在輸出上附上浮水印結果。您可以在購買授權前驗證自己文件的準確性。

IronOCR 支援條碼閱讀與文字提取嗎?

IronOCR 專注於文字提取和 OCR。對於條碼閱讀,Iron Software 提供了額外的 IronBarcode 程式庫。兩者均可個別使用或作為 Iron Suite 套件的一部分。

從Google Cloud Vision API遷移到IronOCR是否容易?

從Google Cloud Vision API遷移到IronOCR通常涉及替換初始化序列為IronTesseract實例化,移除COM生命周期管理,並更新API呼叫。大多數遷移大幅降低程式複雜性。

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

Iron 支援團隊

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