Para llamar a una API de Google Cloud desde tu app, debes crear una API de REST intermedia que maneje la autorización y proteja los valores secretos, como las claves de API. Luego, debes escribir código en tu app para dispositivos móviles a fin de autenticarte en este servicio intermedio y comunicarte con él.
Una forma de crear esta API de REST es usar Firebase Authentication y Functions, lo que te brinda una puerta de enlace administrada y sin servidores a las APIs de Google Cloud que controla la autenticación y se puede llamar desde tu app para dispositivos móviles con SDK precompilados.
En esta guía, se muestra cómo usar esta técnica para llamar a la API de Cloud Vision desde tu app. Este método permitirá que todos los usuarios autenticados accedan a los servicios facturados de Cloud Vision a través de tu proyecto de Cloud, por lo que debes considerar si este mecanismo de autenticación es suficiente para tu caso de uso antes de continuar.
Antes de comenzar
Configura tu proyecto
Si aún no has agregado Firebase a tu app, sigue los pasos en la guía de introducción para hacerlo.Usa Swift Package Manager para instalar y administrar las dependencias de Firebase.
- En Xcode, con tu proyecto de app abierto, navega a File > Add Packages.
- Cuando se te solicite, agrega el repositorio del SDK de Firebase para plataformas de Apple:
- Elige la biblioteca de Firebase ML.
- Agrega la marca
-ObjC
a la sección Other Linker Flags de la configuración de compilación de tu destino. - Cuando termines, Xcode comenzará a resolver y descargar automáticamente tus dependencias en segundo plano.
https://github.com/firebase/firebase-ios-sdk.git
A continuación, realiza la configuración en la app:
- En tu app, importa Firebase:
Swift
import FirebaseMLModelDownloader
Objective-C
@import FirebaseMLModelDownloader;
Quedan unos pocos pasos de configuración para terminar:
-
Si aún no habilitaste las APIs de Cloud en tu proyecto, hazlo de la siguiente manera:
- Abre la Firebase ML Página de APIs de Firebase console.
-
Si todavía no actualizaste tu proyecto a un plan de precios Blaze, haz clic en Actualizar para hacerlo (se te pedirá que realices la actualización únicamente si tu proyecto no está en el plan Blaze).
Solo los proyectos con un plan Blaze pueden usar las APIs de Cloud.
- Si las APIs de Cloud no están habilitadas, haz clic en Habilitar las APIs de Cloud.
- Configura tus claves de API de Firebase existentes para inhabilitar el acceso a la API de Cloud Vision siguiendo los pasos que se indican a continuación:
- Abre la página Credenciales de la consola de Cloud.
- Para cada clave de API de la lista, abre la vista de edición y, en la sección Restricciones de claves, agrega a la lista todas las APIs disponibles excepto la de Cloud Vision.
Implementa la función que admite llamadas
A continuación, implementa la Cloud Function que usarás para conectar tu app y la API de Cloud Vision. El repositorio functions-samples
contiene un ejemplo
que puedes usar.
De forma predeterminada, el acceso a la API de Cloud Vision a través de esta función permitirá que solo los usuarios autenticados de tu app accedan a la API de Cloud Vision. Puedes modificar la función para diferentes requisitos.
Sigue estos pasos para implementar la función:
- Clona o descarga functions-samples repo
y cambia al directorio
Node-1st-gen/vision-annotate-image
:git clone https://github.com/firebase/functions-samples
cd Node-1st-gen/vision-annotate-image
- Instala las dependencias:
cd functions
npm install
cd ..
- Si no tienes Firebase CLI, instálalo.
- Inicializa un proyecto de Firebase en el directorio
vision-annotate-image
. Cuando se te solicite, selecciona tu proyecto en la lista.firebase init
- Sigue estos pasos para implementar la función:
firebase deploy --only functions:annotateImage
Agrega Firebase Auth a tu app
La función que admite llamadas implementada anteriormente rechazará todas las solicitudes de usuarios no autenticados de tu app. Si aún no lo has hecho, tendrás que agregar Firebase Auth a tu app.
Agrega las dependencias necesarias a tu app
Usa Swift Package Manager para instalar la biblioteca de Cloud Functions para Firebase.
Ya estás listo para comenzar a reconocer texto en imágenes.
1. Prepara la imagen de entrada
Para llamar a Cloud Vision, la imagen debe tener el formato de una string codificada en base64. Para procesar unaUIImage
, sigue estos pasos:
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. Invoca la función que admite llamadas para reconocer texto
Para reconocer puntos de referencia en una imagen, invoca la función que admite llamadas pasando una solicitud de JSON de Cloud Vision.Primero, inicializa una instancia de Cloud Functions:
Swift
lazy var functions = Functions.functions()
Objective-C
@property(strong, nonatomic) FIRFunctions *functions;
Crea la solicitud. La API de Cloud Vision es compatible con dos Tipos de detección de texto:
TEXT_DETECTION
yDOCUMENT_TEXT_DETECTION
. Consulta la documentación de OCR de Cloud Vision para ver la diferencia entre los dos casos de uso.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"]} };
Finalmente, invoca la función:
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. Extrae texto de bloques de texto reconocido
Si la operación de reconocimiento de texto se ejecuta correctamente, se mostrará una respuesta JSON de BatchAnnotateImagesResponse en el resultado de la tarea. Las anotaciones de texto se pueden encontrar en el objeto fullTextAnnotation
.
Puedes obtener el texto reconocido como una string en el campo text
. Por ejemplo:
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"]);
También puedes obtener información específica de las regiones de la imagen. Para cada block
, paragraph
, word
y symbol
puedes obtener el texto reconocido en la región y las coordenadas que limitan la región. Por ejemplo:
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];
}
}