OcrLine.swift 54 lignes · 1548 octets
import Foundation

/// Bounding box in pixels of the OCRed image (y axis pointing down).
/// Plain struct (no CoreGraphics): the model and the parser stay testable
/// without UIKit. Only RELATIVE positions matter (heights, gaps, alignments) —
/// the absolute frame depends on the candidate (preprocessing, orientation)
/// but is consistent within a single result.
struct OcrBox: Equatable {
    var left: Int
    var top: Int
    var right: Int
    var bottom: Int

    var height: Int { bottom - top }
    var width: Int { right - left }

    func overlapsHorizontally(_ other: OcrBox) -> Bool {
        left < other.right && other.left < right
    }

    func union(_ other: OcrBox) -> OcrBox {
        OcrBox(
            left: min(left, other.left),
            top: min(top, other.top),
            right: max(right, other.right),
            bottom: max(bottom, other.bottom)
        )
    }
}

/// Recognized text line with its box and confidence (0-100, Tesseract scale).
struct OcrLine: Equatable {
    var text: String
    var box: OcrBox
    var confidence: Float
}

/// Spatially coherent group of lines (address block, contact block…).
struct OcrBlock: Equatable {
    var lines: [OcrLine]

    func text() -> String {
        lines.map(\.text).joined(separator: "\n")
    }

    func box() -> OcrBox {
        lines.map(\.box).reduce(lines[0].box) { $0.union($1) }
    }

    func avgConfidence() -> Float {
        if lines.isEmpty { return 0 }
        return lines.map(\.confidence).reduce(0, +) / Float(lines.count)
    }
}