iOS-OCR mit Apple Vision und Swift
Mit RecognizeTextRequest von Apple Vision extrahieren Sie Text aus einem Bild auf einem iPhone.
Diese Anleitung erstellt eine kleine SwiftUI-App, die ein Bild aus „Dateien“ öffnet und auswählbaren
Text anzeigt. Sie behandelt gedrehte Fotos, leere Ergebnisse, unlesbare Dateien und Abbrüche, wenn
Nutzer ein anderes Bild wählen oder die App verlassen.
Welche iOS-OCR-API sollten Sie verwenden?
Für Standbilder bietet die Swift-API von Vision asynchrone Texterkennung ab iOS 18. Das folgende Beispiel verwendet diese API und englischen Text. Es benötigt weder ein OCR-SDK von Drittanbietern noch eine heruntergeladene Modelldatei.
Wenn Sie frühere iOS-Versionen unterstützen, prüfen Sie stattdessen
VNRecognizeTextRequest;
der folgende Code ist kein Kompatibilitäts-Wrapper. Für eine Live-Kameraoberfläche lesen Sie die
Hinweise zu VisionKit weiter unten.
Text in einem Standbild erkennen
Erstellen Sie in Xcode ein iOS-App-Projekt namens ImageOCR mit SwiftUI und Swift,
ohne Speicherintegration. Setzen Sie das Deployment Target auf iOS 18.0 und verwenden Sie den
Sprachmodus Swift 6. Erstellen Sie den Build für diese API mit
Xcode 16 oder neuer.
Das Beispiel wurde mit Xcode 27.0, dem Swift-6.4-Compiler im Swift-6-Modus und dem iOS-27.0-SDK
erstellt und anschließend auf einem iPhone-17-Simulator mit iOS 27.0 ausgeführt. iOS 18 ist die
Mindestversion der API, keine hier getestete Laufzeitumgebung.
Sie verwenden drei Dateien: Fügen Sie OCR.swift hinzu, ersetzen Sie
ContentView.swift und ersetzen Sie ImageOCRApp.swift. Belassen Sie alle drei
im App-Target. Es sind weder Paketabhängigkeiten noch Berechtigungsschlüssel für Kamera und
Fotomediathek hinzuzufügen, da die App eine Datei über die Systemauswahl auswählt.
Beginnen Sie mit einer lokalen JPEG- oder PNG-Datei mit großem, gut lesbarem englischem Text.
Falls Ihr Bild in „Fotos“ liegt, speichern Sie es zuerst über das Teilen-Menü in „Dateien“.
Bild lesen und seinen Text erkennen
Fügen Sie diesen Code in OCR.swift ein. Der Recognizer-Actor hält das Lesen von
Dateien und das Decodieren von Bildern vom Main Actor fern. Er liest das erste Bild in der Datei
und übergibt dessen Image-I/O-Ausrichtung
an Vision. Ein CGImage allein enthält die Pixel, nicht aber die Ausrichtung,
die für ihre aufrechte Darstellung nötig ist.
import Foundation
import ImageIO
import Observation
import Vision
enum ImageInputError: Error {
case unreadableImage
}
actor TextRecognizer {
func recognize(_ url: URL) async throws -> String {
try Task.checkCancellation()
let hasAccess = url.startAccessingSecurityScopedResource()
defer {
if hasAccess { url.stopAccessingSecurityScopedResource() }
}
let data = try Data(contentsOf: url)
guard let source = CGImageSourceCreateWithData(data as CFData, nil),
let image = CGImageSourceCreateImageAtIndex(source, 0, nil)
else {
throw ImageInputError.unreadableImage
}
let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any]
let rawOrientation = properties?[kCGImagePropertyOrientation] as? UInt32 ?? 1
let orientation = CGImagePropertyOrientation(rawValue: rawOrientation) ?? .up
try Task.checkCancellation()
var request = RecognizeTextRequest()
request.recognitionLevel = .accurate
request.recognitionLanguages = [Locale.Language(identifier: "en-US")]
request.usesLanguageCorrection = true
let observations = try await request.perform(on: image, orientation: orientation)
try Task.checkCancellation()
return observations.compactMap { $0.topCandidates(1).first?.string }
.joined(separator: "\n")
}
}
@MainActor
@Observable
final class OCRModel {
var text = ""
var message = "Choose an image to recognize."
var isRecognizing = false
private let recognizer = TextRecognizer()
private var work: Task<Void, Never>?
func importImage(_ result: Result<URL, Error>) {
cancel()
text = ""
guard case let .success(url) = result else {
message = "Could not open the selected file."
return
}
message = "Recognizing…"
isRecognizing = true
work = Task {
do {
let recognized = try await recognizer.recognize(url)
try Task.checkCancellation()
text = recognized
message = recognized.isEmpty ? "No text found." : "Text recognized."
} catch {
// A canceled task must not replace feedback from a newer selection.
guard !Task.isCancelled else { return }
message = "Could not read this image. Try a local JPEG or PNG."
}
isRecognizing = false
work = nil
}
}
func cancel() {
guard isRecognizing else { return }
work?.cancel()
work = nil
isRecognizing = false
message = "Recognition canceled."
}
}
Das Modell unterscheidet ein gültiges Bild ohne erkannten Text von einer Datei, die nicht gelesen werden konnte. Der Abbruch erfolgt kooperativ: Er verhindert, dass ein verspätetes Ergebnis die Anzeige verändert, garantiert aber keinen sofortigen Stopp der nativen Verarbeitung. UI-Änderungen bleiben auf dem Main Actor, ohne Unterbrechung zwischen der letzten Abbruchprüfung und der Veröffentlichung des Ergebnisses.
Dateiauswahl und Ergebnisse verbinden
Ersetzen Sie ContentView.swift durch den folgenden Code. Der
Vertrag von fileImporter
verlangt beim Lesen der ausgewählten URL einen bereichsgebundenen Zugriff;
TextRecognizer gleicht diesen Zugriff mit defer aus.
Eine URL, die bereits in der Sandbox der App liegt, kann auch dann lesbar sein, wenn das Starten
des bereichsgebundenen Zugriffs false zurückgibt. Daher entscheidet das Lesen
der Datei über den Erfolg.
import SwiftUI
import UniformTypeIdentifiers
struct ContentView: View {
@Environment(\.scenePhase) private var scenePhase
@State private var model = OCRModel()
@State private var showImporter = false
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 16) {
HStack {
Button("Choose image") {
model.cancel()
showImporter = true
}
Button("Cancel recognition") { model.cancel() }
.disabled(!model.isRecognizing)
}
Text(model.message)
if model.isRecognizing {
ProgressView()
}
ScrollView {
Text(model.text)
.frame(maxWidth: .infinity, alignment: .leading)
.textSelection(.enabled)
}
}
.padding()
.navigationTitle("Image OCR")
}
.fileImporter(isPresented: $showImporter, allowedContentTypes: [.image]) { result in
model.importImage(result)
}
.onChange(of: scenePhase) { _, phase in
if phase != .active { model.cancel() }
}
.onDisappear { model.cancel() }
}
}
Ersetzen Sie ImageOCRApp.swift durch den Einstiegspunkt der App:
import SwiftUI
@main
struct ImageOCRApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
Starten Sie die App und tippen Sie auf Choose image. Navigieren Sie in „Dateien“ zu Ihrem Bild und wählen Sie es aus. Die App löscht den zuvor erkannten Text, zeigt Recognizing… an und anschließend Text recognized. sowie den extrahierten Text. Halten Sie den Text gedrückt, um ihn auszuwählen oder zu kopieren. Bei einem leeren Bild erscheint stattdessen No text found.. Die App hält den aktuell erkannten Text im Arbeitsspeicher; sie speichert keine Ausgabedatei und lädt keine hoch.
Das Öffnen der Auswahl und das Auswählen einer Datei sind getrennte Aktionen. Wenn gerade keine
Erkennung läuft, bleibt das vorherige Ergebnis beim Öffnen und anschließenden Schließen der Auswahl
erhalten. Während der Erkennung bricht ein Tippen auf
Choose image die laufende Aufgabe sofort ab.
Wird diese Auswahl geschlossen, bleibt Recognition canceled.
stehen; die Auswahl einer Datei startet eine neue Verarbeitung. Bei einem Abbruch ruft das System
den Completion Handler von fileImporter nicht auf.
Cancel recognition bricht die laufende Verarbeitung ebenfalls ab. Die App bricht ab, wenn ihre Scene inaktiv wird, auch beim Wechsel in den Hintergrund. Die Rückkehr zur App startet die Erkennung nicht erneut: Wählen Sie das Bild noch einmal aus. Vollständig erkannter Text bleibt bei der Rückkehr zur App sichtbar, sofern der Prozess weitergelaufen ist.
Ergebnis und Fehlerzustände prüfen
Probieren Sie ein einfaches Bild mit SWIFT VISION 2468 aus, bevor Sie einen komplexen
Kassenbon testen. Dieser Text wurde mit dem Beispiel im Simulator erkannt, auch wenn seine Pixel
gedreht waren und die Datei die passenden Ausrichtungsmetadaten enthielt. OCR kann reale Dokumente
dennoch falsch lesen; die durch Zeilenumbrüche verbundenen Erkennungen rekonstruieren weder
Tabellen noch das Seitenlayout.
| Eingabe oder Aktion | Erwartetes Verhalten |
|---|---|
| Gut lesbarer englischer Text | Auswählbarer erkannter Text und Text recognized. |
| Leeres Bild | No text found. mit leerem Textfeld |
| Beschädigtes Bild oder Datei, die vor dem Lesen verschwindet | Could not read this image. Try a local JPEG or PNG. |
| Auswahl meldet einen Importfehler | Could not open the selected file. |
| Laufende Verarbeitung abbrechen oder ersetzen | Die alte Aufgabe kann die neue Rückmeldung nicht mit einem Ergebnis überschreiben |
Versuchen Sie bei einer unlesbaren Datei zunächst, sie in einen lokalen Ordner in „Dateien“ zu kopieren und erneut zu öffnen. Ein Cloud-Dateianbieter benötigt möglicherweise eine Verbindung, um die Bytes bereitzustellen, obwohl die Erkennung selbst lokal läuft. Dieses Beispiel liest das gesamte Bild in den Arbeitsspeicher. Verkleinern Sie ungewöhnlich große Eingaben, bevor Sie es als Komponente für die Stapelverarbeitung einsetzen.
Text mit der Live-Kamera scannen
DataScannerViewController
ist die Kameraoberfläche von VisionKit zur Erkennung von Text und Codes. Prüfen Sie vor dem Anbieten
dieser Funktion sowohl isSupported als auch isAvailable, stellen
Sie NSCameraUsageDescription bereit und behandeln Sie den Fall, dass das Scannen während der
App-Ausführung nicht mehr verfügbar ist. Behalten Sie die Standbildauswahl als Rückfalloption bei.
Eine Live-Kamerafunktion muss auf unterstützter physischer Hardware getestet werden. Verweigern Sie insbesondere den Kamerazugriff, gewähren Sie ihn dann in „Einstellungen“ und kehren Sie zum bestehenden App-Prozess zurück, um die Wiederherstellung zu prüfen. Testen Sie auch Unterbrechungen und das Schließen während des Scannens. Der obige Simulatortest belegt keine dieser Kameraverhaltensweisen. Nutzen Sie die verlinkte Integrationsanleitung von Apple, wenn Sie diese separate Funktion hinzufügen.
OCR-Stapelverarbeitung in einen Transloadit-Workflow verlagern
Das obige Beispiel bedient eine einzelne Interaktion in einer laufenden App. Wenn Ihre Eingaben bereits in einen Workflow zur Upload-Verarbeitung gehören, ziehen Sie die Dokumentation zur Bild-OCR von Transloadit für die serverseitige Umsetzung heran. Das ist eine separate Integration, unabhängig von dieser lokalen App. Bewahren Sie geheime Zugangsdaten für Dienste auf Ihrem Backend auf, außerhalb des iOS-Bundles.
OCR-Genauigkeit verbessern
Beginnen Sie mit Ausrichtung, Schärfe und lesbarer Textgröße. Das Zuschneiden irrelevanter Randbereiche kann die Erkennung eines Dokuments erleichtern. Das Vergrößern eines winzigen Quellbilds kann fehlende Details jedoch nicht wiederherstellen. Reduzieren Sie bei Fotos Spiegelungen und starke perspektivische Verzerrungen, bevor Sie die Erkennungseinstellungen ändern.
Wenn eine dicht bedruckte Seite keinen Text liefert, prüfen Sie
minimumTextHeightFraction.
Der Standardwert beträgt 1/32 der Bildhöhe. Kleingedrucktes kann daher ausgeschlossen werden, selbst
wenn es gut lesbar aussieht. Schneiden Sie einen kleineren Bereich zu oder senken Sie diesen
Schwellenwert. Die Berücksichtigung kleineren Texts kann die Erkennungsdauer und den Speicherbedarf
erhöhen.
Das Beispiel wählt Englisch und .accurate. Prüfen Sie für andere Sprachen
supportedRecognitionLanguages der Anfrage
und setzen Sie recognitionLanguages passend zu Ihrer Eingabe. Vision bietet außerdem
customWords für Vokabular wie Produktnamen. Testen Sie die Sprachkorrektur mit Ihren
eigenen Kennungen: Ein plausibles Wort ist nicht unbedingt die richtige Seriennummer.
Häufige Fragen
Was ist die beste OCR-Bibliothek für iOS?
Beginnen Sie mit Apple Vision, wenn dessen Sprachabdeckung zu Ihren Bildern und Ihrem Deployment Target passt. Damit müssen Sie keine native OCR-Binärdatei von Drittanbietern hinzufügen. Wenn Sie ein eigenes Modell oder eine nicht unterstützte Sprache benötigen, prüfen Sie diese Anforderung mit repräsentativen Bildern, bevor Sie eine andere Engine wählen.
Sollte ich SwiftyTesseract in einer neuen iOS-App verwenden?
SwiftyTesseract ist archiviert, und der Maintainer kündigt an, dass es keine weiteren Updates erhalten wird. Betrachten Sie es für eine neue App nicht als gepflegte Abhängigkeit. Eine bestehende Integration erfordert eigene Migrations- und Kompatibilitätstests.
Benötigt iOS-OCR eine Netzwerkverbindung?
Vision führt die Texterkennung auf dem Gerät aus. Diese App benötigt weder einen Modelldownload noch eine Servereinrichtung. Wählen Sie offline eine Datei, die bereits lokal gespeichert ist. Das Herunterladen einer Datei aus iCloud oder von einem anderen Anbieter ist ein separater Vorgang.
Wie sollte ich OCR testen?
Testen Sie sowohl die Erkennung als auch den umgebenden App-Ablauf. Berücksichtigen Sie bekannten Text, leere und beschädigte Dateien, gedrehte Pixel mit Ausrichtungsmetadaten, Abbrüche, den Wechsel zu einer anderen Datei und Wechsel zwischen Hintergrund und Vordergrund. Verwenden Sie für Abnahmetests Ihre tatsächlichen Sprachen, Schriftarten und Layouts. Prüfen Sie erforderliche Felder und eine brauchbare Ausgabe, statt über alle Betriebssystemversionen hinweg genau denselben erkannten Text zu erwarten.
