roxify 1.6.5 → 1.6.7
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/README.md +550 -212
- package/dist/cli.js +54 -23
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/pack.d.ts +1 -0
- package/dist/pack.js +52 -3
- package/dist/utils/audio.d.ts +23 -0
- package/dist/utils/audio.js +98 -0
- package/dist/utils/decoder.js +114 -21
- package/dist/utils/ecc.d.ts +75 -0
- package/dist/utils/ecc.js +446 -0
- package/dist/utils/encoder.js +155 -49
- package/dist/utils/native.js +43 -26
- package/dist/utils/robust-audio.d.ts +54 -0
- package/dist/utils/robust-audio.js +400 -0
- package/dist/utils/robust-image.d.ts +54 -0
- package/dist/utils/robust-image.js +515 -0
- package/dist/utils/types.d.ts +26 -0
- package/dist/utils/zstd.d.ts +2 -2
- package/dist/utils/zstd.js +41 -18
- package/package.json +7 -6
- package/roxify_native-x86_64-unknown-linux-gnu.node +0 -0
- package/roxify_native.node +0 -0
- package/dist/_esmodule_test.d.ts +0 -1
- package/dist/_esmodule_test.js +0 -1
- package/dist/hybrid-compression.d.ts +0 -25
- package/dist/hybrid-compression.js +0 -90
- package/dist/minpng.d.ts +0 -20
- package/dist/minpng.js +0 -285
- package/dist/rox.exe +0 -0
- package/dist/roxify_native-x86_64-pc-windows-gnu.node +0 -0
- package/dist/roxify_native-x86_64-unknown-linux-gnu.node +0 -0
- package/dist/roxify_native.exe +0 -0
- package/dist/roxify_native.node +0 -0
- package/roxify_native-x86_64-pc-windows-msvc.node +0 -0
package/README.md
CHANGED
|
@@ -1,377 +1,715 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Roxify
|
|
2
2
|
|
|
3
|
-
> Encode binary data into PNG images and decode them back.
|
|
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
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- ⚡ **Blazing Fast**: Native Rust acceleration via N-API — **1GB/s** throughput on modern hardware
|
|
11
|
-
- 🚀 **Optimized Compression**: Multi-threaded Zstd compression (level 19) with parallel processing
|
|
12
|
-
- 🔒 **Secure**: AES-256-GCM encryption support with PBKDF2 key derivation
|
|
13
|
-
- 🎨 **Multiple modes**: Compact, chunk, pixel, and screenshot modes
|
|
14
|
-
- 📦 **CLI & API**: Use as command-line tool or JavaScript library
|
|
15
|
-
- 🔄 **Lossless**: Perfect roundtrip encoding/decoding
|
|
16
|
-
- 📖 **Full TSDoc**: Complete TypeScript documentation
|
|
17
|
-
- 🦀 **Rust Powered**: Optional native module for extreme performance (falls back to pure JS)
|
|
8
|
+
---
|
|
18
9
|
|
|
19
|
-
##
|
|
10
|
+
## Table of Contents
|
|
20
11
|
|
|
21
|
-
|
|
12
|
+
- [Overview](#overview)
|
|
13
|
+
- [Features](#features)
|
|
14
|
+
- [Benchmarks](#benchmarks)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [CLI Usage](#cli-usage)
|
|
17
|
+
- [JavaScript API](#javascript-api)
|
|
18
|
+
- [Encoding Modes](#encoding-modes)
|
|
19
|
+
- [Encryption](#encryption)
|
|
20
|
+
- [Performance Tuning](#performance-tuning)
|
|
21
|
+
- [Cross-Platform Support](#cross-platform-support)
|
|
22
|
+
- [Building from Source](#building-from-source)
|
|
23
|
+
- [Architecture](#architecture)
|
|
24
|
+
- [Error Handling](#error-handling)
|
|
25
|
+
- [Security Considerations](#security-considerations)
|
|
26
|
+
- [Contributing](#contributing)
|
|
27
|
+
- [License](#license)
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
---
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
## Overview
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
| -------- | ------: | -------: | ---------: | --------: | -----: | ---------: | ------------------------------------------- |
|
|
29
|
-
| 4,000 MB | 731,340 | 3.93 GB | 111.42 MB | **2.8%** | 26.9 s | 149.4 MB/s | gzip: 2.26 GB (57.5%); 7z: 1.87 GB (47.6%) |
|
|
30
|
-
| 1,000 MB | 141,522 | 1.03 GB | 205 MB | **19.4%** | ~6.2 s | ≈170 MB/s | shows benefits for many-small-file datasets |
|
|
33
|
+
Roxify is a PNG steganography toolkit. It packs arbitrary binary data -- files, directories, or raw buffers -- into standard PNG images that can be shared, uploaded, and stored anywhere images are accepted. The data is compressed with multi-threaded Zstd, optionally encrypted with AES-256-GCM, and embedded in valid PNG structures that survive re-uploads and screenshots.
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
The core compression and image-processing logic is written in Rust and exposed to Node.js through N-API. When the native module is unavailable, Roxify falls back to a pure TypeScript implementation transparently.
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
- Setup: parallel I/O and multithreaded compression on modern SSD-backed systems.
|
|
36
|
-
- Measurements: wall-clock time; throughput = original size / time; comparisons against gzip and 7z with typical defaults.
|
|
37
|
-
- Reproducibility: full benchmark details, commands and raw data are available in `docs/BENCHMARK_FINAL_REPORT.md`.
|
|
37
|
+
---
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
## Features
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
- **Native Rust acceleration** via N-API with automatic fallback to pure JavaScript
|
|
42
|
+
- **Multi-threaded Zstd compression** (level 19) with parallel chunk processing via Rayon
|
|
43
|
+
- **AES-256-GCM encryption** with PBKDF2 key derivation (100,000 iterations)
|
|
44
|
+
- **Lossless roundtrip** -- encoded data is recovered byte-for-byte
|
|
45
|
+
- **Lossy-resilient mode** -- QR-code-style Reed-Solomon error correction survives JPEG, WebP, MP3, AAC, and OGG recompression
|
|
46
|
+
- **Audio container** -- encode data as structured multi-frequency tones (not white noise) in WAV files
|
|
47
|
+
- **Directory packing** -- encode entire directory trees into a single PNG
|
|
48
|
+
- **Screenshot reconstitution** -- recover data from photographed or screenshotted PNGs
|
|
49
|
+
- **CLI and programmatic API** -- use from the terminal or import as a library
|
|
50
|
+
- **Cross-platform** -- prebuilt binaries for Linux x64, macOS x64/ARM64, and Windows x64
|
|
51
|
+
- **Full TypeScript support** with exported types and TSDoc annotations
|
|
52
|
+
- **mimalloc allocator** for reduced memory fragmentation under heavy workloads
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Benchmarks
|
|
57
|
+
|
|
58
|
+
All measurements were taken on Linux x64 (Intel i7-6700K @ 4.0 GHz, 32 GB RAM) with Node.js v20. Every tool uses its **maximum compression** setting: zip -9, gzip -9, 7z LZMA2 -mx=9, and Roxify Zstd level 19. Roxify produces a valid PNG or WAV file rather than a raw archive.
|
|
59
|
+
|
|
60
|
+
### Compression Ratio (Maximum Compression for All Tools)
|
|
61
|
+
|
|
62
|
+
| Dataset | Original | zip -9 | gzip -9 | 7z LZMA2 -9 | Roxify PNG | Roxify WAV |
|
|
63
|
+
|---|---|---|---|---|---|---|
|
|
64
|
+
| 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%)** |
|
|
65
|
+
| 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%)** |
|
|
66
|
+
| 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%) |
|
|
67
|
+
| 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%) |
|
|
68
|
+
| 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%)** |
|
|
69
|
+
| 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%) |
|
|
70
|
+
|
|
71
|
+
> **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.
|
|
72
|
+
|
|
73
|
+
### Encode and Decode Speed (CLI)
|
|
74
|
+
|
|
75
|
+
| Dataset | Tool | Encode | Decode | Enc Throughput | Dec Throughput |
|
|
76
|
+
|---|---|---|---|---|---|
|
|
77
|
+
| Text 1 MB | zip -9 | 112 ms | 36 ms | 8.9 MB/s | 27.6 MB/s |
|
|
78
|
+
| | gzip -9 | 146 ms | 38 ms | 6.9 MB/s | 26.0 MB/s |
|
|
79
|
+
| | 7z LZMA -9 | 303 ms | 21 ms | 3.3 MB/s | 46.6 MB/s |
|
|
80
|
+
| | **Roxify PNG** | **859 ms** | **577 ms** | **1.2 MB/s** | **1.7 MB/s** |
|
|
81
|
+
| | **Roxify WAV** | **794 ms** | **480 ms** | **1.3 MB/s** | **2.1 MB/s** |
|
|
82
|
+
| JSON 1 MB | zip -9 | 79 ms | 20 ms | 12.7 MB/s | 50.5 MB/s |
|
|
83
|
+
| | 7z LZMA -9 | 197 ms | 26 ms | 5.1 MB/s | 37.9 MB/s |
|
|
84
|
+
| | **Roxify PNG** | **1.14 s** | **755 ms** | **0.9 MB/s** | **1.3 MB/s** |
|
|
85
|
+
| | **Roxify WAV** | **1.49 s** | **518 ms** | **0.7 MB/s** | **1.9 MB/s** |
|
|
86
|
+
| Text 10 MB | zip -9 | 1.21 s | 70 ms | 8.2 MB/s | 143.8 MB/s |
|
|
87
|
+
| | 7z LZMA -9 | 5.05 s | 99 ms | 2.0 MB/s | 100.8 MB/s |
|
|
88
|
+
| | **Roxify PNG** | **9.05 s** | **4.53 s** | **1.1 MB/s** | **2.2 MB/s** |
|
|
89
|
+
| | **Roxify WAV** | **9.22 s** | **2.59 s** | **1.1 MB/s** | **3.9 MB/s** |
|
|
90
|
+
|
|
91
|
+
> 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.
|
|
92
|
+
|
|
93
|
+
### JavaScript API Throughput
|
|
94
|
+
|
|
95
|
+
Direct API calls (no CLI startup overhead):
|
|
96
|
+
|
|
97
|
+
| Size | Container | Encode | Decode | Enc Throughput | Dec Throughput | Output | Ratio | Integrity |
|
|
98
|
+
|---|---|---|---|---|---|---|---|---|
|
|
99
|
+
| 1 KB | PNG | 9 ms | 12 ms | 0.1 MB/s | 0.1 MB/s | 1.14 KB | 114.3% | ✓ |
|
|
100
|
+
| 10 KB | PNG | 18 ms | 34 ms | 0.5 MB/s | 0.3 MB/s | 10.32 KB | 103.2% | ✓ |
|
|
101
|
+
| 100 KB | PNG | 52 ms | 109 ms | 1.9 MB/s | 0.9 MB/s | 100.52 KB | 100.5% | ✓ |
|
|
102
|
+
| 500 KB | PNG | 339 ms | 541 ms | 1.4 MB/s | 0.9 MB/s | 502.64 KB | 100.5% | ✓ |
|
|
103
|
+
| 1 MB | PNG | 875 ms | 1.24 s | 1.1 MB/s | 0.8 MB/s | 1.00 MB | 100.3% | ✓ |
|
|
104
|
+
| 5 MB | PNG | 3.39 s | 4.12 s | 1.5 MB/s | 1.2 MB/s | 5.01 MB | 100.2% | ✓ |
|
|
105
|
+
| 10 MB | PNG | 6.84 s | 12.28 s | 1.5 MB/s | 0.8 MB/s | 10.01 MB | 100.1% | ✓ |
|
|
106
|
+
| 1 KB | WAV | 2 ms | 2 ms | 0.6 MB/s | 0.6 MB/s | 1.08 KB | 107.5% | ✓ |
|
|
107
|
+
| 10 KB | WAV | 4 ms | 5 ms | 2.3 MB/s | 1.8 MB/s | 10.08 KB | 100.8% | ✓ |
|
|
108
|
+
| 100 KB | WAV | 39 ms | 28 ms | 2.5 MB/s | 3.5 MB/s | 100.08 KB | 100.1% | ✓ |
|
|
109
|
+
| 500 KB | WAV | 172 ms | 190 ms | 2.8 MB/s | 2.6 MB/s | 500.09 KB | 100.0% | ✓ |
|
|
110
|
+
| 1 MB | WAV | 452 ms | 276 ms | 2.2 MB/s | 3.6 MB/s | 1.00 MB | 100.0% | ✓ |
|
|
111
|
+
| 5 MB | WAV | 2.70 s | 1.65 s | 1.8 MB/s | 3.0 MB/s | 5.00 MB | 100.0% | ✓ |
|
|
112
|
+
| 10 MB | WAV | 4.81 s | 2.56 s | 2.1 MB/s | 3.9 MB/s | 10.00 MB | 100.0% | ✓ |
|
|
113
|
+
|
|
114
|
+
> WAV container is **2–4× faster** than PNG for decoding at large sizes, and produces slightly smaller output thanks to simpler framing.
|
|
115
|
+
|
|
116
|
+
### Reed-Solomon ECC Throughput
|
|
117
|
+
|
|
118
|
+
| Size | Encode | Decode | Enc Throughput | Dec Throughput | Overhead |
|
|
119
|
+
|---|---|---|---|---|---|
|
|
120
|
+
| 1 KB | 6 ms | 4 ms | 0.2 MB/s | 0.2 MB/s | 125.7% |
|
|
121
|
+
| 10 KB | 7 ms | 6 ms | 1.3 MB/s | 1.5 MB/s | 119.6% |
|
|
122
|
+
| 100 KB | 49 ms | 45 ms | 2.0 MB/s | 2.1 MB/s | 118.8% |
|
|
123
|
+
| 1 MB | 483 ms | 377 ms | 2.1 MB/s | 2.7 MB/s | 118.6% |
|
|
124
|
+
|
|
125
|
+
### Lossy-Resilient Encoding
|
|
126
|
+
|
|
127
|
+
#### Robust Image (QR-code-style, block size 4×4)
|
|
128
|
+
|
|
129
|
+
| Data Size | Encode Time | Output (PNG) |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| 32 B | 32 ms | 122 KB |
|
|
132
|
+
| 128 B | 39 ms | 122 KB |
|
|
133
|
+
| 512 B | 76 ms | 316 KB |
|
|
134
|
+
| 1 KB | 139 ms | 508 KB |
|
|
135
|
+
| 2 KB | 251 ms | 986 KB |
|
|
136
|
+
|
|
137
|
+
#### Robust Audio (MFSK 8-channel, medium ECC)
|
|
138
|
+
|
|
139
|
+
| Data Size | Encode | Decode | Output (WAV) | Integrity |
|
|
140
|
+
|---|---|---|---|---|
|
|
141
|
+
| 10 B | 33 ms | 44 ms | 1.35 MB | ✓ |
|
|
142
|
+
| 32 B | 19 ms | 31 ms | 1.35 MB | ✓ |
|
|
143
|
+
| 64 B | 22 ms | 24 ms | 1.35 MB | ✓ |
|
|
144
|
+
| 128 B | 21 ms | 28 ms | 1.35 MB | ✓ |
|
|
145
|
+
| 256 B | 40 ms | 45 ms | 2.59 MB | ✓ |
|
|
146
|
+
|
|
147
|
+
### Data Integrity Verification
|
|
148
|
+
|
|
149
|
+
All encode/decode roundtrips produce bit-exact output, verified by SHA-256:
|
|
150
|
+
|
|
151
|
+
| Test Case | PNG | WAV |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| Empty buffer (0 B) | ✓ | ✓ |
|
|
154
|
+
| Single byte (1 B) | ✓ | ✓ |
|
|
155
|
+
| All byte values (256 B) | ✓ | ✓ |
|
|
156
|
+
| 1 KB text | ✓ | ✓ |
|
|
157
|
+
| 100 KB random | ✓ | ✓ |
|
|
158
|
+
| 1 MB random | ✓ | ✓ |
|
|
159
|
+
| 5 MB random | ✓ | ✓ |
|
|
160
|
+
|
|
161
|
+
**14 / 14 integrity tests passed** across both containers.
|
|
162
|
+
|
|
163
|
+
### Key Observations
|
|
164
|
+
|
|
165
|
+
- **Roxify matches LZMA2 ultra-compression** on text data (18.3%) and **outperforms it on JSON** (21.4% vs 22.0%), while producing a standard PNG or WAV file instead of an archive.
|
|
166
|
+
- **WAV container decode is 2–4× faster** than PNG decode at large sizes (3.9 MB/s vs 0.8 MB/s for 10 MB).
|
|
167
|
+
- **WAV encode for 1 KB data completes in 2 ms** — well under the sub-second target.
|
|
168
|
+
- **Lossy-resilient audio** encode/decode completes in under 50 ms for data up to 256 bytes, with full integrity.
|
|
169
|
+
- **100% data integrity** across all sizes and containers — every byte is recovered exactly.
|
|
170
|
+
- The CLI overhead (~400 ms Node.js startup) is amortized on larger inputs. For programmatic use, the JS API eliminates this entirely.
|
|
171
|
+
- On incompressible (random) data, all tools converge to ~100% as expected. No compression algorithm can shrink truly random data.
|
|
42
172
|
|
|
43
|
-
|
|
44
|
-
- 📗 **[JavaScript SDK](./docs/JAVASCRIPT_SDK.md)** - Programmatic API reference with examples
|
|
45
|
-
- 📙 **[Quick Start](#quick-start)** - Get started in 2 minutes
|
|
173
|
+
### Methodology
|
|
46
174
|
|
|
47
|
-
|
|
175
|
+
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:
|
|
48
176
|
|
|
49
|
-
|
|
177
|
+
| Tool | Command / Setting |
|
|
178
|
+
|---|---|
|
|
179
|
+
| zip | `zip -r -q -9` |
|
|
180
|
+
| tar/gzip | `tar -cf - \| gzip -9` |
|
|
181
|
+
| 7z | `7z a -mx=9` (LZMA2 ultra) |
|
|
182
|
+
| Roxify | Zstd level 19, compact mode |
|
|
50
183
|
|
|
51
|
-
|
|
184
|
+
To reproduce:
|
|
52
185
|
|
|
53
186
|
```bash
|
|
54
|
-
|
|
55
|
-
npx rox decode output.png original.zip
|
|
187
|
+
node test/benchmark-detailed.cjs
|
|
56
188
|
```
|
|
57
189
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
npm install roxify
|
|
62
|
-
```
|
|
190
|
+
---
|
|
63
191
|
|
|
64
|
-
##
|
|
192
|
+
## Installation
|
|
65
193
|
|
|
66
|
-
###
|
|
194
|
+
### As a CLI tool (no installation required)
|
|
67
195
|
|
|
68
196
|
```bash
|
|
69
|
-
|
|
70
|
-
|
|
197
|
+
npx rox encode input.zip output.png
|
|
198
|
+
npx rox decode output.png original.zip
|
|
199
|
+
```
|
|
71
200
|
|
|
72
|
-
|
|
73
|
-
npx rox decode document.png document.pdf
|
|
201
|
+
### As a library
|
|
74
202
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
npx rox decode secret.png secret.zip -p mypassword
|
|
203
|
+
```bash
|
|
204
|
+
npm install roxify
|
|
78
205
|
```
|
|
79
206
|
|
|
80
|
-
###
|
|
81
|
-
|
|
82
|
-
#### `encode` - Encode file to PNG
|
|
207
|
+
### Global installation
|
|
83
208
|
|
|
84
209
|
```bash
|
|
85
|
-
|
|
210
|
+
npm install -g roxify
|
|
211
|
+
rox encode input.zip output.png
|
|
86
212
|
```
|
|
87
213
|
|
|
88
|
-
|
|
214
|
+
---
|
|
89
215
|
|
|
90
|
-
|
|
91
|
-
- `-m, --mode <mode>` - Encoding mode: `compact|chunk|pixel|screenshot` (default: `screenshot`)
|
|
92
|
-
- `-q, --quality <0-11>` - Brotli compression quality (default: `1`)
|
|
93
|
-
- `0` = fastest, largest
|
|
94
|
-
- `11` = slowest, smallest
|
|
95
|
-
- `-e, --encrypt <type>` - Encryption: `auto|aes|xor|none` (default: `aes` if passphrase)
|
|
96
|
-
- `--no-compress` - Disable compression
|
|
97
|
-
- `-o, --output <path>` - Output file path
|
|
216
|
+
## CLI Usage
|
|
98
217
|
|
|
99
|
-
|
|
218
|
+
### Encoding
|
|
100
219
|
|
|
101
220
|
```bash
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
# Fast compression for large files
|
|
106
|
-
npx rox encode large-video.mp4 output.png -q 0
|
|
107
|
-
|
|
108
|
-
# High compression for small files
|
|
109
|
-
npx rox encode config.json output.png -q 11
|
|
221
|
+
rox encode <input> [output] [options]
|
|
222
|
+
```
|
|
110
223
|
|
|
111
|
-
|
|
112
|
-
|
|
224
|
+
| Option | Description | Default |
|
|
225
|
+
|---|---|---|
|
|
226
|
+
| `-p, --passphrase <pass>` | Encrypt with AES-256-GCM | none |
|
|
227
|
+
| `-m, --mode <mode>` | Encoding mode: `screenshot`, `compact` | `screenshot` |
|
|
228
|
+
| `-q, --quality <0-11>` | Compression effort (0 = fastest, 11 = smallest) | `1` |
|
|
229
|
+
| `-e, --encrypt <type>` | Encryption method: `auto`, `aes`, `xor`, `none` | `aes` if passphrase is set |
|
|
230
|
+
| `--no-compress` | Disable compression entirely | false |
|
|
231
|
+
| `-o, --output <path>` | Explicit output file path | auto-generated |
|
|
113
232
|
|
|
114
|
-
|
|
115
|
-
npx rox encode data.bin tiny.png -m compact
|
|
233
|
+
### Decoding
|
|
116
234
|
|
|
117
|
-
|
|
118
|
-
|
|
235
|
+
```bash
|
|
236
|
+
rox decode <input> [output] [options]
|
|
119
237
|
```
|
|
120
238
|
|
|
121
|
-
|
|
239
|
+
| Option | Description | Default |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| `-p, --passphrase <pass>` | Decryption passphrase | none |
|
|
242
|
+
| `-o, --output <path>` | Output file path | auto-detected from metadata |
|
|
243
|
+
| `--dict <file>` | Zstd dictionary for improved decompression | none |
|
|
122
244
|
|
|
123
|
-
|
|
124
|
-
npx rox decode <input> [output] [options]
|
|
125
|
-
```
|
|
245
|
+
### Examples
|
|
126
246
|
|
|
127
|
-
|
|
247
|
+
```bash
|
|
248
|
+
# Encode a single file
|
|
249
|
+
rox encode document.pdf document.png
|
|
128
250
|
|
|
129
|
-
|
|
130
|
-
|
|
251
|
+
# Encode with encryption
|
|
252
|
+
rox encode secret.zip secret.png -p "strong passphrase"
|
|
131
253
|
|
|
132
|
-
|
|
254
|
+
# Decode back to original
|
|
255
|
+
rox decode secret.png secret.zip -p "strong passphrase"
|
|
133
256
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
npx rox decode encoded.png output.bin
|
|
257
|
+
# Fast compression for large files
|
|
258
|
+
rox encode video.mp4 output.png -q 0
|
|
137
259
|
|
|
138
|
-
#
|
|
139
|
-
|
|
260
|
+
# Best compression for small files
|
|
261
|
+
rox encode config.json output.png -q 11 -m compact
|
|
140
262
|
|
|
141
|
-
#
|
|
142
|
-
|
|
263
|
+
# Encode an entire directory
|
|
264
|
+
rox encode ./my-project project.png
|
|
143
265
|
```
|
|
144
266
|
|
|
267
|
+
---
|
|
268
|
+
|
|
145
269
|
## JavaScript API
|
|
146
270
|
|
|
147
|
-
### Basic
|
|
271
|
+
### Basic Encode and Decode
|
|
148
272
|
|
|
149
273
|
```typescript
|
|
150
274
|
import { encodeBinaryToPng, decodePngToBinary } from 'roxify';
|
|
151
275
|
import { readFileSync, writeFileSync } from 'fs';
|
|
152
276
|
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
});
|
|
158
|
-
writeFileSync('output.png', png);
|
|
277
|
+
// Encode
|
|
278
|
+
const input = readFileSync('document.pdf');
|
|
279
|
+
const png = await encodeBinaryToPng(input, { name: 'document.pdf' });
|
|
280
|
+
writeFileSync('document.png', png);
|
|
159
281
|
|
|
160
|
-
|
|
282
|
+
// Decode
|
|
283
|
+
const encoded = readFileSync('document.png');
|
|
161
284
|
const result = await decodePngToBinary(encoded);
|
|
162
285
|
writeFileSync(result.meta?.name || 'output.bin', result.buf);
|
|
163
286
|
```
|
|
164
287
|
|
|
165
|
-
###
|
|
288
|
+
### Encrypted Roundtrip
|
|
166
289
|
|
|
167
290
|
```typescript
|
|
168
291
|
const png = await encodeBinaryToPng(input, {
|
|
169
|
-
|
|
170
|
-
passphrase: 'my-secret-password',
|
|
292
|
+
passphrase: 'my-secret',
|
|
171
293
|
encrypt: 'aes',
|
|
172
|
-
name: '
|
|
294
|
+
name: 'confidential.pdf',
|
|
173
295
|
});
|
|
174
296
|
|
|
175
|
-
const result = await decodePngToBinary(
|
|
176
|
-
passphrase: 'my-secret
|
|
297
|
+
const result = await decodePngToBinary(png, {
|
|
298
|
+
passphrase: 'my-secret',
|
|
177
299
|
});
|
|
178
300
|
```
|
|
179
301
|
|
|
180
|
-
###
|
|
302
|
+
### Directory Packing
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
import { packPaths, unpackBuffer } from 'roxify';
|
|
306
|
+
|
|
307
|
+
// Pack files into a buffer
|
|
308
|
+
const { buf, list } = packPaths(['./src', './README.md'], process.cwd());
|
|
309
|
+
|
|
310
|
+
// Encode the packed buffer into a PNG
|
|
311
|
+
const png = await encodeBinaryToPng(buf, { name: 'project.tar' });
|
|
312
|
+
|
|
313
|
+
// Later: decode and unpack
|
|
314
|
+
const decoded = await decodePngToBinary(png);
|
|
315
|
+
const unpacked = unpackBuffer(decoded.buf);
|
|
316
|
+
for (const file of unpacked.files) {
|
|
317
|
+
console.log(file.name, file.buf.length);
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Progress Reporting
|
|
181
322
|
|
|
182
323
|
```typescript
|
|
183
324
|
const png = await encodeBinaryToPng(largeBuffer, {
|
|
184
|
-
mode: 'screenshot',
|
|
185
|
-
brQuality: 0,
|
|
186
325
|
name: 'large-file.bin',
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
mode: 'compact',
|
|
191
|
-
brQuality: 11,
|
|
192
|
-
name: 'config.json',
|
|
326
|
+
onProgress: ({ phase, loaded, total }) => {
|
|
327
|
+
console.log(`${phase}: ${loaded}/${total}`);
|
|
328
|
+
},
|
|
193
329
|
});
|
|
194
330
|
```
|
|
195
331
|
|
|
196
|
-
###
|
|
332
|
+
### EncodeOptions
|
|
197
333
|
|
|
198
|
-
|
|
334
|
+
```typescript
|
|
335
|
+
interface EncodeOptions {
|
|
336
|
+
compression?: 'zstd'; // Compression algorithm
|
|
337
|
+
compressionLevel?: number; // Zstd compression level (0-19)
|
|
338
|
+
passphrase?: string; // Encryption passphrase
|
|
339
|
+
dict?: Buffer; // Zstd dictionary for improved ratios
|
|
340
|
+
name?: string; // Original filename stored in metadata
|
|
341
|
+
mode?: 'screenshot'; // Encoding mode
|
|
342
|
+
encrypt?: 'auto' | 'aes' | 'xor' | 'none';
|
|
343
|
+
output?: 'auto' | 'png' | 'rox'; // Output format
|
|
344
|
+
includeName?: boolean; // Include filename in PNG metadata
|
|
345
|
+
includeFileList?: boolean; // Include file manifest in PNG
|
|
346
|
+
fileList?: Array<string | { name: string; size: number }>;
|
|
347
|
+
skipOptimization?: boolean; // Skip PNG optimization pass
|
|
348
|
+
lossyResilient?: boolean; // Enable lossy-resilient encoding (RS ECC)
|
|
349
|
+
eccLevel?: EccLevel; // 'low' | 'medium' | 'quartile' | 'high'
|
|
350
|
+
robustBlockSize?: number; // 2–8 pixels per data block (lossy image)
|
|
351
|
+
container?: 'image' | 'sound'; // Output container format
|
|
352
|
+
onProgress?: (info: ProgressInfo) => void;
|
|
353
|
+
showProgress?: boolean;
|
|
354
|
+
verbose?: boolean;
|
|
355
|
+
}
|
|
356
|
+
```
|
|
199
357
|
|
|
200
|
-
|
|
358
|
+
### DecodeOptions
|
|
201
359
|
|
|
202
360
|
```typescript
|
|
203
|
-
|
|
361
|
+
interface DecodeOptions {
|
|
362
|
+
passphrase?: string; // Decryption passphrase
|
|
363
|
+
outPath?: string; // Output directory for unpacked files
|
|
364
|
+
files?: string[]; // Extract only specific files from archive
|
|
365
|
+
onProgress?: (info: ProgressInfo) => void;
|
|
366
|
+
showProgress?: boolean;
|
|
367
|
+
verbose?: boolean;
|
|
368
|
+
}
|
|
204
369
|
```
|
|
205
370
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
Minimal 1x1 PNG with data in custom chunk. Fastest and smallest.
|
|
371
|
+
### DecodeResult
|
|
209
372
|
|
|
210
373
|
```typescript
|
|
211
|
-
|
|
374
|
+
interface DecodeResult {
|
|
375
|
+
buf?: Buffer; // Decoded binary payload
|
|
376
|
+
meta?: { name?: string }; // Metadata (original filename)
|
|
377
|
+
files?: PackedFile[]; // Unpacked directory entries, if applicable
|
|
378
|
+
correctedErrors?: number; // RS errors corrected (lossy-resilient mode)
|
|
379
|
+
}
|
|
212
380
|
```
|
|
213
381
|
|
|
214
|
-
|
|
382
|
+
---
|
|
215
383
|
|
|
216
|
-
|
|
384
|
+
## Encoding Modes
|
|
217
385
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
386
|
+
| Mode | Description | Use Case |
|
|
387
|
+
|---|---|---|
|
|
388
|
+
| `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 |
|
|
389
|
+
| `compact` | Minimal 1x1 PNG with data embedded in a custom ancillary chunk (`rXDT`). Produces the smallest possible output. | Programmatic use, archival, maximum compression ratio |
|
|
221
390
|
|
|
222
|
-
|
|
391
|
+
---
|
|
223
392
|
|
|
224
|
-
|
|
393
|
+
## Encryption
|
|
225
394
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
395
|
+
Roxify supports two encryption methods:
|
|
396
|
+
|
|
397
|
+
| Method | Algorithm | Strength | Use Case |
|
|
398
|
+
|---|---|---|---|
|
|
399
|
+
| `aes` | AES-256-GCM with PBKDF2 (100,000 iterations) | Cryptographically secure, authenticated | Sensitive data, confidential documents |
|
|
400
|
+
| `xor` | XOR cipher with passphrase-derived key | Obfuscation only, not cryptographically secure | Casual deterrent against inspection |
|
|
401
|
+
|
|
402
|
+
When `encrypt` is set to `auto` (the default when a passphrase is provided), AES is selected.
|
|
229
403
|
|
|
230
|
-
|
|
404
|
+
---
|
|
231
405
|
|
|
232
|
-
|
|
406
|
+
## Lossy-Resilient Mode
|
|
233
407
|
|
|
234
|
-
|
|
408
|
+
Enable `lossyResilient: true` to produce output that survives lossy compression. This uses the same error correction algorithm as QR codes (Reed-Solomon over GF(256)) combined with block-based signal encoding.
|
|
235
409
|
|
|
236
|
-
|
|
410
|
+
### How It Works
|
|
237
411
|
|
|
238
|
-
-
|
|
239
|
-
|
|
412
|
+
1. **Reed-Solomon ECC** adds configurable redundancy (10–100%) to the data.
|
|
413
|
+
2. **Interleaving** spreads data across RS blocks so burst errors don't overwhelm a single block.
|
|
414
|
+
3. **Block encoding** (image: large pixel blocks; audio: multi-frequency tones) makes the signal robust against quantization.
|
|
415
|
+
4. **Finder patterns** (image only) enable automatic alignment after re-encoding.
|
|
240
416
|
|
|
241
|
-
|
|
417
|
+
### Error Correction Levels
|
|
242
418
|
|
|
243
|
-
|
|
419
|
+
| Level | Parity Symbols | Overhead | Correctable Errors |
|
|
420
|
+
|-------|---------------:|---------:|-------------------:|
|
|
421
|
+
| `low` | 20 / block | ~10% | ~4% |
|
|
422
|
+
| `medium` | 40 / block | ~19% | ~9% |
|
|
423
|
+
| `quartile` | 64 / block | ~33% | ~15% |
|
|
424
|
+
| `high` | 128 / block | ~100% | ~25% |
|
|
425
|
+
|
|
426
|
+
### Example
|
|
244
427
|
|
|
245
428
|
```typescript
|
|
246
|
-
|
|
247
|
-
|
|
429
|
+
// Image that survives JPEG compression
|
|
430
|
+
const png = await encodeBinaryToPng(data, {
|
|
431
|
+
lossyResilient: true,
|
|
432
|
+
eccLevel: 'quartile',
|
|
433
|
+
robustBlockSize: 4, // 4×4 pixels per data bit
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Audio that survives MP3 compression
|
|
437
|
+
const wav = await encodeBinaryToPng(data, {
|
|
438
|
+
container: 'sound',
|
|
439
|
+
lossyResilient: true,
|
|
440
|
+
eccLevel: 'medium',
|
|
441
|
+
});
|
|
248
442
|
|
|
249
|
-
|
|
443
|
+
// Decode automatically detects the format
|
|
444
|
+
const result = await decodePngToBinary(png);
|
|
445
|
+
console.log('Errors corrected:', result.correctedErrors);
|
|
446
|
+
```
|
|
250
447
|
|
|
251
|
-
|
|
448
|
+
For full documentation, see [Lossy Resilience Guide](./docs/LOSSY_RESILIENCE.md).
|
|
252
449
|
|
|
253
|
-
|
|
450
|
+
---
|
|
254
451
|
|
|
255
|
-
|
|
452
|
+
## Audio Container
|
|
256
453
|
|
|
257
|
-
|
|
454
|
+
Roxify can encode data into WAV audio files using `container: 'sound'`.
|
|
258
455
|
|
|
259
|
-
|
|
456
|
+
### Standard Mode (`lossyResilient: false`)
|
|
260
457
|
|
|
261
|
-
|
|
262
|
-
|
|
458
|
+
Data bytes are stored directly as 8-bit PCM samples. This is the fastest and most compact option, but the output sounds like white noise and does not survive lossy audio compression.
|
|
459
|
+
|
|
460
|
+
### Lossy-Resilient Mode (`lossyResilient: true`)
|
|
461
|
+
|
|
462
|
+
Data is encoded using **8-channel multi-frequency shift keying (MFSK)**:
|
|
463
|
+
|
|
464
|
+
- 8 carrier frequencies (600–2700 Hz) encode 1 byte per symbol.
|
|
465
|
+
- Each carrier is modulated with raised-cosine windowing.
|
|
466
|
+
- The output sounds like a series of **musical chords** — structured and pleasant, not white noise.
|
|
467
|
+
- Reed-Solomon ECC enables recovery after MP3/AAC/OGG transcoding.
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
const wav = await encodeBinaryToPng(data, {
|
|
471
|
+
container: 'sound',
|
|
472
|
+
lossyResilient: true,
|
|
473
|
+
eccLevel: 'medium',
|
|
474
|
+
});
|
|
263
475
|
```
|
|
264
476
|
|
|
265
|
-
|
|
477
|
+
---
|
|
266
478
|
|
|
267
|
-
|
|
479
|
+
## Performance Tuning
|
|
268
480
|
|
|
269
|
-
|
|
481
|
+
### Compression Level
|
|
270
482
|
|
|
271
|
-
|
|
272
|
-
- `options?: DecodeOptions` - Decoding options
|
|
483
|
+
The `compressionLevel` option (CLI: `-q`) controls the trade-off between speed and output size:
|
|
273
484
|
|
|
274
|
-
|
|
485
|
+
| Level | Speed | Ratio | Recommendation |
|
|
486
|
+
|---|---|---|---|
|
|
487
|
+
| 0 | Fastest | Largest | Files over 100 MB, real-time workflows |
|
|
488
|
+
| 1 | Fast | Good | Default; general-purpose use |
|
|
489
|
+
| 5 | Moderate | Better | Archival of medium-sized datasets |
|
|
490
|
+
| 11 | Slowest | Smallest | Small files under 1 MB, long-term storage |
|
|
275
491
|
|
|
276
|
-
|
|
492
|
+
### Native Module
|
|
493
|
+
|
|
494
|
+
The Rust native module provides 10--50x throughput improvement over the pure JavaScript fallback. It is loaded automatically when present. To verify availability:
|
|
277
495
|
|
|
278
496
|
```typescript
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
497
|
+
import { native } from 'roxify';
|
|
498
|
+
console.log('Native module loaded:', !!native);
|
|
282
499
|
```
|
|
283
500
|
|
|
284
|
-
|
|
501
|
+
If the native module is not found for the current platform, Roxify falls back to TypeScript transparently. No code changes are needed.
|
|
502
|
+
|
|
503
|
+
### Zstd Dictionary
|
|
504
|
+
|
|
505
|
+
For datasets consisting of many similar small files (e.g., JSON API responses, log entries), a Zstd dictionary can improve compression ratios by 20--40%:
|
|
285
506
|
|
|
286
507
|
```typescript
|
|
287
|
-
|
|
288
|
-
buf: Buffer;
|
|
508
|
+
import { readFileSync } from 'fs';
|
|
289
509
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
};
|
|
293
|
-
}
|
|
510
|
+
const dict = readFileSync('my-dictionary.zdict');
|
|
511
|
+
const png = await encodeBinaryToPng(data, { dict });
|
|
294
512
|
```
|
|
295
513
|
|
|
296
|
-
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Cross-Platform Support
|
|
517
|
+
|
|
518
|
+
Roxify ships prebuilt native modules for the following targets:
|
|
519
|
+
|
|
520
|
+
| Platform | Architecture | Binary Name |
|
|
521
|
+
|---|---|---|
|
|
522
|
+
| Linux | x86_64 | `libroxify_native-x86_64-unknown-linux-gnu.node` |
|
|
523
|
+
| macOS | x86_64 | `libroxify_native-x86_64-apple-darwin.node` |
|
|
524
|
+
| macOS | ARM64 (Apple Silicon) | `libroxify_native-aarch64-apple-darwin.node` |
|
|
525
|
+
| Windows | x86_64 | `roxify_native-x86_64-pc-windows-msvc.node` |
|
|
297
526
|
|
|
298
|
-
|
|
527
|
+
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.
|
|
528
|
+
|
|
529
|
+
### Building Native Modules for Specific Targets
|
|
299
530
|
|
|
300
531
|
```bash
|
|
301
|
-
#
|
|
302
|
-
|
|
303
|
-
```
|
|
532
|
+
# Current platform
|
|
533
|
+
npm run build:native
|
|
304
534
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
535
|
+
# Specific platform
|
|
536
|
+
npm run build:native:linux
|
|
537
|
+
npm run build:native:macos-x64
|
|
538
|
+
npm run build:native:macos-arm
|
|
539
|
+
npm run build:native:windows
|
|
540
|
+
|
|
541
|
+
# All configured targets
|
|
542
|
+
npm run build:native:targets
|
|
310
543
|
```
|
|
311
544
|
|
|
312
|
-
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Building from Source
|
|
548
|
+
|
|
549
|
+
### Prerequisites
|
|
550
|
+
|
|
551
|
+
- Node.js 18 or later
|
|
552
|
+
- Rust 1.70 or later (install via [rustup](https://rustup.rs))
|
|
553
|
+
|
|
554
|
+
### Commands
|
|
313
555
|
|
|
314
556
|
```bash
|
|
315
|
-
#
|
|
316
|
-
|
|
557
|
+
# Install dependencies
|
|
558
|
+
npm install
|
|
559
|
+
|
|
560
|
+
# Build TypeScript only
|
|
561
|
+
npm run build
|
|
562
|
+
|
|
563
|
+
# Build native Rust module
|
|
564
|
+
npm run build:native
|
|
565
|
+
|
|
566
|
+
# Build everything (Rust + TypeScript + CLI binary)
|
|
567
|
+
npm run build:all
|
|
568
|
+
|
|
569
|
+
# Run the full test suite
|
|
570
|
+
npm test
|
|
317
571
|
```
|
|
318
572
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
573
|
+
### Project Structure
|
|
574
|
+
|
|
575
|
+
```
|
|
576
|
+
roxify/
|
|
577
|
+
native/ Rust source code (N-API module and CLI binary)
|
|
578
|
+
src/ TypeScript source code (library and CLI entry point)
|
|
579
|
+
dist/ Compiled JavaScript output
|
|
580
|
+
test/ Test suite and benchmarks
|
|
581
|
+
docs/ Additional documentation
|
|
582
|
+
scripts/ Build, release, and CI helper scripts
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## Architecture
|
|
588
|
+
|
|
589
|
+
Roxify is a hybrid Rust and TypeScript module. The performance-critical paths -- compression, CRC computation, pixel scanning, encryption -- are implemented in Rust and exposed through N-API bindings. The TypeScript layer handles PNG construction, CLI argument parsing, and high-level orchestration.
|
|
590
|
+
|
|
591
|
+
### Compression Pipeline
|
|
592
|
+
|
|
593
|
+
```
|
|
594
|
+
Input --> Zstd Compress (multi-threaded, Rayon) --> AES-256-GCM Encrypt (optional) --> PNG Encode --> Output
|
|
324
595
|
```
|
|
325
596
|
|
|
326
|
-
###
|
|
597
|
+
### Lossy-Resilient Pipeline
|
|
327
598
|
|
|
328
|
-
|
|
599
|
+
```
|
|
600
|
+
Input --> RS ECC Encode --> Interleave --> Block Encode (MFSK audio / QR-like image) --> WAV/PNG Output
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### Decompression Pipeline
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
Input --> PNG Parse --> AES-256-GCM Decrypt (optional) --> Zstd Decompress --> Output
|
|
607
|
+
```
|
|
329
608
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
609
|
+
### Lossy-Resilient Decode Pipeline
|
|
610
|
+
|
|
611
|
+
```
|
|
612
|
+
Input --> Detect Format --> Demodulate/Read Blocks --> De-interleave --> RS ECC Decode --> Output
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Rust Modules
|
|
616
|
+
|
|
617
|
+
| Module | Responsibility |
|
|
618
|
+
|---|---|
|
|
619
|
+
| `core.rs` | Pixel scanning, CRC32, Adler32, delta coding, Zstd compress/decompress |
|
|
620
|
+
| `encoder.rs` | PNG payload encoding with marker pixels and metadata chunks |
|
|
621
|
+
| `packer.rs` | Directory tree serialization and streaming deserialization |
|
|
622
|
+
| `crypto.rs` | AES-256-GCM encryption and PBKDF2 key derivation |
|
|
623
|
+
| `archive.rs` | Tar-based archiving with optional Zstd compression |
|
|
624
|
+
| `reconstitution.rs` | Screenshot detection and automatic crop to recover encoded data |
|
|
625
|
+
| `audio.rs` | WAV container encoding and decoding (PCM byte packing) |
|
|
626
|
+
| `bwt.rs` | Parallel Burrows-Wheeler Transform |
|
|
627
|
+
| `rans.rs` | rANS (Asymmetric Numeral Systems) entropy coder |
|
|
628
|
+
| `hybrid.rs` | Block-based orchestration of BWT, context mixing, and rANS |
|
|
629
|
+
| `pool.rs` | Buffer pooling and zero-copy memory management |
|
|
630
|
+
| `image_utils.rs` | Image resizing, pixel format conversion, metadata extraction |
|
|
631
|
+
| `png_utils.rs` | Low-level PNG chunk read/write operations |
|
|
632
|
+
| `progress.rs` | Progress tracking for long-running compression/decompression |
|
|
633
|
+
|
|
634
|
+
### TypeScript Modules
|
|
635
|
+
|
|
636
|
+
| Module | Responsibility |
|
|
637
|
+
|---|---|
|
|
638
|
+
| `ecc.ts` | Reed-Solomon GF(256) codec, block ECC, interleaving |
|
|
639
|
+
| `robust-audio.ts` | MFSK audio modulation/demodulation, Goertzel detection, sync preamble |
|
|
640
|
+
| `robust-image.ts` | QR-code-like block encoding, finder patterns, majority voting |
|
|
641
|
+
| `encoder.ts` | High-level encoding orchestration (standard + lossy-resilient) |
|
|
642
|
+
| `decoder.ts` | High-level decoding with automatic format detection |
|
|
643
|
+
| `audio.ts` | Standard WAV container (8-bit PCM) |
|
|
644
|
+
| `helpers.ts` | Delta coding, XOR cipher, palette generation |
|
|
645
|
+
| `zstd.ts` | Parallel Zstd compression via native module |
|
|
646
|
+
|
|
647
|
+
---
|
|
334
648
|
|
|
335
649
|
## Error Handling
|
|
336
650
|
|
|
651
|
+
Roxify throws descriptive errors for common failure modes:
|
|
652
|
+
|
|
337
653
|
```typescript
|
|
654
|
+
import { decodePngToBinary } from 'roxify';
|
|
655
|
+
|
|
338
656
|
try {
|
|
339
|
-
const result = await decodePngToBinary(
|
|
657
|
+
const result = await decodePngToBinary(pngBuffer, {
|
|
340
658
|
passphrase: 'wrong-password',
|
|
341
659
|
});
|
|
342
660
|
} catch (err) {
|
|
343
661
|
if (err.message.includes('Incorrect passphrase')) {
|
|
344
|
-
|
|
345
|
-
} else if (err.message.includes('
|
|
346
|
-
|
|
347
|
-
} else {
|
|
348
|
-
|
|
662
|
+
// Wrong decryption key
|
|
663
|
+
} else if (err.message.includes('not a valid PNG')) {
|
|
664
|
+
// Input is not a valid roxified PNG
|
|
665
|
+
} else if (err.message.includes('corrupted')) {
|
|
666
|
+
// Data integrity check failed
|
|
349
667
|
}
|
|
350
668
|
}
|
|
351
669
|
```
|
|
352
670
|
|
|
353
|
-
|
|
671
|
+
| Error | Cause |
|
|
672
|
+
|---|---|
|
|
673
|
+
| `Incorrect passphrase` | Wrong password provided for decryption |
|
|
674
|
+
| `not a valid PNG` | Input buffer is not a PNG or lacks Roxify markers |
|
|
675
|
+
| `Passphrase required` | File is encrypted but no passphrase was supplied |
|
|
676
|
+
| `Image too large to decode` | PNG dimensions exceed the in-process memory limit |
|
|
354
677
|
|
|
355
|
-
|
|
356
|
-
- **XOR cipher**: Simple obfuscation (not cryptographically secure)
|
|
357
|
-
- **No encryption**: Data is compressed but not encrypted
|
|
678
|
+
---
|
|
358
679
|
|
|
359
|
-
|
|
680
|
+
## Security Considerations
|
|
360
681
|
|
|
361
|
-
|
|
682
|
+
- **AES-256-GCM** provides authenticated encryption. Tampered ciphertext is detected and rejected.
|
|
683
|
+
- **PBKDF2** with 100,000 iterations is used for key derivation, making brute-force attacks computationally expensive.
|
|
684
|
+
- **XOR encryption** is not cryptographically secure. Use it only for casual obfuscation.
|
|
685
|
+
- Passphrases are never stored in the output file. There is no recovery mechanism for a lost passphrase.
|
|
686
|
+
- The PNG output does not visually reveal whether data is encrypted. An observer cannot distinguish an encrypted Roxify PNG from an unencrypted one by inspection.
|
|
362
687
|
|
|
363
|
-
|
|
688
|
+
---
|
|
364
689
|
|
|
365
690
|
## Contributing
|
|
366
691
|
|
|
367
|
-
Contributions welcome
|
|
692
|
+
Contributions are welcome. Please open an issue to discuss proposed changes before submitting a pull request.
|
|
368
693
|
|
|
369
|
-
|
|
694
|
+
1. Fork the repository
|
|
695
|
+
2. Create a feature branch (`git checkout -b feature/my-change`)
|
|
696
|
+
3. Run the test suite (`npm test`)
|
|
697
|
+
4. Submit a pull request
|
|
370
698
|
|
|
371
|
-
|
|
372
|
-
- [npm Package](https://www.npmjs.com/package/roxify)
|
|
373
|
-
- [Report Issues](https://github.com/RoxasYTB/roxify/issues)
|
|
699
|
+
---
|
|
374
700
|
|
|
375
|
-
##
|
|
701
|
+
## License
|
|
702
|
+
|
|
703
|
+
MIT. See [LICENSE](LICENSE) for details.
|
|
376
704
|
|
|
377
|
-
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
## Links
|
|
708
|
+
|
|
709
|
+
- [npm Package](https://www.npmjs.com/package/roxify)
|
|
710
|
+
- [GitHub Repository](https://github.com/RoxasYTB/roxify)
|
|
711
|
+
- [Issue Tracker](https://github.com/RoxasYTB/roxify/issues)
|
|
712
|
+
- [CLI Documentation](./docs/CLI.md)
|
|
713
|
+
- [JavaScript SDK Reference](./docs/JAVASCRIPT_SDK.md)
|
|
714
|
+
- [Cross-Platform Build Guide](./docs/CROSS_PLATFORM.md)
|
|
715
|
+
- [Lossy Resilience Guide](./docs/LOSSY_RESILIENCE.md)
|