OcrOrientation.swift 43 lignes · 1515 octets
import Foundation

// `OcrException` lives in OcrEngine.swift (Vision engine owner).

/// Tries several orientations and keeps the one maximizing
/// business-card signals (email, phone, URL, amount of text).
///
/// Image-agnostic port: Android rotated `Bitmap`s via `Matrix`; on iOS the
/// image type and the rotation are injected by the Vision engine owner.
enum OcrOrientation {
    static let angles = [0, 90, 180, 270]

    static func recognizeBest<Image>(
        image: Image,
        rotate: (Image, Int) -> Image,
        recognize: (Image) throws -> OcrResult
    ) throws -> OcrResult {
        var best: OcrResult? = nil
        var bestScore = Int.min
        for angle in angles {
            let candidate = angle == 0 ? image : rotate(image, angle)
            guard let result = try? recognize(candidate) else { continue }
            let s = score(result)
            if s > bestScore {
                bestScore = s
                best = result
            }
            // Good enough: both email and phone found.
            if !result.emails.isEmpty && !result.phones.isEmpty { break }
        }
        guard let best else { throw OcrException("OCR vide — reprenez la photo") }
        return best
    }

    static func score(_ result: OcrResult) -> Int {
        var s = result.rawText.count
        s += result.emails.count * 200
        s += result.phones.count * 150
        s += result.urls.count * 100
        if result.rawText.contains("@") { s += 50 }
        return s
    }
}