Skip to main content

Initial commmit

ID
67cd5bd
date
2024-06-06 06:26:30+00:00
author
Alex Chan <alex@alexwlchan.net>
message
Initial commmit
changed files
12 files, 284 additions

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