roxify 1.9.8 → 1.10.0
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.
- package/LICENSE +63 -21
- package/README.md +163 -163
- package/dist/rox-macos-universal +0 -0
- package/dist/roxify_native +0 -0
- package/dist/roxify_native-macos-arm64 +0 -0
- package/dist/roxify_native-macos-x64 +0 -0
- package/dist/roxify_native.exe +0 -0
- package/dist/utils/decoder.js +0 -28
- package/dist/utils/inspection.d.ts +28 -0
- package/dist/utils/inspection.js +406 -124
- package/dist/utils/native.js +9 -1
- package/dist/utils/rust-cli-wrapper.js +35 -35
- package/package.json +5 -2
- package/roxify_native-aarch64-apple-darwin.node +0 -0
- package/roxify_native-aarch64-pc-windows-msvc.node +0 -0
- package/roxify_native-aarch64-unknown-linux-gnu.node +0 -0
- package/roxify_native-i686-pc-windows-msvc.node +0 -0
- package/roxify_native-i686-unknown-linux-gnu.node +0 -0
- package/roxify_native-x86_64-apple-darwin.node +0 -0
- package/roxify_native-x86_64-pc-windows-gnu.node +0 -0
- package/roxify_native-x86_64-pc-windows-msvc.node +0 -0
- package/roxify_native-x86_64-unknown-linux-gnu.node +0 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,63 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
to
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Roxify Proprietary Open Source License (RPOSL) v1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Yohan SANNIER (RoxasYTB). All rights reserved.
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS
|
|
6
|
+
|
|
7
|
+
1. DEFINITIONS
|
|
8
|
+
"Software" refers to roxify, including all source code, documentation,
|
|
9
|
+
binaries, and associated files in this repository.
|
|
10
|
+
"Author" refers to Yohan SANNIER (RoxasYTB), sole copyright holder.
|
|
11
|
+
"Commercial Use" means any use intended for or directed toward commercial
|
|
12
|
+
advantage or monetary compensation.
|
|
13
|
+
|
|
14
|
+
2. PERMISSIONS
|
|
15
|
+
Subject to the conditions below, you are granted a non-exclusive,
|
|
16
|
+
worldwide, royalty-free license to:
|
|
17
|
+
a) View, read, and study the source code.
|
|
18
|
+
b) Use the Software for personal, educational, or research purposes.
|
|
19
|
+
c) Fork and modify the Software for personal, non-commercial use.
|
|
20
|
+
d) Distribute unmodified copies of the Software for non-commercial
|
|
21
|
+
purposes, provided this license is included in full.
|
|
22
|
+
e) Contribute improvements back to the original repository via pull
|
|
23
|
+
requests.
|
|
24
|
+
|
|
25
|
+
3. RESTRICTIONS
|
|
26
|
+
a) COMMERCIAL USE PROHIBITED — You may NOT use, sell, sublicense,
|
|
27
|
+
redistribute, or otherwise exploit the Software or any derivative
|
|
28
|
+
work for Commercial Use without prior written authorization from
|
|
29
|
+
the Author.
|
|
30
|
+
b) REBRANDING PROHIBITED — You may NOT rebrand, rename, or present a
|
|
31
|
+
modified version of the Software as your own product for
|
|
32
|
+
distribution.
|
|
33
|
+
c) COMPETING PRODUCTS — You may NOT use the Software, in whole or in
|
|
34
|
+
part, to create a competing product or service.
|
|
35
|
+
d) EXCLUSIVE COMMERCIAL RIGHTS — All commercial rights are reserved
|
|
36
|
+
exclusively to the Author. No third party may commercialize this
|
|
37
|
+
Software or any derivative work.
|
|
38
|
+
|
|
39
|
+
4. CONTRIBUTIONS
|
|
40
|
+
By submitting a contribution (pull request, patch, or otherwise) to
|
|
41
|
+
this project, you agree to assign all intellectual property rights
|
|
42
|
+
of your contribution to the Author, and you grant the Author an
|
|
43
|
+
irrevocable, perpetual, worldwide license to use, modify, and
|
|
44
|
+
distribute your contribution under any terms.
|
|
45
|
+
|
|
46
|
+
5. DISCLAIMER
|
|
47
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
48
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
49
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
50
|
+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
51
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
52
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF IT.
|
|
53
|
+
|
|
54
|
+
6. TERMINATION
|
|
55
|
+
This license is automatically terminated if you violate any of its
|
|
56
|
+
terms. Upon termination, you must destroy all copies of the Software
|
|
57
|
+
in your possession.
|
|
58
|
+
|
|
59
|
+
7. GOVERNING LAW
|
|
60
|
+
This license shall be governed by and construed in accordance with
|
|
61
|
+
the laws of France.
|
|
62
|
+
|
|
63
|
+
For commercial licensing inquiries, contact: yohan.sannier@aperture-sciences.com
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Encode binary data into PNG images and decode them back, losslessly. Roxify combines native Rust acceleration, multi-threaded Zstd compression, and AES-256-GCM encryption into a single, portable Node.js module.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/roxify)
|
|
6
|
-
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -60,34 +60,34 @@ All measurements were taken on Linux x64 (Intel i7-6700K @ 4.0 GHz, 32 GB RAM) w
|
|
|
60
60
|
|
|
61
61
|
### Compression Ratio (Maximum Compression for All Tools)
|
|
62
62
|
|
|
63
|
-
| Dataset
|
|
64
|
-
|
|
65
|
-
| Text 1 MB
|
|
66
|
-
| JSON 1 MB
|
|
67
|
-
| Binary 1 MB | 1.00 MB
|
|
68
|
-
| Mixed 5 MB
|
|
69
|
-
| Text 10 MB
|
|
70
|
-
| Mixed 10 MB | 10.00 MB | 4.90 MB (49.0%) | 4.90 MB (49.0%) | 4.65 MB (46.5%) | 4.73 MB (47.3%)
|
|
63
|
+
| Dataset | Original | zip -9 | gzip -9 | 7z LZMA2 -9 | Roxify PNG | Roxify WAV |
|
|
64
|
+
| ----------- | -------- | --------------- | --------------- | --------------- | ------------------- | ------------------- |
|
|
65
|
+
| Text 1 MB | 1.00 MB | 219 KB (21.4%) | 219 KB (21.4%) | 187 KB (18.3%) | **188 KB (18.3%)** | **187 KB (18.3%)** |
|
|
66
|
+
| JSON 1 MB | 1.00 MB | 263 KB (25.7%) | 263 KB (25.7%) | 225 KB (22.0%) | **220 KB (21.5%)** | **219 KB (21.4%)** |
|
|
67
|
+
| Binary 1 MB | 1.00 MB | 1.00 MB (100%) | 1.00 MB (100%) | 1.00 MB (100%) | 1.00 MB (100%) | 1.00 MB (100%) |
|
|
68
|
+
| Mixed 5 MB | 5.00 MB | 2.45 MB (49.0%) | 2.45 MB (49.1%) | 2.33 MB (46.6%) | 2.38 MB (47.6%) | 2.38 MB (47.6%) |
|
|
69
|
+
| Text 10 MB | 10.00 MB | 2.13 MB (21.3%) | 2.13 MB (21.3%) | 1.71 MB (17.1%) | **1.71 MB (17.1%)** | **1.70 MB (17.0%)** |
|
|
70
|
+
| Mixed 10 MB | 10.00 MB | 4.90 MB (49.0%) | 4.90 MB (49.0%) | 4.65 MB (46.5%) | 4.73 MB (47.3%) | 4.73 MB (47.3%) |
|
|
71
71
|
|
|
72
72
|
> **Roxify matches 7z LZMA2 ultra-compression on text** (18.3% for both at 1 MB) and **beats LZMA2 on JSON** (21.4% vs 22.0%). On mixed data, Roxify is within 1 percentage point of LZMA2 while producing a shareable PNG/WAV instead of an archive.
|
|
73
73
|
|
|
74
74
|
### Encode and Decode Speed (CLI)
|
|
75
75
|
|
|
76
|
-
| Dataset
|
|
77
|
-
|
|
78
|
-
| Text 1 MB
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
| JSON 1 MB
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
87
|
-
| Text 10 MB | zip -9
|
|
88
|
-
|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
76
|
+
| Dataset | Tool | Encode | Decode | Enc Throughput | Dec Throughput |
|
|
77
|
+
| ---------- | -------------- | ---------- | ---------- | -------------- | -------------- |
|
|
78
|
+
| Text 1 MB | zip -9 | 112 ms | 36 ms | 8.9 MB/s | 27.6 MB/s |
|
|
79
|
+
| | gzip -9 | 146 ms | 38 ms | 6.9 MB/s | 26.0 MB/s |
|
|
80
|
+
| | 7z LZMA -9 | 303 ms | 21 ms | 3.3 MB/s | 46.6 MB/s |
|
|
81
|
+
| | **Roxify PNG** | **859 ms** | **577 ms** | **1.2 MB/s** | **1.7 MB/s** |
|
|
82
|
+
| | **Roxify WAV** | **794 ms** | **480 ms** | **1.3 MB/s** | **2.1 MB/s** |
|
|
83
|
+
| JSON 1 MB | zip -9 | 79 ms | 20 ms | 12.7 MB/s | 50.5 MB/s |
|
|
84
|
+
| | 7z LZMA -9 | 197 ms | 26 ms | 5.1 MB/s | 37.9 MB/s |
|
|
85
|
+
| | **Roxify PNG** | **1.14 s** | **755 ms** | **0.9 MB/s** | **1.3 MB/s** |
|
|
86
|
+
| | **Roxify WAV** | **1.49 s** | **518 ms** | **0.7 MB/s** | **1.9 MB/s** |
|
|
87
|
+
| Text 10 MB | zip -9 | 1.21 s | 70 ms | 8.2 MB/s | 143.8 MB/s |
|
|
88
|
+
| | 7z LZMA -9 | 5.05 s | 99 ms | 2.0 MB/s | 100.8 MB/s |
|
|
89
|
+
| | **Roxify PNG** | **9.05 s** | **4.53 s** | **1.1 MB/s** | **2.2 MB/s** |
|
|
90
|
+
| | **Roxify WAV** | **9.22 s** | **2.59 s** | **1.1 MB/s** | **3.9 MB/s** |
|
|
91
91
|
|
|
92
92
|
> Roxify CLI includes Node.js startup overhead (~400 ms). In the JS API (below), the same operations are significantly faster. WAV decode is consistently faster than PNG decode due to simpler container parsing.
|
|
93
93
|
|
|
@@ -95,69 +95,69 @@ All measurements were taken on Linux x64 (Intel i7-6700K @ 4.0 GHz, 32 GB RAM) w
|
|
|
95
95
|
|
|
96
96
|
Direct API calls (no CLI startup overhead):
|
|
97
97
|
|
|
98
|
-
| Size
|
|
99
|
-
|
|
100
|
-
| 1 KB
|
|
101
|
-
| 10 KB
|
|
102
|
-
| 100 KB | PNG
|
|
103
|
-
| 500 KB | PNG
|
|
104
|
-
| 1 MB
|
|
105
|
-
| 5 MB
|
|
106
|
-
| 10 MB
|
|
107
|
-
| 1 KB
|
|
108
|
-
| 10 KB
|
|
109
|
-
| 100 KB | WAV
|
|
110
|
-
| 500 KB | WAV
|
|
111
|
-
| 1 MB
|
|
112
|
-
| 5 MB
|
|
113
|
-
| 10 MB
|
|
98
|
+
| Size | Container | Encode | Decode | Enc Throughput | Dec Throughput | Output | Ratio | Integrity |
|
|
99
|
+
| ------ | --------- | ------ | ------- | -------------- | -------------- | --------- | ------ | --------- |
|
|
100
|
+
| 1 KB | PNG | 9 ms | 12 ms | 0.1 MB/s | 0.1 MB/s | 1.14 KB | 114.3% | ✓ |
|
|
101
|
+
| 10 KB | PNG | 18 ms | 34 ms | 0.5 MB/s | 0.3 MB/s | 10.32 KB | 103.2% | ✓ |
|
|
102
|
+
| 100 KB | PNG | 52 ms | 109 ms | 1.9 MB/s | 0.9 MB/s | 100.52 KB | 100.5% | ✓ |
|
|
103
|
+
| 500 KB | PNG | 339 ms | 541 ms | 1.4 MB/s | 0.9 MB/s | 502.64 KB | 100.5% | ✓ |
|
|
104
|
+
| 1 MB | PNG | 875 ms | 1.24 s | 1.1 MB/s | 0.8 MB/s | 1.00 MB | 100.3% | ✓ |
|
|
105
|
+
| 5 MB | PNG | 3.39 s | 4.12 s | 1.5 MB/s | 1.2 MB/s | 5.01 MB | 100.2% | ✓ |
|
|
106
|
+
| 10 MB | PNG | 6.84 s | 12.28 s | 1.5 MB/s | 0.8 MB/s | 10.01 MB | 100.1% | ✓ |
|
|
107
|
+
| 1 KB | WAV | 2 ms | 2 ms | 0.6 MB/s | 0.6 MB/s | 1.08 KB | 107.5% | ✓ |
|
|
108
|
+
| 10 KB | WAV | 4 ms | 5 ms | 2.3 MB/s | 1.8 MB/s | 10.08 KB | 100.8% | ✓ |
|
|
109
|
+
| 100 KB | WAV | 39 ms | 28 ms | 2.5 MB/s | 3.5 MB/s | 100.08 KB | 100.1% | ✓ |
|
|
110
|
+
| 500 KB | WAV | 172 ms | 190 ms | 2.8 MB/s | 2.6 MB/s | 500.09 KB | 100.0% | ✓ |
|
|
111
|
+
| 1 MB | WAV | 452 ms | 276 ms | 2.2 MB/s | 3.6 MB/s | 1.00 MB | 100.0% | ✓ |
|
|
112
|
+
| 5 MB | WAV | 2.70 s | 1.65 s | 1.8 MB/s | 3.0 MB/s | 5.00 MB | 100.0% | ✓ |
|
|
113
|
+
| 10 MB | WAV | 4.81 s | 2.56 s | 2.1 MB/s | 3.9 MB/s | 10.00 MB | 100.0% | ✓ |
|
|
114
114
|
|
|
115
115
|
> WAV container is **2–4× faster** than PNG for decoding at large sizes, and produces slightly smaller output thanks to simpler framing.
|
|
116
116
|
|
|
117
117
|
### Reed-Solomon ECC Throughput
|
|
118
118
|
|
|
119
|
-
| Size
|
|
120
|
-
|
|
121
|
-
| 1 KB
|
|
122
|
-
| 10 KB
|
|
123
|
-
| 100 KB | 49 ms
|
|
124
|
-
| 1 MB
|
|
119
|
+
| Size | Encode | Decode | Enc Throughput | Dec Throughput | Overhead |
|
|
120
|
+
| ------ | ------ | ------ | -------------- | -------------- | -------- |
|
|
121
|
+
| 1 KB | 6 ms | 4 ms | 0.2 MB/s | 0.2 MB/s | 125.7% |
|
|
122
|
+
| 10 KB | 7 ms | 6 ms | 1.3 MB/s | 1.5 MB/s | 119.6% |
|
|
123
|
+
| 100 KB | 49 ms | 45 ms | 2.0 MB/s | 2.1 MB/s | 118.8% |
|
|
124
|
+
| 1 MB | 483 ms | 377 ms | 2.1 MB/s | 2.7 MB/s | 118.6% |
|
|
125
125
|
|
|
126
126
|
### Lossy-Resilient Encoding
|
|
127
127
|
|
|
128
128
|
#### Robust Image (QR-code-style, block size 4×4)
|
|
129
129
|
|
|
130
130
|
| Data Size | Encode Time | Output (PNG) |
|
|
131
|
-
|
|
132
|
-
| 32 B
|
|
133
|
-
| 128 B
|
|
134
|
-
| 512 B
|
|
135
|
-
| 1 KB
|
|
136
|
-
| 2 KB
|
|
131
|
+
| --------- | ----------- | ------------ |
|
|
132
|
+
| 32 B | 32 ms | 122 KB |
|
|
133
|
+
| 128 B | 39 ms | 122 KB |
|
|
134
|
+
| 512 B | 76 ms | 316 KB |
|
|
135
|
+
| 1 KB | 139 ms | 508 KB |
|
|
136
|
+
| 2 KB | 251 ms | 986 KB |
|
|
137
137
|
|
|
138
138
|
#### Robust Audio (MFSK 8-channel, medium ECC)
|
|
139
139
|
|
|
140
140
|
| Data Size | Encode | Decode | Output (WAV) | Integrity |
|
|
141
|
-
|
|
142
|
-
| 10 B
|
|
143
|
-
| 32 B
|
|
144
|
-
| 64 B
|
|
145
|
-
| 128 B
|
|
146
|
-
| 256 B
|
|
141
|
+
| --------- | ------ | ------ | ------------ | --------- |
|
|
142
|
+
| 10 B | 33 ms | 44 ms | 1.35 MB | ✓ |
|
|
143
|
+
| 32 B | 19 ms | 31 ms | 1.35 MB | ✓ |
|
|
144
|
+
| 64 B | 22 ms | 24 ms | 1.35 MB | ✓ |
|
|
145
|
+
| 128 B | 21 ms | 28 ms | 1.35 MB | ✓ |
|
|
146
|
+
| 256 B | 40 ms | 45 ms | 2.59 MB | ✓ |
|
|
147
147
|
|
|
148
148
|
### Data Integrity Verification
|
|
149
149
|
|
|
150
150
|
All encode/decode roundtrips produce bit-exact output, verified by SHA-256:
|
|
151
151
|
|
|
152
|
-
| Test Case
|
|
153
|
-
|
|
154
|
-
| Empty buffer (0 B)
|
|
155
|
-
| Single byte (1 B)
|
|
156
|
-
| All byte values (256 B) | ✓
|
|
157
|
-
| 1 KB text
|
|
158
|
-
| 100 KB random
|
|
159
|
-
| 1 MB random
|
|
160
|
-
| 5 MB random
|
|
152
|
+
| Test Case | PNG | WAV |
|
|
153
|
+
| ----------------------- | --- | --- |
|
|
154
|
+
| Empty buffer (0 B) | ✓ | ✓ |
|
|
155
|
+
| Single byte (1 B) | ✓ | ✓ |
|
|
156
|
+
| All byte values (256 B) | ✓ | ✓ |
|
|
157
|
+
| 1 KB text | ✓ | ✓ |
|
|
158
|
+
| 100 KB random | ✓ | ✓ |
|
|
159
|
+
| 1 MB random | ✓ | ✓ |
|
|
160
|
+
| 5 MB random | ✓ | ✓ |
|
|
161
161
|
|
|
162
162
|
**14 / 14 integrity tests passed** across both containers.
|
|
163
163
|
|
|
@@ -175,12 +175,12 @@ All encode/decode roundtrips produce bit-exact output, verified by SHA-256:
|
|
|
175
175
|
|
|
176
176
|
Benchmarks were generated using `test/benchmark-detailed.cjs`. Datasets consist of procedurally generated text, JSON, and random binary data. Each tool was invoked with its maximum compression setting:
|
|
177
177
|
|
|
178
|
-
| Tool
|
|
179
|
-
|
|
180
|
-
| zip
|
|
181
|
-
| tar/gzip | `tar -cf - \| gzip -9`
|
|
182
|
-
| 7z
|
|
183
|
-
| Roxify
|
|
178
|
+
| Tool | Command / Setting |
|
|
179
|
+
| -------- | --------------------------- |
|
|
180
|
+
| zip | `zip -r -q -9` |
|
|
181
|
+
| tar/gzip | `tar -cf - \| gzip -9` |
|
|
182
|
+
| 7z | `7z a -mx=9` (LZMA2 ultra) |
|
|
183
|
+
| Roxify | Zstd level 19, compact mode |
|
|
184
184
|
|
|
185
185
|
To reproduce:
|
|
186
186
|
|
|
@@ -222,14 +222,14 @@ rox encode input.zip output.png
|
|
|
222
222
|
rox encode <input> [output] [options]
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
| Option
|
|
226
|
-
|
|
227
|
-
| `-p, --passphrase <pass>` | Encrypt with AES-256-GCM
|
|
228
|
-
| `-m, --mode <mode>`
|
|
229
|
-
| `-q, --quality <0-11>`
|
|
230
|
-
| `-e, --encrypt <type>`
|
|
231
|
-
| `--no-compress`
|
|
232
|
-
| `-o, --output <path>`
|
|
225
|
+
| Option | Description | Default |
|
|
226
|
+
| ------------------------- | ----------------------------------------------- | -------------------------- |
|
|
227
|
+
| `-p, --passphrase <pass>` | Encrypt with AES-256-GCM | none |
|
|
228
|
+
| `-m, --mode <mode>` | Encoding mode: `screenshot`, `compact` | `screenshot` |
|
|
229
|
+
| `-q, --quality <0-11>` | Compression effort (0 = fastest, 11 = smallest) | `1` |
|
|
230
|
+
| `-e, --encrypt <type>` | Encryption method: `auto`, `aes`, `xor`, `none` | `aes` if passphrase is set |
|
|
231
|
+
| `--no-compress` | Disable compression entirely | false |
|
|
232
|
+
| `-o, --output <path>` | Explicit output file path | auto-generated |
|
|
233
233
|
|
|
234
234
|
### Decoding
|
|
235
235
|
|
|
@@ -237,11 +237,11 @@ rox encode <input> [output] [options]
|
|
|
237
237
|
rox decode <input> [output] [options]
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
-
| Option
|
|
241
|
-
|
|
242
|
-
| `-p, --passphrase <pass>` | Decryption passphrase
|
|
243
|
-
| `-o, --output <path>`
|
|
244
|
-
| `--dict <file>`
|
|
240
|
+
| Option | Description | Default |
|
|
241
|
+
| ------------------------- | ------------------------------------------ | --------------------------- |
|
|
242
|
+
| `-p, --passphrase <pass>` | Decryption passphrase | none |
|
|
243
|
+
| `-o, --output <path>` | Output file path | auto-detected from metadata |
|
|
244
|
+
| `--dict <file>` | Zstd dictionary for improved decompression | none |
|
|
245
245
|
|
|
246
246
|
### Examples
|
|
247
247
|
|
|
@@ -334,22 +334,22 @@ const png = await encodeBinaryToPng(largeBuffer, {
|
|
|
334
334
|
|
|
335
335
|
```typescript
|
|
336
336
|
interface EncodeOptions {
|
|
337
|
-
compression?: 'zstd';
|
|
338
|
-
compressionLevel?: number;
|
|
339
|
-
passphrase?: string;
|
|
340
|
-
dict?: Buffer;
|
|
341
|
-
name?: string;
|
|
342
|
-
mode?: 'screenshot';
|
|
337
|
+
compression?: 'zstd'; // Compression algorithm
|
|
338
|
+
compressionLevel?: number; // Zstd compression level (0-19)
|
|
339
|
+
passphrase?: string; // Encryption passphrase
|
|
340
|
+
dict?: Buffer; // Zstd dictionary for improved ratios
|
|
341
|
+
name?: string; // Original filename stored in metadata
|
|
342
|
+
mode?: 'screenshot'; // Encoding mode
|
|
343
343
|
encrypt?: 'auto' | 'aes' | 'xor' | 'none';
|
|
344
344
|
output?: 'auto' | 'png' | 'rox'; // Output format
|
|
345
|
-
includeName?: boolean;
|
|
346
|
-
includeFileList?: boolean;
|
|
345
|
+
includeName?: boolean; // Include filename in PNG metadata
|
|
346
|
+
includeFileList?: boolean; // Include file manifest in PNG
|
|
347
347
|
fileList?: Array<string | { name: string; size: number }>;
|
|
348
|
-
skipOptimization?: boolean;
|
|
349
|
-
lossyResilient?: boolean;
|
|
350
|
-
eccLevel?: EccLevel;
|
|
351
|
-
robustBlockSize?: number;
|
|
352
|
-
container?: 'image' | 'sound';
|
|
348
|
+
skipOptimization?: boolean; // Skip PNG optimization pass
|
|
349
|
+
lossyResilient?: boolean; // Enable lossy-resilient encoding (RS ECC)
|
|
350
|
+
eccLevel?: EccLevel; // 'low' | 'medium' | 'quartile' | 'high'
|
|
351
|
+
robustBlockSize?: number; // 2–8 pixels per data block (lossy image)
|
|
352
|
+
container?: 'image' | 'sound'; // Output container format
|
|
353
353
|
onProgress?: (info: ProgressInfo) => void;
|
|
354
354
|
showProgress?: boolean;
|
|
355
355
|
verbose?: boolean;
|
|
@@ -360,9 +360,9 @@ interface EncodeOptions {
|
|
|
360
360
|
|
|
361
361
|
```typescript
|
|
362
362
|
interface DecodeOptions {
|
|
363
|
-
passphrase?: string;
|
|
364
|
-
outPath?: string;
|
|
365
|
-
files?: string[];
|
|
363
|
+
passphrase?: string; // Decryption passphrase
|
|
364
|
+
outPath?: string; // Output directory for unpacked files
|
|
365
|
+
files?: string[]; // Extract only specific files from archive
|
|
366
366
|
onProgress?: (info: ProgressInfo) => void;
|
|
367
367
|
showProgress?: boolean;
|
|
368
368
|
verbose?: boolean;
|
|
@@ -373,10 +373,10 @@ interface DecodeOptions {
|
|
|
373
373
|
|
|
374
374
|
```typescript
|
|
375
375
|
interface DecodeResult {
|
|
376
|
-
buf?: Buffer;
|
|
377
|
-
meta?: { name?: string };
|
|
378
|
-
files?: PackedFile[];
|
|
379
|
-
correctedErrors?: number;
|
|
376
|
+
buf?: Buffer; // Decoded binary payload
|
|
377
|
+
meta?: { name?: string }; // Metadata (original filename)
|
|
378
|
+
files?: PackedFile[]; // Unpacked directory entries, if applicable
|
|
379
|
+
correctedErrors?: number; // RS errors corrected (lossy-resilient mode)
|
|
380
380
|
}
|
|
381
381
|
```
|
|
382
382
|
|
|
@@ -384,10 +384,10 @@ interface DecodeResult {
|
|
|
384
384
|
|
|
385
385
|
## Encoding Modes
|
|
386
386
|
|
|
387
|
-
| Mode
|
|
388
|
-
|
|
387
|
+
| Mode | Description | Use Case |
|
|
388
|
+
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
389
389
|
| `screenshot` | Encodes data as RGB pixels in a standard PNG. The image looks like a gradient or noise pattern and survives re-uploads and social media processing. | Sharing on image-only platforms, bypassing file-type filters |
|
|
390
|
-
| `compact`
|
|
390
|
+
| `compact` | Minimal 1x1 PNG with data embedded in a custom ancillary chunk (`rXDT`). Produces the smallest possible output. | Programmatic use, archival, maximum compression ratio |
|
|
391
391
|
|
|
392
392
|
### Stretch-Resilient Decoding
|
|
393
393
|
|
|
@@ -410,10 +410,10 @@ rox decode zoomed-screenshot.png -o output/
|
|
|
410
410
|
|
|
411
411
|
Roxify supports two encryption methods:
|
|
412
412
|
|
|
413
|
-
| Method | Algorithm
|
|
414
|
-
|
|
415
|
-
| `aes`
|
|
416
|
-
| `xor`
|
|
413
|
+
| Method | Algorithm | Strength | Use Case |
|
|
414
|
+
| ------ | -------------------------------------------- | ---------------------------------------------- | -------------------------------------- |
|
|
415
|
+
| `aes` | AES-256-GCM with PBKDF2 (100,000 iterations) | Cryptographically secure, authenticated | Sensitive data, confidential documents |
|
|
416
|
+
| `xor` | XOR cipher with passphrase-derived key | Obfuscation only, not cryptographically secure | Casual deterrent against inspection |
|
|
417
417
|
|
|
418
418
|
When `encrypt` is set to `auto` (the default when a passphrase is provided), AES is selected.
|
|
419
419
|
|
|
@@ -432,12 +432,12 @@ Enable `lossyResilient: true` to produce output that survives lossy compression.
|
|
|
432
432
|
|
|
433
433
|
### Error Correction Levels
|
|
434
434
|
|
|
435
|
-
| Level
|
|
436
|
-
|
|
437
|
-
| `low`
|
|
438
|
-
| `medium`
|
|
439
|
-
| `quartile` |
|
|
440
|
-
| `high`
|
|
435
|
+
| Level | Parity Symbols | Overhead | Correctable Errors |
|
|
436
|
+
| ---------- | -------------: | -------: | -----------------: |
|
|
437
|
+
| `low` | 20 / block | ~10% | ~4% |
|
|
438
|
+
| `medium` | 40 / block | ~19% | ~9% |
|
|
439
|
+
| `quartile` | 64 / block | ~33% | ~15% |
|
|
440
|
+
| `high` | 128 / block | ~100% | ~25% |
|
|
441
441
|
|
|
442
442
|
### Example
|
|
443
443
|
|
|
@@ -446,7 +446,7 @@ Enable `lossyResilient: true` to produce output that survives lossy compression.
|
|
|
446
446
|
const png = await encodeBinaryToPng(data, {
|
|
447
447
|
lossyResilient: true,
|
|
448
448
|
eccLevel: 'quartile',
|
|
449
|
-
robustBlockSize: 4,
|
|
449
|
+
robustBlockSize: 4, // 4×4 pixels per data bit
|
|
450
450
|
});
|
|
451
451
|
|
|
452
452
|
// Audio that survives MP3 compression
|
|
@@ -498,12 +498,12 @@ const wav = await encodeBinaryToPng(data, {
|
|
|
498
498
|
|
|
499
499
|
The `compressionLevel` option (CLI: `-q`) controls the trade-off between speed and output size:
|
|
500
500
|
|
|
501
|
-
| Level | Speed
|
|
502
|
-
|
|
503
|
-
| 0
|
|
504
|
-
| 1
|
|
505
|
-
| 5
|
|
506
|
-
| 11
|
|
501
|
+
| Level | Speed | Ratio | Recommendation |
|
|
502
|
+
| ----- | -------- | -------- | ----------------------------------------- |
|
|
503
|
+
| 0 | Fastest | Largest | Files over 100 MB, real-time workflows |
|
|
504
|
+
| 1 | Fast | Good | Default; general-purpose use |
|
|
505
|
+
| 5 | Moderate | Better | Archival of medium-sized datasets |
|
|
506
|
+
| 11 | Slowest | Smallest | Small files under 1 MB, long-term storage |
|
|
507
507
|
|
|
508
508
|
### Native Module
|
|
509
509
|
|
|
@@ -533,12 +533,12 @@ const png = await encodeBinaryToPng(data, { dict });
|
|
|
533
533
|
|
|
534
534
|
Roxify ships prebuilt native modules for the following targets:
|
|
535
535
|
|
|
536
|
-
| Platform | Architecture
|
|
537
|
-
|
|
538
|
-
| Linux
|
|
539
|
-
| macOS
|
|
540
|
-
| macOS
|
|
541
|
-
| Windows
|
|
536
|
+
| Platform | Architecture | Binary Name |
|
|
537
|
+
| -------- | --------------------- | ------------------------------------------------ |
|
|
538
|
+
| Linux | x86_64 | `libroxify_native-x86_64-unknown-linux-gnu.node` |
|
|
539
|
+
| macOS | x86_64 | `libroxify_native-x86_64-apple-darwin.node` |
|
|
540
|
+
| macOS | ARM64 (Apple Silicon) | `libroxify_native-aarch64-apple-darwin.node` |
|
|
541
|
+
| Windows | x86_64 | `roxify_native-x86_64-pc-windows-msvc.node` |
|
|
542
542
|
|
|
543
543
|
The correct binary is resolved automatically at runtime. If no binary is found for the current platform, Roxify falls back silently to the pure JavaScript implementation.
|
|
544
544
|
|
|
@@ -630,35 +630,35 @@ Input --> Detect Format --> Demodulate/Read Blocks --> De-interleave --> RS ECC
|
|
|
630
630
|
|
|
631
631
|
### Rust Modules
|
|
632
632
|
|
|
633
|
-
| Module
|
|
634
|
-
|
|
635
|
-
| `core.rs`
|
|
636
|
-
| `encoder.rs`
|
|
637
|
-
| `packer.rs`
|
|
638
|
-
| `crypto.rs`
|
|
639
|
-
| `archive.rs`
|
|
640
|
-
| `reconstitution.rs` | Screenshot detection and automatic crop to recover encoded data
|
|
641
|
-
| `audio.rs`
|
|
642
|
-
| `bwt.rs`
|
|
643
|
-
| `rans.rs`
|
|
644
|
-
| `hybrid.rs`
|
|
645
|
-
| `pool.rs`
|
|
646
|
-
| `image_utils.rs`
|
|
647
|
-
| `png_utils.rs`
|
|
648
|
-
| `progress.rs`
|
|
633
|
+
| Module | Responsibility |
|
|
634
|
+
| ------------------- | ---------------------------------------------------------------------- |
|
|
635
|
+
| `core.rs` | Pixel scanning, CRC32, Adler32, delta coding, Zstd compress/decompress |
|
|
636
|
+
| `encoder.rs` | PNG payload encoding with marker pixels and metadata chunks |
|
|
637
|
+
| `packer.rs` | Directory tree serialization and streaming deserialization |
|
|
638
|
+
| `crypto.rs` | AES-256-GCM encryption and PBKDF2 key derivation |
|
|
639
|
+
| `archive.rs` | Tar-based archiving with optional Zstd compression |
|
|
640
|
+
| `reconstitution.rs` | Screenshot detection and automatic crop to recover encoded data |
|
|
641
|
+
| `audio.rs` | WAV container encoding and decoding (PCM byte packing) |
|
|
642
|
+
| `bwt.rs` | Parallel Burrows-Wheeler Transform |
|
|
643
|
+
| `rans.rs` | rANS (Asymmetric Numeral Systems) entropy coder |
|
|
644
|
+
| `hybrid.rs` | Block-based orchestration of BWT, context mixing, and rANS |
|
|
645
|
+
| `pool.rs` | Buffer pooling and zero-copy memory management |
|
|
646
|
+
| `image_utils.rs` | Image resizing, pixel format conversion, metadata extraction |
|
|
647
|
+
| `png_utils.rs` | Low-level PNG chunk read/write operations |
|
|
648
|
+
| `progress.rs` | Progress tracking for long-running compression/decompression |
|
|
649
649
|
|
|
650
650
|
### TypeScript Modules
|
|
651
651
|
|
|
652
|
-
| Module
|
|
653
|
-
|
|
654
|
-
| `ecc.ts`
|
|
652
|
+
| Module | Responsibility |
|
|
653
|
+
| ----------------- | --------------------------------------------------------------------- |
|
|
654
|
+
| `ecc.ts` | Reed-Solomon GF(256) codec, block ECC, interleaving |
|
|
655
655
|
| `robust-audio.ts` | MFSK audio modulation/demodulation, Goertzel detection, sync preamble |
|
|
656
|
-
| `robust-image.ts` | QR-code-like block encoding, finder patterns, majority voting
|
|
657
|
-
| `encoder.ts`
|
|
658
|
-
| `decoder.ts`
|
|
659
|
-
| `audio.ts`
|
|
660
|
-
| `helpers.ts`
|
|
661
|
-
| `zstd.ts`
|
|
656
|
+
| `robust-image.ts` | QR-code-like block encoding, finder patterns, majority voting |
|
|
657
|
+
| `encoder.ts` | High-level encoding orchestration (standard + lossy-resilient) |
|
|
658
|
+
| `decoder.ts` | High-level decoding with automatic format detection |
|
|
659
|
+
| `audio.ts` | Standard WAV container (8-bit PCM) |
|
|
660
|
+
| `helpers.ts` | Delta coding, XOR cipher, palette generation |
|
|
661
|
+
| `zstd.ts` | Parallel Zstd compression via native module |
|
|
662
662
|
|
|
663
663
|
---
|
|
664
664
|
|
|
@@ -684,11 +684,11 @@ try {
|
|
|
684
684
|
}
|
|
685
685
|
```
|
|
686
686
|
|
|
687
|
-
| Error
|
|
688
|
-
|
|
689
|
-
| `Incorrect passphrase`
|
|
690
|
-
| `not a valid PNG`
|
|
691
|
-
| `Passphrase required`
|
|
687
|
+
| Error | Cause |
|
|
688
|
+
| --------------------------- | ------------------------------------------------- |
|
|
689
|
+
| `Incorrect passphrase` | Wrong password provided for decryption |
|
|
690
|
+
| `not a valid PNG` | Input buffer is not a PNG or lacks Roxify markers |
|
|
691
|
+
| `Passphrase required` | File is encrypted but no passphrase was supplied |
|
|
692
692
|
| `Image too large to decode` | PNG dimensions exceed the in-process memory limit |
|
|
693
693
|
|
|
694
694
|
---
|
|
@@ -716,7 +716,7 @@ Contributions are welcome. Please open an issue to discuss proposed changes befo
|
|
|
716
716
|
|
|
717
717
|
## License
|
|
718
718
|
|
|
719
|
-
|
|
719
|
+
This project is licensed under the **Roxify Proprietary Open Source License (RPOSL)**. The source code is freely available for personal, educational, and research use. All commercial rights are exclusively reserved to the author. See [LICENSE](LICENSE) for details.
|
|
720
720
|
|
|
721
721
|
---
|
|
722
722
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/roxify_native.exe
CHANGED
|
Binary file
|
package/dist/utils/decoder.js
CHANGED
|
@@ -1170,34 +1170,6 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
1170
1170
|
e instanceof DataFormatError) {
|
|
1171
1171
|
throw e;
|
|
1172
1172
|
}
|
|
1173
|
-
try {
|
|
1174
|
-
const rawPayload = Buffer.from(native.extractPayloadFromPng(processedBuf));
|
|
1175
|
-
let payload = tryDecryptIfNeeded(rawPayload, opts.passphrase);
|
|
1176
|
-
payload = await tryDecompress(payload, (info) => {
|
|
1177
|
-
if (opts.onProgress)
|
|
1178
|
-
opts.onProgress(info);
|
|
1179
|
-
});
|
|
1180
|
-
if (!payload.slice(0, MAGIC.length).equals(MAGIC)) {
|
|
1181
|
-
throw new DataFormatError('Missing ROX1 magic after native extraction');
|
|
1182
|
-
}
|
|
1183
|
-
payload = payload.slice(MAGIC.length);
|
|
1184
|
-
const nameFromPng = native.extractNameFromPng
|
|
1185
|
-
? (() => { try {
|
|
1186
|
-
return native.extractNameFromPng(processedBuf);
|
|
1187
|
-
}
|
|
1188
|
-
catch {
|
|
1189
|
-
return undefined;
|
|
1190
|
-
} })()
|
|
1191
|
-
: undefined;
|
|
1192
|
-
return { buf: payload, meta: { name: nameFromPng } };
|
|
1193
|
-
}
|
|
1194
|
-
catch (nativeErr) {
|
|
1195
|
-
if (nativeErr instanceof PassphraseRequiredError ||
|
|
1196
|
-
nativeErr instanceof IncorrectPassphraseError ||
|
|
1197
|
-
nativeErr instanceof DataFormatError) {
|
|
1198
|
-
throw nativeErr;
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
1173
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
1202
1174
|
throw new Error('Failed to decode PNG: ' + errMsg);
|
|
1203
1175
|
}
|