如要從應用程式呼叫 Google Cloud API,您必須建立用於處理授權並保護密鑰值 (例如 API 金鑰) 的中繼 REST API。接著,您必須在行動應用程式中編寫程式碼,以便驗證這個中繼服務並與其通訊。
建立此 REST API 的其中一種方法是使用 Firebase 驗證和函式。這個 API 為 Google Cloud API 提供代管的無伺服器閘道,可處理驗證作業,並透過預先建構的 SDK 從行動應用程式呼叫。
本指南示範如何使用這項技巧,從應用程式呼叫 Cloud Vision API。這個方法會允許所有通過驗證的使用者透過您的 Cloud 專案存取 Cloud Vision 付費服務,因此請先評估這項驗證機制是否足以滿足您的用途,再繼續操作。
事前準備
設定專案
使用 Swift Package Manager 安裝及管理 Firebase 依附元件。
- 在 Xcode 中保持開啟應用程式專案,然後依序點選「File」>「Add Packages」。
- 在系統提示時,新增 Firebase Apple 平台 SDK 存放區:
- 選擇 Firebase ML 程式庫。
- 在目標建構設定的「Other Linker Flags」部分中新增
-ObjC
標記。 - 完成後,Xcode 會自動開始在背景解析並下載依附元件。
https://github.com/firebase/firebase-ios-sdk.git
接下來,進行一些應用程式內設定:
- 在應用程式中匯入 Firebase:
Swift
import FirebaseMLModelDownloader
Objective-C
@import FirebaseMLModelDownloader;
還差幾個步驟就可以開始使用了:
-
如果您尚未為專案啟用雲端式 API,請立即啟用:
- 開啟 Firebase 控制台的 Firebase ML API 頁面。
-
如果您尚未將專案升級至 Blaze 定價方案,按一下「升級」即可進行升級 (只有在專案未採用 Blaze 方案時,系統才會提示您升級)。
只有 Blaze 層級的專案可以使用以雲端為基礎的 API。
- 如果雲端型 API 尚未啟用,請點選「啟用雲端式 API」。
- 設定現有的 Firebase API 金鑰以禁止存取 Cloud Vision API:
部署可呼叫函式
接下來,請部署要用來橋接應用程式和 Cloud Vision API 的 Cloud 函式。functions-samples
存放區包含可使用的範例。
根據預設,透過此函式存取 Cloud Vision API,只會允許經過驗證的應用程式使用者存取 Cloud Vision API。您可以依據不同的需求修改函式。
如何部署函式:
- 複製或下載 functions-samples 存放區,並變更為
Node-1st-gen/vision-annotate-image
目錄:git clone https://github.com/firebase/functions-samples
cd Node-1st-gen/vision-annotate-image
- 安裝依附元件:
cd functions
npm install
cd ..
- 如果沒有 Firebase CLI,請安裝。
- 初始化
vision-annotate-image
目錄中的 Firebase 專案。系統出現提示時,請在清單中選取您的專案。firebase init
- 部署函式:
firebase deploy --only functions:annotateImage
將 Firebase 驗證新增至應用程式
上方部署的可呼叫函式會拒絕應用程式中未經驗證使用者的任何要求。如果您尚未這麼做,您必須將 Firebase 驗證新增至應用程式。
為應用程式新增必要的依附元件
使用 Swift Package Manager 安裝 Cloud Functions for Firebase 程式庫。
現在可以開始辨識圖片中的文字。
1. 準備輸入圖片
為了呼叫 Cloud Vision,圖片必須採用 Base64 編碼字串格式。如何處理UIImage
:Swift
guard let imageData = uiImage.jpegData(compressionQuality: 1.0) else { return } let base64encodedImage = imageData.base64EncodedString()
Objective-C
NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f); NSString *base64encodedImage = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
2. 叫用可呼叫的函式來辨識文字
為了辨識圖片中的地標,請叫用傳遞 JSON Cloud Vision 要求的可呼叫函式。首先,請初始化 Cloud Functions 的執行個體:
Swift
lazy var functions = Functions.functions()
Objective-C
@property(strong, nonatomic) FIRFunctions *functions;
建立要求。Cloud Vision API 支援兩種文字偵測類型:
TEXT_DETECTION
和DOCUMENT_TEXT_DETECTION
。如要瞭解這兩種用途的差異,請參閱 Cloud Vision OCR 文件。Swift
let requestData = [ "image": ["content": base64encodedImage], "features": ["type": "TEXT_DETECTION"], "imageContext": ["languageHints": ["en"]] ]
Objective-C
NSDictionary *requestData = @{ @"image": @{@"content": base64encodedImage}, @"features": @{@"type": @"TEXT_DETECTION"}, @"imageContext": @{@"languageHints": @[@"en"]} };
最後,叫用函式:
Swift
do { let result = try await functions.httpsCallable("annotateImage").call(requestData) print(result) } catch { if let error = error as NSError? { if error.domain == FunctionsErrorDomain { let code = FunctionsErrorCode(rawValue: error.code) let message = error.localizedDescription let details = error.userInfo[FunctionsErrorDetailsKey] } // ... } }
Objective-C
[[_functions HTTPSCallableWithName:@"annotateImage"] callWithObject:requestData completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) { if (error) { if ([error.domain isEqualToString:@"com.firebase.functions"]) { FIRFunctionsErrorCode code = error.code; NSString *message = error.localizedDescription; NSObject *details = error.userInfo[@"details"]; } // ... } // Function completed succesfully // Get information about labeled objects }];
3. 從已辨識的文字區塊擷取文字
如果文字辨識作業成功,工作結果中會傳回 BatchAnnotateImagesResponse 的 JSON 回應。您可以在 fullTextAnnotation
物件中找到文字註解。
您可以在 text
欄位中以字串形式取得辨識的文字。例如:
Swift
let annotation = result.flatMap { $0.data as? [String: Any] }
.flatMap { $0["fullTextAnnotation"] }
.flatMap { $0 as? [String: Any] }
guard let annotation = annotation else { return }
if let text = annotation["text"] as? String {
print("Complete annotation: \(text)")
}
Objective-C
NSDictionary *annotation = result.data[@"fullTextAnnotation"];
if (!annotation) { return; }
NSLog(@"\nComplete annotation:");
NSLog(@"\n%@", annotation[@"text"]);
您也可以取得圖片各區域的相關資訊。對於每個 block
、paragraph
、word
和 symbol
,您可以取得在區域辨識的文字和區域邊界座標。例如:
Swift
guard let pages = annotation["pages"] as? [[String: Any]] else { return }
for page in pages {
var pageText = ""
guard let blocks = page["blocks"] as? [[String: Any]] else { continue }
for block in blocks {
var blockText = ""
guard let paragraphs = block["paragraphs"] as? [[String: Any]] else { continue }
for paragraph in paragraphs {
var paragraphText = ""
guard let words = paragraph["words"] as? [[String: Any]] else { continue }
for word in words {
var wordText = ""
guard let symbols = word["symbols"] as? [[String: Any]] else { continue }
for symbol in symbols {
let text = symbol["text"] as? String ?? ""
let confidence = symbol["confidence"] as? Float ?? 0.0
wordText += text
print("Symbol text: \(text) (confidence: \(confidence)%n")
}
let confidence = word["confidence"] as? Float ?? 0.0
print("Word text: \(wordText) (confidence: \(confidence)%n%n")
let boundingBox = word["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
print("Word bounding box: \(boundingBox.description)%n")
paragraphText += wordText
}
print("%nParagraph: %n\(paragraphText)%n")
let boundingBox = paragraph["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
print("Paragraph bounding box: \(boundingBox)%n")
let confidence = paragraph["confidence"] as? Float ?? 0.0
print("Paragraph Confidence: \(confidence)%n")
blockText += paragraphText
}
pageText += blockText
}
}
Objective-C
for (NSDictionary *page in annotation[@"pages"]) {
NSMutableString *pageText = [NSMutableString new];
for (NSDictionary *block in page[@"blocks"]) {
NSMutableString *blockText = [NSMutableString new];
for (NSDictionary *paragraph in block[@"paragraphs"]) {
NSMutableString *paragraphText = [NSMutableString new];
for (NSDictionary *word in paragraph[@"words"]) {
NSMutableString *wordText = [NSMutableString new];
for (NSDictionary *symbol in word[@"symbols"]) {
NSString *text = symbol[@"text"];
[wordText appendString:text];
NSLog(@"Symbol text: %@ (confidence: %@\n", text, symbol[@"confidence"]);
}
NSLog(@"Word text: %@ (confidence: %@\n\n", wordText, word[@"confidence"]);
NSLog(@"Word bounding box: %@\n", word[@"boundingBox"]);
[paragraphText appendString:wordText];
}
NSLog(@"\nParagraph: \n%@\n", paragraphText);
NSLog(@"Paragraph bounding box: %@\n", paragraph[@"boundingBox"]);
NSLog(@"Paragraph Confidence: %@\n", paragraph[@"confidence"]);
[blockText appendString:paragraphText];
}
[pageText appendString:blockText];
}
}