Encode an identifier into an image's pixels; verify a JSON record against any copy
Project description
Mememage
Encode an identifier into an image's pixels; verify a JSON record against any copy.
Mememage writes a 2-pixel-tall bar into the bottom rows of an image. The bar holds two values:
- identifier — a short string that points to a JSON record, stored separately (a server, a CDN, IPFS, a file).
- content hash — a SHA-256 over the record.
verifyrecomputes it and compares against the bar.
The bar survives JPEG, resaves, screenshots, and re-uploads, so the identifier reads back from any copy. encode reads any image Pillow can open and writes a lossless PNG; decode and verify work on any format the bar survives. Record fields are arbitrary — captions, credits, generation parameters, links.
pip install mememage # encode / decode / verify — Pillow included
# pip install "mememage[encrypt]" # adds AES-256 field encryption
Quickstart
Three functions, all pure image operations:
import mememage
# encode — write the bar into the image, build the record from your fields
result = mememage.encode("photo.png", {"title": "Morning fog", "by": "catmemes"})
result.identifier # 'mememage-3dc5f03a747bb38e' (derived from the fields)
result.save("photo.json") # the record — store or serve it separately
# decode — read the bar back out of the pixels (the inverse of encode)
bar = mememage.decode("photo.jpg") # any format the bar survived: PNG, JPEG, a screenshot
bar.identifier, bar.content_hash
# verify — does a record match an image? (recomputed hash == the bar's)
mememage.verify("photo.jpg", result.record) # True if the record is intact
You resolve the record from its identifier — look it up wherever you keep it, then verify:
bar = mememage.decode("photo.jpg") # identifier + content hash from the pixels
record = my_store[bar.identifier] # your storage: a dict, a file, a DB, a URL
mememage.verify("photo.jpg", record) # True if the record matches the image
encodeaccepts any image — a path,bytes, a PILImage, or a numpy array (HEIC needs the[heic]extra) — and returns the barred image asRecord.image. Given a destination — a path (in place, or a.pngsibling for non-PNG),out=<path.png>, orout=<stream>(e.g.BytesIO) — it writes the file. Output is always PNG: the bar is lossless, and a lossy re-encode would corrupt it. An in-memory input with no destination never touches disk.decode/verifyaccept the same in-memory forms — a path,bytes, a file-like, a PILImage, or a numpy array. No disk round-trip.- No network I/O —
decodereturns the identifier; you resolve the record. Core is pure pixel + hash operations.
Encrypt private fields
- Mark fields
privateto encrypt them (AES-256-GCM via PBKDF2) under a password. - The record still verifies without the password — the hash covers the ciphertext.
unlockreturns the decrypted fields. The password is not stored; only the ciphertext is kept in the record.
result = mememage.encode("photo.png", {"title": "Public", "gps": "45.5,-122.6"},
password="hunter2", private=["gps"])
mememage.verify("photo.png", result.record) # matches — no password
mememage.unlock(result, "hunter2")["gps"] # '45.5,-122.6'
Command line
mememage encode photo.png --field title="Morning fog" -o photo.json # write the record
mememage decode photo.jpg --record photo.json # VERIFIED (exit 0) / ALTERED (exit 1)
mememage decode photo.jpg # read the identifier only (no record)
Without -o, the record is written next to the image as <identifier>.json.
decode exits 0 on a match.
License
MIT.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mememage-0.1.0.tar.gz.
File metadata
- Download URL: mememage-0.1.0.tar.gz
- Upload date:
- Size: 48.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3652bc174ea9420d4b2120b5de685fe4388f67e55bfea11158a4015c9f7413f1
|
|
| MD5 |
9dfecb92d90e5ec90eaee5e651dd49c2
|
|
| BLAKE2b-256 |
145d022177b2d7068224e1d4f97c5495cf26bdce9c9f7ac0e9f1af200d0824f7
|
Provenance
The following attestation bundles were made for mememage-0.1.0.tar.gz:
Publisher:
publish.yml on sememtac/mememage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mememage-0.1.0.tar.gz -
Subject digest:
3652bc174ea9420d4b2120b5de685fe4388f67e55bfea11158a4015c9f7413f1 - Sigstore transparency entry: 2066016421
- Sigstore integration time:
-
Permalink:
sememtac/mememage@c2b7d0a6d14fcd16e27e4daa6bbcf0bd2c61fe30 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sememtac
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c2b7d0a6d14fcd16e27e4daa6bbcf0bd2c61fe30 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mememage-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mememage-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36698908816663f3ef028792a790bb40e1265bbc4b57f71f7b843cf3d562838e
|
|
| MD5 |
09a3dc316bf81ab7f703d1ab349e7676
|
|
| BLAKE2b-256 |
20c82004151f99a6136dd9dc7dd73de0bf0de25484a5dcaaf22931e7b8e737ce
|
Provenance
The following attestation bundles were made for mememage-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on sememtac/mememage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mememage-0.1.0-py3-none-any.whl -
Subject digest:
36698908816663f3ef028792a790bb40e1265bbc4b57f71f7b843cf3d562838e - Sigstore transparency entry: 2066016503
- Sigstore integration time:
-
Permalink:
sememtac/mememage@c2b7d0a6d14fcd16e27e4daa6bbcf0bd2c61fe30 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sememtac
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c2b7d0a6d14fcd16e27e4daa6bbcf0bd2c61fe30 -
Trigger Event:
release
-
Statement type: