Initial commmit
- ID
67cd5bd- date
2024-06-06 06:26:30+00:00- author
Alex Chan <alex@alexwlchan.net>- message
Initial commmit- changed files
Changed files
.github/dependabot.yml (0) → .github/dependabot.yml (239)
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..3c453e4
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: daily
+ time: "09:00"
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: daily
+ time: "09:00"
.github/workflows/test.yml (0) → .github/workflows/test.yml (506)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..71fa0c2
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,30 @@
+name: Run tests
+
+on:
+ push:
+ branches:
+ - main
+
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ test:
+ runs-on: macos-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ cache: 'pip'
+ cache-dependency-path: 'dev_requirements.txt'
+
+ - name: Install dependencies
+ run: pip install -r dev_requirements.txt
+
+ - name: Run tests
+ run: python3 -m pytest -n 5 tests
.github/workflows/upload_binaries.yml (0) → .github/workflows/upload_binaries.yml (1283)
diff --git a/.github/workflows/upload_binaries.yml b/.github/workflows/upload_binaries.yml
new file mode 100644
index 0000000..47572a9
--- /dev/null
+++ b/.github/workflows/upload_binaries.yml
@@ -0,0 +1,49 @@
+name: Upload binaries
+
+on:
+ push:
+ tags:
+ - v[0-9]+.*
+
+jobs:
+ create-release:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v4
+ - uses: taiki-e/create-gh-release-action@v1
+ with:
+ changelog: CHANGELOG.md
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ upload-assets:
+ strategy:
+ matrix:
+
+ # See https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
+ include:
+ - target: aarch64-apple-darwin
+ os: macos-latest
+ - target: x86_64-apple-darwin
+ os: macos-13
+
+ runs-on: ${{ matrix.os }}
+
+ permissions:
+ contents: write
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Compile the Swift script
+ run: swiftc get_live_text.swift
+
+ - name: Create the zip archive
+ run: zip "get_live_text.${{ matrix.target }}.zip" get_live_text README.md LICENSE
+
+ - name: Push the zip file to the GitHub release
+ run: gh release upload "$GITHUB_REF_NAME" "get_live_text.${{ matrix.target }}.zip" --clobber
+ env:
+ GH_TOKEN: ${{ github.token }}
.gitignore (0) → .gitignore (20)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..17d846b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+get_live_text
CHANGELOG.md (0) → CHANGELOG.md (54)
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..7bd82b3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# CHANGELOG
+
+## v1.0.0 - 2024-06-06
+
+Initial release.
CONTRIBUTING.md (0) → CONTRIBUTING.md (404)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..76eaf89
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,12 @@
+# CONTRIBUTING
+
+## Creating a new release
+
+1. Bump the version number in `get_live_text.swift`
+2. Add a changelog entry in `CHANGELOG.md`
+3. Create a Git tag with your new version number
+4. Push your changes and Git tag to GitHub
+
+GitHub Actions will create a new release, including compiled binaries.
+
+These binaries aren't notarised -- see https://github.com/alexwlchan/safari-webarchiver/issues/6
LICENSE (0) → LICENSE (1053)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b3d4b83
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2024 Alex Chan
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
README.md (0) → README.md (1491)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7c3610f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+# get_live_text
+
+This tool uses Apple’s [Live Text feature](https://support.apple.com/en-gb/guide/preview/prvw625a5b2c/mac) to get text from an image on the command line.
+This gives you a way to OCR images programatically without installing any extra software.
+
+```console
+get_live_text "picture_of_a_sign.jpg"
+```
+
+This is the same as if you'd copy/pasted the text from the image using the Preview app, but now you can do so programatically and in bulk.
+
+## Installation
+
+### Install from source
+
+1. Install the Xcode Command Line Tools
+2. Download the `get_live_text.swift` script from this repo
+3. Compile the script into a binary:
+
+ ```console
+ $ swiftc get_live_text.swift
+ ```
+
+4. Copy the compiled binary `get_live_text` to somewhere in your PATH.
+
+### Install a compiled binary
+
+1. Find the latest [GitHub release](https://github.com/alexwlchan/get_live_text/releases)
+2. Download the zip file which is appropriate for your system (Intel = `x86_64`, Apple Silion = `aarch64`)
+3. Open the zip file, and add the `get_live_text` app to your PATH
+
+The app is just a compiled version of the Swift script.
+It isn't notarised, so when you run it, you may get a warning that this app is from an unidentified developer.
+You can get around this by right-clicking the app icon in Finder, and choosing `Open` from the shortcut menu.
+
+## Usage
+
+Run the script passing one arguments: the path to the image you want to OCR.
+
+```console
+$ get_live_text "picture_of_a_sign.jpg"
+```
dev_requirements.in (0) → dev_requirements.in (20)
diff --git a/dev_requirements.in b/dev_requirements.in
new file mode 100644
index 0000000..9cda381
--- /dev/null
+++ b/dev_requirements.in
@@ -0,0 +1,2 @@
+pytest
+pytest-xdist
dev_requirements.txt (0) → dev_requirements.txt (403)
diff --git a/dev_requirements.txt b/dev_requirements.txt
new file mode 100644
index 0000000..8461de5
--- /dev/null
+++ b/dev_requirements.txt
@@ -0,0 +1,16 @@
+# This file was autogenerated by uv via the following command:
+# uv pip compile dev_requirements.in --output-file dev_requirements.txt
+execnet==2.1.1
+ # via pytest-xdist
+iniconfig==2.0.0
+ # via pytest
+packaging==24.0
+ # via pytest
+pluggy==1.5.0
+ # via pytest
+pytest==8.2.1
+ # via
+ # -r dev_requirements.in
+ # pytest-xdist
+pytest-xdist==3.6.1
+ # via -r dev_requirements.in
get_live_text.swift (0) → get_live_text.swift (2766)
diff --git a/get_live_text.swift b/get_live_text.swift
new file mode 100755
index 0000000..d796656
--- /dev/null
+++ b/get_live_text.swift
@@ -0,0 +1,93 @@
+#!/usr/bin/env swift
+// Get OCR'd text from an image using Live Text in macOS.
+//
+// If you're using Preview, you can use Live Text to copy and paste text
+// that's in an image. This script allows you to access that text
+// programatically, which is useful if you want to do bulk analysis of
+// the text in your images.
+//
+// You can search text in the Photos app, but this is useful if you:
+//
+// - want to search images that aren't in your Photos library
+// - want to do analysis which isn't just searching
+//
+// This is based on https://developer.apple.com/documentation/vision/recognizing_text_in_images
+//
+// Tested on macOS Monterey.
+//
+// You may need to run `chmod +x get_live_text` first and install the Xcode
+// command-line tools.
+//
+// == Usage ==
+//
+// Pass the path to your image as a single command-line argument. Any text
+// in the image will be returned as a JSON list:
+//
+// $ get_live_text railway-sign.jpg
+// ["Passengers must","not pass this point","or cross the line"]
+//
+// If the image doesn't contain any text, it returns an empty list:
+//
+// $ get_live_text dancers.jpg
+// []
+//
+
+import Vision
+
+// Process the results of the text-recognition request.
+//
+// This is based on the code in Apple's documentation, and prints the
+// recognized text as a list of JSON strings.
+//
+// See https://developer.apple.com/documentation/vision/recognizing_text_in_images#3601255
+func recognizeTextHandler(request: VNRequest, error: Error?) {
+ guard
+ let observations =
+ request.results as? [VNRecognizedTextObservation]
+ else {
+ return
+ }
+ let recognizedStrings = observations.compactMap { observation in
+ // Return the string of the top VNRecognizedText instance.
+ return observation.topCandidates(1).first?.string
+ }
+
+ // Serialise to JSON
+ do {
+ let jsonData = try JSONSerialization.data(withJSONObject: recognizedStrings)
+
+ if let JSONString = String(data: jsonData, encoding: String.Encoding.utf8) {
+ print(JSONString)
+ }
+ } catch {
+ fputs("Unable to serialise the result as JSON: \(error).\n", stderr)
+ exit(1)
+ }
+}
+
+// Given the path to an image, print a JSON array of text it contains.
+func printTextInImage(imagePath: String) {
+ let requestHandler = VNImageRequestHandler(
+ url: URL(fileURLWithPath: imagePath),
+ options: [:]
+ )
+
+ let request = VNRecognizeTextRequest(completionHandler: recognizeTextHandler)
+
+ do {
+ // Perform the text-recognition request.
+ try requestHandler.perform([request])
+ } catch {
+ fputs("Unable to recognise text: \(error).\n", stderr)
+ exit(1)
+ }
+}
+
+let arguments = CommandLine.arguments
+
+if arguments.count != 2 {
+ fputs("Usage: \(arguments[0]) PATH\n", stderr)
+ exit(1)
+}
+
+printTextInImage(imagePath: arguments[1])
tests/test_truth.py (0) → tests/test_truth.py (34)
diff --git a/tests/test_truth.py b/tests/test_truth.py
new file mode 100644
index 0000000..29c6b40
--- /dev/null
+++ b/tests/test_truth.py
@@ -0,0 +1,2 @@
+def test_truth():
+ assert True