Skip to content

Commit

Permalink
chore: add macos libs
Browse files Browse the repository at this point in the history
  • Loading branch information
snapre committed Oct 27, 2023
1 parent bce2a9a commit cd83ddb
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 1 deletion.
13 changes: 13 additions & 0 deletions resource/swift/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 1. build MacosOcr project
echo "☕️ start build ocr ..."
cd ./src/MacosOcr
swift build -c release
cd ../../
cp ./src/MacosOcr/.build/release/MacosOcr ./ocr

# 2. build LeftMouseDragged project
echo "☕️ start build mouse-drag ..."
cd ./src/LeftMouseDragged
swift build -c release
cd ../../
cp ./src/LeftMouseDragged/.build/release/LeftMouseDragged ./mouse-drag
Binary file modified resource/swift/mouse-drag
Binary file not shown.
Binary file modified resource/swift/ocr
Binary file not shown.
8 changes: 7 additions & 1 deletion resource/swift/readme.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
## executable binary create by swift
## Build swift project
```bash
bash ./build.sh
```

## Executable binary create by swift
- OCR
- ocr ability powered by macOS.
- usage: ocr /path/to/img

- mouse-drag
- mouse drag to (+x,+y) relate to current point
- mouse-drag delay x y

8 changes: 8 additions & 0 deletions resource/swift/src/LeftMouseDragged/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
14 changes: 14 additions & 0 deletions resource/swift/src/LeftMouseDragged/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "LeftMouseDragged",
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.executableTarget(
name: "LeftMouseDragged"),
]
)
108 changes: 108 additions & 0 deletions resource/swift/src/LeftMouseDragged/Sources/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book

import AppKit
import Cocoa

func taskDelay(_ millSeconds: Int, _ task: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + Double(millSeconds) / 1000.0, execute: task)
}

func postMouseEvent(button:CGMouseButton, type:CGEventType, point: CGPoint,clickCount:Int64 = 1)
{
let event = createMouseEvent(button: button, type: type, point: point,clickCount:clickCount)
event.post(tap: CGEventTapLocation.cghidEventTap)
}

func createMouseEvent(button:CGMouseButton, type:CGEventType, point: CGPoint,clickCount:Int64 = 1) -> CGEvent
{
let event : CGEvent = CGEvent(mouseEventSource: CGEventSource.init(stateID: CGEventSourceStateID.privateState), mouseType: type, mouseCursorPosition: point, mouseButton: button)!
event.setIntegerValueField(CGEventField.mouseEventClickState, value: clickCount)
return event
}

func mouseDragged(point:CGPoint,toPoint:CGPoint,button:CGMouseButton,postDelay:Int){
let toMaxX:Bool = toPoint.x - point.x > 0
let toMaxY:Bool = toPoint.y - point.y > 0

var tempPointY = point.y
var tempPointX = point.x

postMouseEvent(button: button, type: button == .left ? .leftMouseDown : .rightMouseDown, point: point,clickCount: 1);

let blockOperation = BlockOperation()

blockOperation.addExecutionBlock {
while toMaxY ? (toPoint.y > tempPointY) : (toPoint.y < tempPointY){
Thread.sleep(forTimeInterval: 0.0001 * Double(postDelay))
toMaxY ? (tempPointY += 1) : (tempPointY -= 1)
postMouseEvent(button: button, type: button == .left ? .leftMouseDragged : .rightMouseDragged, point: CGPoint(x: tempPointX, y: tempPointY),clickCount: 1);
}
}
blockOperation.addExecutionBlock {
while toMaxX ? (toPoint.x > tempPointX) : (toPoint.x < tempPointX) {
Thread.sleep(forTimeInterval: 0.0001 * Double(postDelay))
toMaxX ? (tempPointX += 1) : (tempPointX -= 1)
postMouseEvent(button: button, type: button == .left ? .leftMouseDragged : .rightMouseDragged, point: CGPoint(x: tempPointX, y: tempPointY),clickCount: 1);
}

}
blockOperation.completionBlock = {
postMouseEvent(button: button, type: button == .left ? .leftMouseUp : .rightMouseUp, point: toPoint,clickCount: 1);
}
blockOperation.start()
}

func printJson(_ data: Any) {
let jsonData = try! JSONSerialization.data(withJSONObject: data)
print(String(data: jsonData, encoding: String.Encoding.utf8) ?? "")
}

func main(args: [String]) -> Int32 {
guard CommandLine.arguments.count == 6 || CommandLine.arguments.count == 4 else {
fputs(String(format: "usage1: %1$@ postDelay x1 y1 x2 y2, dragged from (x1, y1) to (x1, y2), when move a px, sleep(postDelay)\n", CommandLine.arguments[0]), stderr)
fputs(String(format: "usage2: %1$@ postDelay x y, dragged from mouseLocation to (mouseLocation.x + x, mouseLocation.y + y), when move a px, sleep(postDelay)\n", CommandLine.arguments[0]), stderr)
return 1
}
let postDelay = Int(args[1]) ?? 0
var mouseLoc = NSEvent.mouseLocation

if (CommandLine.arguments.count == 4) {
mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
let newLoc = CGPoint(x: mouseLoc.x+CGFloat(Int(args[2]) ?? 0), y: mouseLoc.y+CGFloat(Int(args[3]) ?? 0))
mouseDragged(
point: CGPoint(x: mouseLoc.x, y: mouseLoc.y),
toPoint: newLoc,
button: .left,
postDelay: postDelay
)
printJson([
"success": true,
"from": [ "x1": Int(mouseLoc.x), "y1": Int(mouseLoc.y) ],
"to": [ "x2": Int(newLoc.x), "y2": Int(newLoc.y) ],
])
return 0
}

let x1 = Int(args[2]) ?? Int(mouseLoc.x)
let y1 = Int(args[3]) ?? Int(mouseLoc.y)
let x2 = Int(args[4]) ?? Int(mouseLoc.x)
let y2 = Int(args[5]) ?? Int(mouseLoc.y)

if (x1 != x2 || y1 != y2) {
mouseDragged(
point: CGPoint(x: x1, y: y1),
toPoint: CGPoint(x: x2, y: y2),
button: .left,
postDelay: postDelay
)
}
printJson([
"success": true,
"from": [ "x1": x1, "y1": y1 ],
"to": [ "x2": x2, "y2": y2 ],
])
return 0
}

exit(main(args: CommandLine.arguments))
8 changes: 8 additions & 0 deletions resource/swift/src/MacosOcr/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
17 changes: 17 additions & 0 deletions resource/swift/src/MacosOcr/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "MacosOcr",
platforms: [
.macOS(.v10_15)
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.executableTarget(
name: "MacosOcr"),
]
)
101 changes: 101 additions & 0 deletions resource/swift/src/MacosOcr/Sources/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book

import Cocoa
import Vision
// import ArgumentParser

// https://developer.apple.com/documentation/vision/vnrecognizetextrequest

let MODE: VNRequestTextRecognitionLevel = VNRequestTextRecognitionLevel.accurate // or .fast
let USE_LANG_CORRECTION = false
var REVISION:Int
if #available(macOS 13, *) {
REVISION = VNRecognizeTextRequestRevision3
} else if #available(macOS 11, *) {
REVISION = VNRecognizeTextRequestRevision2
} else {
REVISION = VNRecognizeAnimalsRequestRevision1
}

func main(args: [String]) -> Int32 {
guard CommandLine.arguments.count == 2 else {
fputs(String(format: "usage: %1$@ image\n", CommandLine.arguments[0]), stderr)
return 1
}

let src = args[1]

guard let img = NSImage(byReferencingFile: src) else {
fputs("Error: failed to load image '\(src)'\n", stderr)
return 1
}

guard let imgRef = img.cgImage(forProposedRect: &img.alignmentRect, context: nil, hints: nil) else {
fputs("Error: failed to convert NSImage to CGImage for '\(src)'\n", stderr)
return 1
}

let request: VNRecognizeTextRequest = VNRecognizeTextRequest { (request, error) in
let observations: [VNRecognizedTextObservation] = request.results as? [VNRecognizedTextObservation] ?? []
var results: [Any] = []
for observation: VNRecognizedTextObservation in observations {
let candidate: VNRecognizedText = observation.topCandidates(1)[0]
let value = [
"word": candidate.string,
"rect": [
"left": Int(Float(observation.topLeft.x) * Float(imgRef.width)),
"top": Int(Float(1 - observation.topLeft.y) * Float(imgRef.height)),
"width": Int(Float(observation.topRight.x - observation.topLeft.x) * Float(imgRef.width)),
"height": Int(Float(observation.topLeft.y - observation.bottomLeft.y) * Float(imgRef.height)),
],
"confidence": candidate.confidence,
]
results.append(value)
}
let data = try! JSONSerialization.data(withJSONObject: results)
print(String(data: data, encoding: String.Encoding.utf8) ?? "")
}
request.recognitionLevel = MODE
request.usesLanguageCorrection = USE_LANG_CORRECTION
request.revision = REVISION
request.recognitionLanguages = ["zh-Hans", "en-US"]
//request.minimumTextHeight = 0
//request.customWords = [String]

try? VNImageRequestHandler(cgImage: imgRef, options: [:]).perform([request])
return 0
}

exit(main(args: CommandLine.arguments))

// struct Banner: ParsableCommand {
// static let configuration = CommandConfiguration(
// abstract: "A Swift command-line tool to manage blog post banners",
// subcommands: [Generate.self])

// init() { }
// }

// // Banner.main()

// struct Generate: ParsableCommand {

// public static let configuration = CommandConfiguration(abstract: "Generate a blog post banner from the given input")

// @Argument(help: "The title of the blog post")
// private var title: String

// @Option(name: .shortAndLong, default: nil, help: "The week of the blog post as used in the file name")
// private var week: Int?

// @Flag(name: .long, help: "Show extra logging for debugging purposes")
// private var verbose: Bool

// func run() throws {
// if verbose {
// let weekDescription = week.map { "and week \($0)" }
// print("Creating a banner for title \"\(title)\" \(weekDescription ?? "")")
// }
// }
// }

0 comments on commit cd83ddb

Please sign in to comment.