Skip to content

Commit

Permalink
perf: use execa to run swift directly
Browse files Browse the repository at this point in the history
  • Loading branch information
tisfeng committed May 17, 2023
1 parent dd31f41 commit 3f05a4e
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 26 deletions.
18 changes: 0 additions & 18 deletions Package.swift

This file was deleted.

Binary file removed assets/RecognizeText
Binary file not shown.
82 changes: 82 additions & 0 deletions assets/recognizeText.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book
// swift build -c release

import Cocoa
import Vision

let recognitionLevel = VNRequestTextRecognitionLevel.accurate
let usesLanguageCorrection = true

func captureScreen() -> CGImage? {
let screenRect = NSScreen.main?.frame ?? .zero
let imageRef = CGWindowListCreateImage(screenRect, .optionOnScreenOnly, kCGNullWindowID, .bestResolution)
return imageRef
}

func captureSelectedArea() -> CGImage? {
let task = Process()
task.launchPath = "/usr/sbin/screencapture"
task.arguments = ["-i", "-c"]
task.launch()
task.waitUntilExit()

guard let pasteboard = NSPasteboard.general.pasteboardItems?.first,
let fileType = pasteboard.types.first,
let data = pasteboard.data(forType: fileType),
let image = NSImage(data: data) else {
fputs("Error: failed to capture selected area\n", stderr)
return nil
}

var proposedRect = NSRect.zero
guard let imgRef = image.cgImage(forProposedRect: &proposedRect, context: nil, hints: nil) else {
fputs("Error: failed to convert NSImage to CGImage for captured area\n", stderr)
return nil
}

return imgRef
}

func main() -> Int32 {
let imgRef: CGImage? = captureSelectedArea()

guard let capturedImage = imgRef else {
fputs("Error: failed to capture image\n", stderr)
return 1
}

let request = VNRecognizeTextRequest()
request.recognitionLevel = recognitionLevel
request.usesLanguageCorrection = usesLanguageCorrection
if #available(macOS 13.0, *) {
request.automaticallyDetectsLanguage = true
}

// "en-US", "fr-FR", "it-IT", "de-DE", "es-ES", "pt-BR", "zh-Hans", "zh-Hant", "yue-Hans", "yue-Hant", "ko-KR", "ja-JP", "ru-RU", "uk-UA"
request.recognitionLanguages = ["zh-Hans", "zh-Hant", "en-US", "ja-JP", "fr-FR", "de-DE", "es-ES", "pt-BR", "it-IT", "ko-KR", "ru-RU", "uk-UA"]

do {
try VNImageRequestHandler(cgImage: capturedImage, options: [:]).perform([request])
} catch {
fputs("Error: \(error.localizedDescription)", stderr)
return 1
}

guard let observations = request.results else {
fputs("Error: could not get text recognition results", stderr)
return 1
}

// Currently, we just join all recognized text by '\n'
// TODO: use the bounding box frame and the end character of each line to determine how to join the text.
let obs = observations
.map { $0.topCandidates(1).first?.string ?? "" }
.joined(separator: "\n")

print(obs)

return 0
}

exit(main())
13 changes: 11 additions & 2 deletions src/ocr.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/*
* @author: tisfeng
* @createTime: 2023-05-15 23:31
* @lastEditor: tisfeng
* @lastEditTime: 2023-05-17 18:42
* @fileName: ocr.tsx
*
* Copyright (c) 2023 by ${git_name}, All Rights Reserved.
*/

import { closeMainWindow, open, showHUD } from "@raycast/api";
import { recognizeText } from "./recognizeText";

Expand All @@ -6,11 +16,10 @@ export default async function command() {

try {
const recognizedText = await recognizeText();

if (!recognizedText) {
return await showHUD("❌ No text detected!");
}
console.log(recognizedText);
console.log(`Recognized text: ${recognizedText}`);

const encodedQueryText = encodeURIComponent(recognizedText);
const easyDictUrl = `raycast://extensions/isfeng/easydict/easydict?fallbackText=${encodedQueryText}`;
Expand Down
19 changes: 13 additions & 6 deletions src/recognizeText.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
/*
* @author: tisfeng
* @createTime: 2023-05-15 23:31
* @lastEditor: tisfeng
* @lastEditTime: 2023-05-17 18:40
* @fileName: recognizeText.ts
*
* Copyright (c) 2023 by ${git_name}, All Rights Reserved.
*/

import { environment } from "@raycast/api";
import { join } from "path";
import { execa, ExecaError } from "execa";
import { chmod } from "fs/promises";
import { join } from "path";

const recognizeText = async () => {
const command = join(environment.assetsPath, "RecognizeText");
await chmod(command, "755");

try {
const { stdout } = await execa(command);
const filePath = join(environment.assetsPath, "recognizeText.swift");
const { stdout } = await execa("swift", [filePath]);
return stdout;
} catch (error) {
if ((error as ExecaError).stdout === "No text selected") {
Expand Down

0 comments on commit 3f05a4e

Please sign in to comment.