| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- import Foundation
- import Vision
- import AppKit
- struct OcrLine: Encodable {
- let text: String
- let x: Double
- let y: Double
- let width: Double
- let height: Double
- }
- let args = CommandLine.arguments
- guard args.count >= 2 else {
- fputs("usage: swift ocr_image_text.swift <image>\\n", stderr)
- exit(2)
- }
- let imageURL = URL(fileURLWithPath: args[1])
- guard let image = NSImage(contentsOf: imageURL),
- let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
- fputs("failed to load image: \\(args[1])\\n", stderr)
- exit(1)
- }
- let request = VNRecognizeTextRequest()
- request.recognitionLevel = .accurate
- request.usesLanguageCorrection = true
- request.recognitionLanguages = ["zh-Hans", "en-US"]
- request.minimumTextHeight = 0.006
- let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
- try handler.perform([request])
- let observations = request.results ?? []
- let lines = observations.compactMap { observation -> OcrLine? in
- guard let candidate = observation.topCandidates(1).first else { return nil }
- let box = observation.boundingBox
- return OcrLine(
- text: candidate.string,
- x: Double(box.minX),
- y: Double(box.minY),
- width: Double(box.width),
- height: Double(box.height)
- )
- }.sorted {
- let y0 = Int($0.y * 1000)
- let y1 = Int($1.y * 1000)
- if y0 != y1 { return y0 > y1 }
- return $0.x < $1.x
- }
- let data = try JSONEncoder().encode(lines)
- FileHandle.standardOutput.write(data)
|