import Foundation
import Vision
import AppKit
import PDFKit
func ocrImage(_ path: String) -> [OcrResult] {
let url = URL(fileURLWithPath: path)
// Check if PDF
if path.lowercased().hasSuffix(".pdf") {
return ocrPdf(url)
}
guard let ciImage = CIImage(contentsOf: url) else {
fputs("error: could not load image at \(path)\n", stderr)
return []
}
return (try? recognizeText(in: ciImage)) ?? []
}
func ocrPdf(_ url: URL) -> [OcrResult] {
guard let document = PDFDocument(url: url) else {
fputs("error: could not load PDF at \(url.path)\n", stderr)
return []
}
var allResults: [OcrResult] = []
for i in 0..<document.pageCount {
guard let page = document.page(at: i) else { continue }
// Try native text first
if let rawText = page.string, !rawText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
allResults.append(OcrResult(text: rawText, confidence: 1.0))
continue
}
// Fall back to Vision OCR
let pageRect = page.bounds(for: .mediaBox)
let image = NSImage(size: pageRect.size)
image.lockFocus()
if let context = NSGraphicsContext.current?.cgContext {
context.setFillColor(NSColor.white.cgColor)
context.fill(pageRect)
page.draw(with: .mediaBox, to: context)
}
image.unlockFocus()
guard let tiffData = image.tiffRepresentation,
let bitmap = NSBitmapImageRep(data: tiffData),
let cgImage = bitmap.cgImage else { continue }
let ciImage = CIImage(cgImage: cgImage)
allResults.append(contentsOf: (try? recognizeText(in: ciImage)) ?? [])
}
return allResults
}
// Main
let args = CommandLine.arguments
guard args.count > 1 else {
fputs("usage: ocr.swift <image_or_pdf_path>\n", stderr)
exit(1)
}
let results = ocrImage(args[1])
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
do {
let data = try encoder.encode(results)
if let json = String(data: data, encoding: .utf8) {
print(json)
} else {
fputs("error: failed to encode JSON as UTF-8\n", stderr)
exit(1)
}
} catch {
fputs("error: JSON encoding failed: \(error)\n", stderr)
exit(1)
}