SwiftUI 框架

在 SwiftUI 利用 Live Text API 從圖片中擷取文本

去年,iOS 15 新增了 Live Text 這個非常有用的功能 。在 iOS 16,Apple 發佈了 Live Text API,讓開發者可以在自己的 App 中加入這個功能。在這篇教學文章中,讓我們一起來看看如何在 SwiftUI 中使用 Live Text API。
在 SwiftUI 利用 Live Text API 從圖片中擷取文本
Photo by Abdelrahman Wael on Unsplash
In: SwiftUI 框架, iOS 16

去年,iOS 15 新增了一個非常有用的功能 ── Live Text。你可能也有聽過 OCR(光學字元辨識的縮寫)一詞,這是一個將文本圖像轉換為機器可讀的文本格式的過程;這就是 Live Text 所做的事。

Live Text 內置在相機 App 和相片 App 中。如果你還沒有嘗試過這個功能,現在就來打開相機 App 試試吧!當我們把電話的鏡頭對准文本圖像,右下角就會出現一個 Live Text 按鈕。點擊按鈕後,iOS 就會自動擷取文本。然後,你就可以將其複制,並粘貼到其他 App(例如備忘錄 App)中。

對於使用者來說,這是一個非常強大又方便的功能。而對於開發者來說,我們都會希望把這個 Live Text 功能加到自己的 App 中。在 iOS 16,Apple 發佈了 Live Text API,讓開發者可以在自己的 App 中加入 Live Text 功能。在這篇教學文章中,讓我們一起來看看如何在 SwiftUI 中使用 Live Text API。

利用 DataScannerViewController 啟用 Live Text

在 WWDC 的 Capturing Machine-readable Codes and Text with VisionKit Session 中,Apple 工程師展示了以下圖片:

avfoundation-and-vision-framework

文本辨識 (Text Recognization) 不是 iOS 16 的新功能。在舊版本的 iOS 上,我們已經可以使用 AVFoundation 和 Vision 框架中的 API,來偵測和辨識文本。但是,實作起來十分複雜,尤其是對於那些剛接觸 iOS 開發的人來說。

在新版本的 iOS 中,以上所有的步驟都被簡化為 VisionKit 中的一個新類別 DataScannerViewController。我們在 App 內使用這個視圖控制器,就可以自動顯示有 Live Text 功能的相機 UI。

要使用這個類別,讓我們先匯入 VisionKit 框架,並檢查設備是否支援資料掃描器功能:

DataScannerViewController.isSupported

Live Text API 只支援 2018 年後推出、有 Neural Engine 的設備。另外,我們也要檢查 availability,來確保使用者批准 App 使用資料掃描器:

DataScannerViewController.isAvailable

通過兩項檢查後,我們就可以開始掃描了。讓我們看看以下範例程式碼,來啟用有 Live Text 功能的相機:

let dataScanner = DataScannerViewController(
                     recognizedDataTypes: [.text()],
                     qualityLevel: .balanced,
                     isHighlightingEnabled: true
                  )

present(dataScanner, animated: true) {
    try? dataScanner.startScanning()
}

我們只需要創建一個 DataScannerViewController 實例,並指定要辨識的資料型別即可。在範例中,我們要辨識的是文本,因此我們會把資料型別指定為 .text()。準備好實例之後,我們就可以調用 startScanning() 方法來開始掃描。

在 SwiftUI 使用 DataScannerViewController

DataScannerViewController 類別現時只支援 UIKit,因此在 SwiftUI 我們需要多做幾個步驟。我們需要採用 UIViewControllerRepresentable 協定,才可以在 SwiftUI 專案中使用這個類別。在這個情況下,讓我們創建一個新的 DataScanner 結構:

struct DataScanner: UIViewControllerRepresentable {
  .
  .
  .
}

這個結構會接受兩個 binding 變數 (variable):一個用於觸發資料掃描,另一個則用來儲存掃描到的文本的 binding。

@Binding var startScanning: Bool
@Binding var scanText: String

讓我們實作以下方法,來採用 UIViewControllerRepresentable 協定:

func makeUIViewController(context: Context) -> DataScannerViewController {
    let controller = DataScannerViewController(
                        recognizedDataTypes: [.text()],
                        qualityLevel: .balanced,
                        isHighlightingEnabled: true
                    )

    return controller
}

func updateUIViewController(_ uiViewController: DataScannerViewController, context: Context) {

    if startScanning {
        try? uiViewController.startScanning()
    } else {
        uiViewController.stopScanning()
    }
}

makeUIViewController 方法中,我們回傳了一個 DataScannerViewController 的實例。在 updateUIViewController 中,我們會根據 startScanning 的數值來開始或停止掃描。

然後,我們要實作以下的 DataScannerViewControllerDelegate 方法,來擷取掃描到的文本。

func dataScanner(_ dataScanner: DataScannerViewController, didTapOn item: RecognizedItem) {
  .
  .
  .
}

當使用者點擊偵測到的文本時,就會調用這個方法,因此我們會這樣實作它:

class Coordinator: NSObject, DataScannerViewControllerDelegate {
    var parent: DataScanner

    init(_ parent: DataScanner) {
        self.parent = parent
    }

    func dataScanner(_ dataScanner: DataScannerViewController, didTapOn item: RecognizedItem) {
        switch item {
        case .text(let text):
            parent.scanText = text.transcript
        default: break
        }
    }

}

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}

我們會檢查辨别到的物件,如果辨別到任何文本,就會把它儲存。最後,在 makeUIViewController 方法中插入這行程式碼來配置 delegate:

controller.delegate = context.coordinator

現在,控制器已經可以在 SwiftUI 視圖中使用了。

利用 DataScanner 擷取文本

舉個例子,我們會構建一個 UI 簡單的文本掃描器 App。在啟動 App 之後,它會自動顯示 Live Text 的相機視圖。當偵測到文本時,使用者可以點擊文本來擷取它。掃描到的文本會在顯示在螢幕的下半部分。

swiftui-live-text-demo

創建好一個標準的 SwiftUI 專案後,讓我們打開 ContentView.swiftVisionKit 框架。

import VisionKit

然後,我們要宣告幾個變數,來控制資料掃描器和掃描到的文本的操作。

@State private var startScanning = false
@State private var scanText = ""

body 的部分,讓我們這樣更新程式碼:

VStack(spacing: 0) {
    DataScanner(startScanning: $startScanning, scanText: $scanText)
        .frame(height: 400)

    Text(scanText)
        .frame(minWidth: 0, maxWidth: .infinity, maxHeight: .infinity)
        .background(in: Rectangle())
        .backgroundStyle(Color(uiColor: .systemGray6))

}
.task {
    if DataScannerViewController.isSupported && DataScannerViewController.isAvailable {
        startScanning.toggle()
    }
}

我們在 App 啟動時就開始啟用資料掃描器,但在此之前,我們需要調用 DataScannerViewController.isSupportedDataScannerViewController.isAvailable,來確保設備支援 Live Text。

這個範例 App 差不多完成了。因為 Live Text 需要相機的訪問權限,所以我們要到專案配置,在 Info.plist 檔案中添加 Privacy – Camera Usage Description Key,並說明 App 需要訪問相機的原因。

xcode-info-plist-enable-camera-access

完成後,我們可以在真實的 iOS 設備上測試 App 的 Live Text 功能。

Live Text 除了支援英語外,還支援法語、意大利語、德語、西班牙語、中文、葡萄牙語、日語、和韓語。

swiftui-live-text-api-demo-chinese

你可以在 GitHub 查看範例專案的原始程式碼。

備註:我們正就著 iOS 16 更新《精通 SwiftUI》一書。如你有意學習 SwiftUI,歡迎透過網頁購買書籍,我們會在今年免費為大家更新本書。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。

作者
Simon Ng
軟體工程師,AppCoda 創辦人。著有《iOS 17 App 程式設計實戰心法》、《iOS 17 App程式設計進階攻略》以及《精通SwiftUI》。曾任職於HSBC, FedEx等跨國企業,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda業務,致力於iOS程式教學、產品設計及開發。你可以到推特與我聯絡。
評論
更多來自 AppCoda 中文版
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。