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 CHANGED
@@ -1,21 +1,63 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 RoxCompressor
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
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
  [![npm version](https://img.shields.io/npm/v/roxify.svg)](https://www.npmjs.com/package/roxify)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+ [![License: RPOSL](https://img.shields.io/badge/License-RPOSL-red.svg)](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 | 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%) |
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 | 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** |
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 | 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% | ✓ |
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 | 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% |
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 | 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 |
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 | 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 | ✓ |
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 | 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 | ✓ | ✓ |
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 | 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 |
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 | 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 |
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 | 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 |
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'; // 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
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; // Include filename in PNG metadata
346
- includeFileList?: boolean; // Include file manifest in PNG
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; // 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
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; // Decryption passphrase
364
- outPath?: string; // Output directory for unpacked files
365
- files?: string[]; // Extract only specific files from archive
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; // 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)
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 | Description | Use Case |
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` | Minimal 1x1 PNG with data embedded in a custom ancillary chunk (`rXDT`). Produces the smallest possible output. | Programmatic use, archival, maximum compression ratio |
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 | 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 |
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 | 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% |
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, // 4×4 pixels per data bit
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 | 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 |
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 | 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` |
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 | 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 |
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 | Responsibility |
653
- |---|---|
654
- | `ecc.ts` | Reed-Solomon GF(256) codec, block ECC, interleaving |
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` | 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 |
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 | 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 |
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
- MIT. See [LICENSE](LICENSE) for details.
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
Binary file
@@ -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
  }