hexatess-code 0.1.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of hexatess-code might be problematic. Click here for more details.

Files changed (34) hide show
  1. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/LICENSE +1 -1
  2. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/PKG-INFO +30 -13
  3. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/README.md +24 -11
  4. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/pyproject.toml +6 -1
  5. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/__init__.py +4 -4
  6. hexatess_code-0.3.0/src/hexatess/camera.py +840 -0
  7. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/cli.py +39 -4
  8. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/decoder.py +1 -1
  9. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/encoder.py +6 -4
  10. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/header.py +1 -1
  11. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess_code.egg-info/PKG-INFO +30 -13
  12. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess_code.egg-info/SOURCES.txt +2 -0
  13. hexatess_code-0.3.0/src/hexatess_code.egg-info/requires.txt +9 -0
  14. hexatess_code-0.3.0/tests/test_camera.py +75 -0
  15. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_codec.py +1 -1
  16. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_conformance.py +1 -1
  17. hexatess_code-0.1.0/src/hexatess_code.egg-info/requires.txt +0 -4
  18. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/setup.cfg +0 -0
  19. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/galois.py +0 -0
  20. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/geometry.py +0 -0
  21. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/masks.py +0 -0
  22. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/reedsolomon.py +0 -0
  23. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/render.py +0 -0
  24. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess/resilience.py +0 -0
  25. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess_code.egg-info/dependency_links.txt +0 -0
  26. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess_code.egg-info/entry_points.txt +0 -0
  27. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/src/hexatess_code.egg-info/top_level.txt +0 -0
  28. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_galois.py +0 -0
  29. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_geometry.py +0 -0
  30. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_header.py +0 -0
  31. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_masks.py +0 -0
  32. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_reedsolomon.py +0 -0
  33. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_render.py +0 -0
  34. {hexatess_code-0.1.0 → hexatess_code-0.3.0}/tests/test_resilience.py +0 -0
@@ -27,4 +27,4 @@ The format specification (SPECIFICATION.md) is additionally released under
27
27
  the Creative Commons Attribution 4.0 International license (CC-BY-4.0), so
28
28
  that anyone may implement compatible encoders/decoders in any language,
29
29
  under any license, without restriction. Provide attribution as:
30
- "Hexatess Code Specification v0.1, https://github.com/<you>/hexatess-code".
30
+ "Hexatess Code Specification v0.2, https://github.com/<you>/hexatess-code".
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hexatess-code
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: Hexatess Code - an experimental 2D barcode on a hexagonal grid with Reed-Solomon error correction
5
5
  Author: The Hexatess Code Authors
6
6
  License: MIT License
@@ -32,7 +32,7 @@ License: MIT License
32
32
  the Creative Commons Attribution 4.0 International license (CC-BY-4.0), so
33
33
  that anyone may implement compatible encoders/decoders in any language,
34
34
  under any license, without restriction. Provide attribution as:
35
- "Hexatess Code Specification v0.1, https://github.com/<you>/hexatess-code".
35
+ "Hexatess Code Specification v0.2, https://github.com/<you>/hexatess-code".
36
36
 
37
37
  Project-URL: Homepage, https://github.com/lovro-abram/hexatess-code
38
38
  Project-URL: Specification, https://github.com/lovro-abram/hexatess-code/blob/main/SPECIFICATION.md
@@ -56,9 +56,18 @@ License-File: LICENSE
56
56
  Requires-Dist: pillow>=9.0
57
57
  Provides-Extra: dev
58
58
  Requires-Dist: pytest>=7.0; extra == "dev"
59
+ Provides-Extra: camera
60
+ Requires-Dist: numpy>=1.24; extra == "camera"
61
+ Requires-Dist: opencv-python>=4.8; extra == "camera"
62
+ Requires-Dist: scipy>=1.10; extra == "camera"
59
63
  Dynamic: license-file
60
64
 
61
65
  # Hexatess Code 🐝
66
+ [![PyPI](https://img.shields.io/pypi/v/hexatess-code)](https://pypi.org/project/hexatess-code/)
67
+
68
+ [![Python](https://img.shields.io/pypi/pyversions/hexatess-code)](https://pypi.org/project/hexatess-code/)
69
+
70
+ [![CI](https://github.com/lovro-abram/hexatess-code/actions/workflows/ci.yml/badge.svg)](https://github.com/lovro-abram/hexatess-code/actions/workflows/ci.yml)
62
71
 
63
72
  **An experimental 2D barcode on a hexagonal grid** — with a hexagonal
64
73
  bullseye finder, spiral serialization and a continuously selectable
@@ -81,7 +90,7 @@ text, stats = decode(grid) # ('Hello, Hexatess!', {...})
81
90
  * **A** — a real encoded symbol: hexagonal bullseye finder (rings 0–4),
82
91
  orientation key (ring 5: two dark cells), data region (rings 6…)
83
92
  filled in spiral order, and a quiet zone of at least 1 module;
84
- * **B** — finder close-up: light centre (v0.1 rule `bit = ring mod 2`),
93
+ * **B** — finder close-up: dark centre (rule `bit = 1 − ring mod 2`),
85
94
  alternating dark/light rings, and the key — the first two canonical
86
95
  ring-5 cells set dark, breaking the 60-fold symmetry and marking the
87
96
  spiral start direction;
@@ -104,27 +113,32 @@ text, stats = decode(grid) # ('Hello, Hexatess!', {...})
104
113
 
105
114
  > **Status: experimental.** This is a young format: the symbol
106
115
  > specification and reference implementation are solid and heavily
107
- > tested (2,500+ tests, conformance vectors), but there is **no camera
108
- > decoder yet** — reading images assumes ideal upright sampling. See
109
- > the roadmap below. Adopting a young format is a deliberate bet; the
110
- > [full format specification](SPECIFICATION.md) is the insurance.
116
+ > tested (2,500+ tests, conformance vectors). A **camera decoder**
117
+ > (`hexatess.camera`, optional `[camera]` extra) already reads symbols
118
+ > from real photographs — printed labels, foil transparencies, tilted
119
+ > and rotated shots. See the roadmap below. Adopting a young format
120
+ > is a deliberate bet; the [full format specification](SPECIFICATION.md)
121
+ > is the insurance.
111
122
 
112
123
  ## Installation
113
124
 
114
125
  ```bash
115
126
  pip install hexatess-code # from PyPI (once published)
127
+ pip install "hexatess-code[camera]" # + photo decoding (numpy, opencv, scipy)
116
128
  # or from a source checkout:
117
129
  pip install -e .
118
130
  ```
119
131
 
120
- Requires Python ≥ 3.8 and Pillow (for rendering only).
132
+ Requires Python ≥ 3.8; Pillow for rendering, numpy + OpenCV + SciPy
133
+ for the optional camera decoder.
121
134
 
122
135
  ## Command line
123
136
 
124
137
  ```bash
125
138
  hexatess "Hello world" -o koda.png --ec 30
126
139
  hexatess "Important URL https://example.org" -o url.png --ec 55
127
- hexatess-code --demo # demo symbol + robustness statistics
140
+ hexatess --demo # demo symbol + robustness statistics
141
+ hexatess decode-photo photo1.jpg photo2.jpg # read symbols from photos
128
142
  ```
129
143
 
130
144
  ## API
@@ -136,6 +150,7 @@ hexatess-code --demo # demo symbol + robustness statistics
136
150
  | `render(grid, path, size_px=18, ...)` | grid → PNG (pointy-top hexagons, quiet zone, supersampling) |
137
151
  | `sample_grid_from_image(path, rmax, ...)` | ideal re-sampling of a rendered PNG (self-test helper) |
138
152
  | `run_tests(...)` | noise/blob robustness statistics |
153
+ | `hexatess.camera.decode_photo(path)` | photograph → `(text, stats)`; finder detection, perspective handling, adaptive sampling (optional `[camera]` extra) |
139
154
 
140
155
  `params` / `stats` contain `rmax` (radius in rings), `mask`, `ec`,
141
156
  `blocks` (list of `(data_bytes, ecc_bytes)`) and `data_len`.
@@ -162,16 +177,18 @@ concentrate inside whole bytes.
162
177
  The format is deliberately **specification-first**: everything needed
163
178
  for an independent implementation is in
164
179
  [`SPECIFICATION.md`](SPECIFICATION.md), and
165
- [`test_vectors/vectors_v0.1.json`](test_vectors/vectors_v0.1.json)
180
+ [`test_vectors/vectors_v0.2.json`](test_vectors/vectors_v0.2.json)
166
181
  contains fixed inputs/outputs (grids, headers, damaged symbols, expected
167
182
  results) to verify conformance. If your Rust/Go/JS decoder passes the
168
183
  vectors, it speaks Hexatess Code.
169
184
 
170
185
  ## Roadmap
171
186
 
172
- 1. **v0.2 — camera decoding:** bullseye detection + perspective
173
- correction (the critical ecosystem step).
174
- 2. **v0.2 — erasure decoding:** declare blob-occluded modules as
187
+ 1. ~~v0.2/0.3 — camera decoding~~ **done (v0.3.0):** `hexatess.camera`
188
+ reads symbols from photographs — bullseye detection, homography +
189
+ correction-field warp handling, adaptive sampling; validated on
190
+ printed foil with curl and glare.
191
+ 2. **Erasure decoding:** declare blob-occluded modules as
175
192
  erasures → doubles correctable symbol counts.
176
193
  3. **JavaScript/TypeScript SDK** + online playground (generate a code
177
194
  in the browser in 10 seconds).
@@ -1,4 +1,9 @@
1
1
  # Hexatess Code 🐝
2
+ [![PyPI](https://img.shields.io/pypi/v/hexatess-code)](https://pypi.org/project/hexatess-code/)
3
+
4
+ [![Python](https://img.shields.io/pypi/pyversions/hexatess-code)](https://pypi.org/project/hexatess-code/)
5
+
6
+ [![CI](https://github.com/lovro-abram/hexatess-code/actions/workflows/ci.yml/badge.svg)](https://github.com/lovro-abram/hexatess-code/actions/workflows/ci.yml)
2
7
 
3
8
  **An experimental 2D barcode on a hexagonal grid** — with a hexagonal
4
9
  bullseye finder, spiral serialization and a continuously selectable
@@ -21,7 +26,7 @@ text, stats = decode(grid) # ('Hello, Hexatess!', {...})
21
26
  * **A** — a real encoded symbol: hexagonal bullseye finder (rings 0–4),
22
27
  orientation key (ring 5: two dark cells), data region (rings 6…)
23
28
  filled in spiral order, and a quiet zone of at least 1 module;
24
- * **B** — finder close-up: light centre (v0.1 rule `bit = ring mod 2`),
29
+ * **B** — finder close-up: dark centre (rule `bit = 1 − ring mod 2`),
25
30
  alternating dark/light rings, and the key — the first two canonical
26
31
  ring-5 cells set dark, breaking the 60-fold symmetry and marking the
27
32
  spiral start direction;
@@ -44,27 +49,32 @@ text, stats = decode(grid) # ('Hello, Hexatess!', {...})
44
49
 
45
50
  > **Status: experimental.** This is a young format: the symbol
46
51
  > specification and reference implementation are solid and heavily
47
- > tested (2,500+ tests, conformance vectors), but there is **no camera
48
- > decoder yet** — reading images assumes ideal upright sampling. See
49
- > the roadmap below. Adopting a young format is a deliberate bet; the
50
- > [full format specification](SPECIFICATION.md) is the insurance.
52
+ > tested (2,500+ tests, conformance vectors). A **camera decoder**
53
+ > (`hexatess.camera`, optional `[camera]` extra) already reads symbols
54
+ > from real photographs — printed labels, foil transparencies, tilted
55
+ > and rotated shots. See the roadmap below. Adopting a young format
56
+ > is a deliberate bet; the [full format specification](SPECIFICATION.md)
57
+ > is the insurance.
51
58
 
52
59
  ## Installation
53
60
 
54
61
  ```bash
55
62
  pip install hexatess-code # from PyPI (once published)
63
+ pip install "hexatess-code[camera]" # + photo decoding (numpy, opencv, scipy)
56
64
  # or from a source checkout:
57
65
  pip install -e .
58
66
  ```
59
67
 
60
- Requires Python ≥ 3.8 and Pillow (for rendering only).
68
+ Requires Python ≥ 3.8; Pillow for rendering, numpy + OpenCV + SciPy
69
+ for the optional camera decoder.
61
70
 
62
71
  ## Command line
63
72
 
64
73
  ```bash
65
74
  hexatess "Hello world" -o koda.png --ec 30
66
75
  hexatess "Important URL https://example.org" -o url.png --ec 55
67
- hexatess-code --demo # demo symbol + robustness statistics
76
+ hexatess --demo # demo symbol + robustness statistics
77
+ hexatess decode-photo photo1.jpg photo2.jpg # read symbols from photos
68
78
  ```
69
79
 
70
80
  ## API
@@ -76,6 +86,7 @@ hexatess-code --demo # demo symbol + robustness statistics
76
86
  | `render(grid, path, size_px=18, ...)` | grid → PNG (pointy-top hexagons, quiet zone, supersampling) |
77
87
  | `sample_grid_from_image(path, rmax, ...)` | ideal re-sampling of a rendered PNG (self-test helper) |
78
88
  | `run_tests(...)` | noise/blob robustness statistics |
89
+ | `hexatess.camera.decode_photo(path)` | photograph → `(text, stats)`; finder detection, perspective handling, adaptive sampling (optional `[camera]` extra) |
79
90
 
80
91
  `params` / `stats` contain `rmax` (radius in rings), `mask`, `ec`,
81
92
  `blocks` (list of `(data_bytes, ecc_bytes)`) and `data_len`.
@@ -102,16 +113,18 @@ concentrate inside whole bytes.
102
113
  The format is deliberately **specification-first**: everything needed
103
114
  for an independent implementation is in
104
115
  [`SPECIFICATION.md`](SPECIFICATION.md), and
105
- [`test_vectors/vectors_v0.1.json`](test_vectors/vectors_v0.1.json)
116
+ [`test_vectors/vectors_v0.2.json`](test_vectors/vectors_v0.2.json)
106
117
  contains fixed inputs/outputs (grids, headers, damaged symbols, expected
107
118
  results) to verify conformance. If your Rust/Go/JS decoder passes the
108
119
  vectors, it speaks Hexatess Code.
109
120
 
110
121
  ## Roadmap
111
122
 
112
- 1. **v0.2 — camera decoding:** bullseye detection + perspective
113
- correction (the critical ecosystem step).
114
- 2. **v0.2 — erasure decoding:** declare blob-occluded modules as
123
+ 1. ~~v0.2/0.3 — camera decoding~~ **done (v0.3.0):** `hexatess.camera`
124
+ reads symbols from photographs — bullseye detection, homography +
125
+ correction-field warp handling, adaptive sampling; validated on
126
+ printed foil with curl and glare.
127
+ 2. **Erasure decoding:** declare blob-occluded modules as
115
128
  erasures → doubles correctable symbol counts.
116
129
  3. **JavaScript/TypeScript SDK** + online playground (generate a code
117
130
  in the browser in 10 seconds).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hexatess-code"
7
- version = "0.1.0"
7
+ version = "0.3.0"
8
8
  description = "Hexatess Code - an experimental 2D barcode on a hexagonal grid with Reed-Solomon error correction"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -36,6 +36,11 @@ dependencies = [
36
36
  dev = [
37
37
  "pytest>=7.0",
38
38
  ]
39
+ camera = [
40
+ "numpy>=1.24",
41
+ "opencv-python>=4.8",
42
+ "scipy>=1.10",
43
+ ]
39
44
 
40
45
  [project.urls]
41
46
  Homepage = "https://github.com/lovro-abram/hexatess-code"
@@ -1,6 +1,6 @@
1
1
  """Hexatess Code - an experimental 2D barcode on a hexagonal grid.
2
2
 
3
- Reference implementation of specification v0.1. The symbol is a
3
+ Reference implementation of specification v0.2. The symbol is a
4
4
  hexagonal lattice with a hexagonal bullseye finder, an
5
5
  orientation key ring, spiral serialization from the centre outwards,
6
6
  a Reed-Solomon protected header and a continuously selectable
@@ -18,7 +18,7 @@ Quick start
18
18
  'Hello, Hexatess!'
19
19
 
20
20
  See SPECIFICATION.md in the repository for the full format
21
- specification, and test_vectors/vectors_v0.1.json for conformance
21
+ specification, and test_vectors/vectors_v0.2.json for conformance
22
22
  data usable by independent implementations.
23
23
  """
24
24
 
@@ -57,8 +57,8 @@ from .reedsolomon import rs_correct_msg, rs_encode_msg
57
57
  from .render import render, sample_grid_from_image
58
58
  from .resilience import add_blob_damage, add_random_noise, run_tests
59
59
 
60
- __version__ = "0.1.0"
61
- SPEC_VERSION = "0.1"
60
+ __version__ = "0.3.0"
61
+ SPEC_VERSION = "0.2"
62
62
 
63
63
  __all__ = [
64
64
  # high-level API