Skip to main content

🐍 ghostmark (Python)

The Python engine of Ghostmark-Image: an invisible two-layer photo mark that hides location, altitude and UTC time inside the pixels of a photo, so the record survives chat apps, screenshots, crops and black-and-white filters.

It writes and reads exactly the same mark as the Android (Kotlin) engine and the JavaScript reference engine: a photo marked on a phone can be read by a Python server, and the other way round.

  • depends on numpy only (Pillow optional: file helpers and the capture-time self-test)
  • Python 3.9+
  • no network, no native code, no model files

Install

pip install ./python[files]      # from the repository root; [files] adds Pillow
pip install -e ./python[test]    # for development and the tests

30-second tour

import numpy as np
from PIL import Image
import ghostmark as gm

rgb = np.asarray(Image.open("photo.jpg").convert("RGB"))      # uint8, shape (H, W, 3)

# write: the self-test squeezes a copy like a chat app and strengthens the mark only if needed
marked, strength = gm.mark_verified(rgb, gm.Record(lat=12.9716, lon=77.5946, alt=920, t=1792929600))
Image.fromarray(marked).save("marked.jpg", quality=95, subsampling=0)

# read any copy: WhatsApp, a screenshot, a black-and-white version ...
r = gm.read(np.asarray(Image.open("copy.jpg").convert("RGB")))
print(r.status)      # 'ok' full record | 'part' location only (about 10 m) | 'damaged' | 'none'
print(r.location)    # (lat, lon) from the best layer that was read, or None
print(r.time, r.id)  # UTC datetime and a 10-letter ID (full record only)

Command line:

ghostmark mark photo.jpg marked.jpg --lat 12.9716 --lon 77.5946 --alt 920 --time 2026-10-25T12:00:00Z
ghostmark read copy.jpg                   # exit code 0 = ok or part, 2 = damaged or none
ghostmark read cropped.jpg --crop         # the picture is a crop of the original
ghostmark read screen.jpg --corners 830,155,2312,135,2219,2126,808,2016   # photo of a screen or print (TL,TR,BR,BL)

API

Function What it does
Record(lat, lon, alt, t, tenth, manual) what to hide; t is unix seconds or a datetime; leave a field None for "not known"
mark(rgb, record, strength=1.0) returns a marked copy (about 0.1 grey levels of change on average; at most 10)
mark_verified(rgb, record) mark plus the capture-time self-test (chat-app copy, strengths 1.0, 1.4, 1.9). Returns (marked, strength)
read(rgb, try_turns=False) reads a full-frame picture of any size; try_turns=True also tries it turned by 90, 270 and 180 degrees; returns a ReadResult
read_cropped(rgb) finds where a plain crop (no turn, no tilt) sat inside the original frame, then reads it
read_perspective(rgb, corners) reads a phone photo of a screen or a print; corners are four rough taps, TL TR BR BL
auto_corners(rgb) first guess for those corners (bright picture on a dark surround)
mark_file(src, dst, record) / read_file(path) file helpers (Pillow); mark_file keeps EXIF

ReadResult: status, l1 (full record dict), l2 (location dict), z1/z2 (detection scores; above 3.5 means "a mark is here"), .ok, .location, .time, .id.

Statuses are honest. A CRC and an error-correcting code guard every value. If a layer cannot be read it is None; the engine never returns a plausible-looking wrong coordinate.

Interoperability, tested

  • The Android engine's test fixtures (marked photos written by the JavaScript reference engine) are read by this package: pytest -q fails if they are not.
  • On the 40 photos of the benchmark, Python-marked copies were read by the JavaScript engine and the reverse (see the main README for the numbers).
  • Both engines produce the same pixels to within one grey level (rounding of the final clamp).

Tests

cd python
pip install -e .[test]
pytest -q          # 14 tests, ~10 s

Limits (read these)

  • Speed: pure numpy. Marking and reading a 12 MP photo takes seconds, not milliseconds (numbers in the main README). read_perspective runs about 1,300 trial alignments and takes about a minute; use it for a few photos, not for batches.
  • No rotation inside the crop and screen readers: read(..., try_turns=True) handles a picture saved sideways, but read_cropped and read_perspective expect the picture upright.
  • Same physical limits as the format: photos below ~64 px, heavy denoising/AI retouching and small crops (below about a third of the area) are not read; black-and-white copies give the location only.
  • It is not a proof of authenticity: anyone with the engine can write a mark.

Licence

Apache License 2.0, see ../LICENSE and ../NOTICE. Free for any use, including commercial; keep the NOTICE with your distribution. A line of credit is appreciated:

Uses Ghostmark by Vijay Parmar, github.com/thevijayparmar/Ghostmark-Image

Metadata

Release files for ghostmark-image 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ghostmark-image 1.1.0
File Size Uploaded Provenance Actions
ghostmark_image-1.1.0.tar.gz 21.4 kB With provenance Details for ghostmark_image-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ghostmark-image 1.1.0
File Interpreter ABI Platform Actions
ghostmark_image-1.1.0-py3-none-any.whl Python 3 none any Details for ghostmark_image-1.1.0-py3-none-any.whl

Total release size: 40.2 kB

Release files / ghostmark_image-1.1.0.tar.gz

Download URL ghostmark_image-1.1.0.tar.gz
Size 21.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1e1722f4d16e0a41bd8ba77269067ec4400ee318b53be906cf807d795362d69a
BLAKE2b-256 checksum
How to use checksums
53f6b7525c5e4d74331643414313d1107d883de32c0c9e6a275c8e173e74ca5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / ghostmark_image-1.1.0-py3-none-any.whl

Download URL ghostmark_image-1.1.0-py3-none-any.whl
Size 18.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2465bc047185429913c8ae0a7b13bde20c1984eb199dd1c3323b14fac4fab88d
BLAKE2b-256 checksum
How to use checksums
b946e4a0707763889284f62b37da5baff7acbfeb4aba9a5f05f186af0cb66a59
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for ghostmark-image 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ghostmark_image-1.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page