roxify 1.2.7 → 1.2.8

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.
@@ -1,131 +1,153 @@
1
- import { compress as zstdCompress, decompress as zstdDecompress, } from '@mongodb-js/zstd';
2
- import { cpus } from 'os';
3
- export async function compressStream(stream, level = 19, onProgress) {
4
- const compressedChunks = [];
5
- let chunkCount = 0;
6
- for await (const chunk of stream) {
7
- const compressed = await zstdCompress(chunk, level);
8
- compressedChunks.push(Buffer.from(compressed));
9
- chunkCount++;
10
- if (onProgress)
11
- onProgress(chunkCount, 0);
12
- }
13
- const chunkSizes = Buffer.alloc(compressedChunks.length * 4);
14
- let totalLength = 8 + chunkSizes.length;
15
- for (let i = 0; i < compressedChunks.length; i++) {
16
- chunkSizes.writeUInt32BE(compressedChunks[i].length, i * 4);
17
- totalLength += compressedChunks[i].length;
18
- }
19
- const header = Buffer.alloc(8);
20
- header.writeUInt32BE(0x5a535444, 0);
21
- header.writeUInt32BE(compressedChunks.length, 4);
22
- return {
23
- chunks: [header, chunkSizes, ...compressedChunks],
24
- totalLength,
25
- };
26
- }
27
- export async function parallelZstdCompress(payload, level = 19, onProgress) {
28
- const chunkSize = 8 * 1024 * 1024;
29
- const chunks = [];
30
- if (Array.isArray(payload)) {
31
- for (const p of payload) {
32
- if (p.length <= chunkSize) {
33
- chunks.push(p);
34
- }
35
- else {
36
- for (let i = 0; i < p.length; i += chunkSize) {
37
- chunks.push(p.subarray(i, Math.min(i + chunkSize, p.length)));
38
- }
39
- }
40
- }
41
- }
42
- else {
43
- if (payload.length <= chunkSize) {
44
- if (onProgress)
45
- onProgress(0, 1);
46
- const result = await zstdCompress(payload, level);
47
- if (onProgress)
48
- onProgress(1, 1);
49
- return [Buffer.from(result)];
50
- }
51
- for (let i = 0; i < payload.length; i += chunkSize) {
52
- chunks.push(payload.subarray(i, Math.min(i + chunkSize, payload.length)));
53
- }
54
- }
55
- const totalChunks = chunks.length;
56
- let completedChunks = 0;
57
- const concurrency = Math.max(1, Math.min(4, cpus().length));
58
- const compressedChunks = new Array(totalChunks);
59
- let idx = 0;
60
- const worker = async () => {
61
- while (true) {
62
- const cur = idx++;
63
- if (cur >= totalChunks)
64
- return;
65
- const chunk = chunks[cur];
66
- const compressed = await zstdCompress(chunk, level);
67
- compressedChunks[cur] = Buffer.from(compressed);
68
- completedChunks++;
69
- if (onProgress)
70
- onProgress(completedChunks, totalChunks);
71
- }
72
- };
73
- await Promise.all(new Array(concurrency).fill(0).map(() => worker()));
74
- const chunkSizes = Buffer.alloc(compressedChunks.length * 4);
75
- for (let i = 0; i < compressedChunks.length; i++) {
76
- chunkSizes.writeUInt32BE(compressedChunks[i].length, i * 4);
77
- }
78
- const header = Buffer.alloc(8);
79
- header.writeUInt32BE(0x5a535444, 0);
80
- header.writeUInt32BE(compressedChunks.length, 4);
81
- return [header, chunkSizes, ...compressedChunks];
82
- }
83
- export async function parallelZstdDecompress(payload, onProgress) {
84
- if (payload.length < 8) {
85
- onProgress?.({ phase: 'decompress_start', total: 1 });
86
- const d = Buffer.from(await zstdDecompress(payload));
87
- onProgress?.({ phase: 'decompress_progress', loaded: 1, total: 1 });
88
- onProgress?.({ phase: 'decompress_done', loaded: 1, total: 1 });
89
- return d;
90
- }
91
- const magic = payload.readUInt32BE(0);
92
- if (magic !== 0x5a535444) {
93
- if (process.env.ROX_DEBUG)
94
- console.log('tryZstdDecompress: invalid magic');
95
- onProgress?.({ phase: 'decompress_start', total: 1 });
96
- const d = Buffer.from(await zstdDecompress(payload));
97
- onProgress?.({ phase: 'decompress_progress', loaded: 1, total: 1 });
98
- onProgress?.({ phase: 'decompress_done', loaded: 1, total: 1 });
99
- return d;
100
- }
101
- const numChunks = payload.readUInt32BE(4);
102
- const chunkSizes = [];
103
- let offset = 8;
104
- for (let i = 0; i < numChunks; i++) {
105
- chunkSizes.push(payload.readUInt32BE(offset));
106
- offset += 4;
107
- }
108
- onProgress?.({ phase: 'decompress_start', total: numChunks });
109
- const decompressedChunks = [];
110
- for (let i = 0; i < numChunks; i++) {
111
- const size = chunkSizes[i];
112
- const chunk = payload.slice(offset, offset + size);
113
- offset += size;
114
- const dec = Buffer.from(await zstdDecompress(chunk));
115
- decompressedChunks.push(dec);
116
- onProgress?.({
117
- phase: 'decompress_progress',
118
- loaded: i + 1,
119
- total: numChunks,
120
- });
121
- }
122
- onProgress?.({
123
- phase: 'decompress_done',
124
- loaded: numChunks,
125
- total: numChunks,
126
- });
127
- return Buffer.concat(decompressedChunks);
128
- }
129
- export async function tryZstdDecompress(payload, onProgress) {
130
- return await parallelZstdDecompress(payload, onProgress);
131
- }
1
+ import { compress as zstdCompress, decompress as zstdDecompress, } from '@mongodb-js/zstd';
2
+ import { cpus } from 'os';
3
+ let nativeZstdCompress = null;
4
+ let nativeZstdDecompress = null;
5
+ try {
6
+ const native = require('../../libroxify_native.node');
7
+ if (native?.nativeZstdCompress) {
8
+ nativeZstdCompress = native.nativeZstdCompress;
9
+ }
10
+ if (native?.nativeZstdDecompress) {
11
+ nativeZstdDecompress = native.nativeZstdDecompress;
12
+ }
13
+ }
14
+ catch (e) { }
15
+ export async function compressStream(stream, level = 19, onProgress) {
16
+ const compressedChunks = [];
17
+ let chunkCount = 0;
18
+ for await (const chunk of stream) {
19
+ const compressed = await zstdCompress(chunk, level);
20
+ compressedChunks.push(Buffer.from(compressed));
21
+ chunkCount++;
22
+ if (onProgress)
23
+ onProgress(chunkCount, 0);
24
+ }
25
+ const chunkSizes = Buffer.alloc(compressedChunks.length * 4);
26
+ let totalLength = 8 + chunkSizes.length;
27
+ for (let i = 0; i < compressedChunks.length; i++) {
28
+ chunkSizes.writeUInt32BE(compressedChunks[i].length, i * 4);
29
+ totalLength += compressedChunks[i].length;
30
+ }
31
+ const header = Buffer.alloc(8);
32
+ header.writeUInt32BE(0x5a535444, 0);
33
+ header.writeUInt32BE(compressedChunks.length, 4);
34
+ return {
35
+ chunks: [header, chunkSizes, ...compressedChunks],
36
+ totalLength,
37
+ };
38
+ }
39
+ export async function parallelZstdCompress(payload, level = 19, onProgress) {
40
+ const chunkSize = 8 * 1024 * 1024;
41
+ const chunks = [];
42
+ if (Array.isArray(payload)) {
43
+ for (const p of payload) {
44
+ if (p.length <= chunkSize) {
45
+ chunks.push(p);
46
+ }
47
+ else {
48
+ for (let i = 0; i < p.length; i += chunkSize) {
49
+ chunks.push(p.subarray(i, Math.min(i + chunkSize, p.length)));
50
+ }
51
+ }
52
+ }
53
+ }
54
+ else {
55
+ if (payload.length <= chunkSize) {
56
+ if (onProgress)
57
+ onProgress(0, 1);
58
+ const result = nativeZstdCompress
59
+ ? Buffer.from(nativeZstdCompress(payload, level))
60
+ : Buffer.from(await zstdCompress(payload, level));
61
+ if (onProgress)
62
+ onProgress(1, 1);
63
+ return [result];
64
+ }
65
+ for (let i = 0; i < payload.length; i += chunkSize) {
66
+ chunks.push(payload.subarray(i, Math.min(i + chunkSize, payload.length)));
67
+ }
68
+ }
69
+ const totalChunks = chunks.length;
70
+ let completedChunks = 0;
71
+ const concurrency = Math.max(1, Math.min(4, cpus().length));
72
+ const compressedChunks = new Array(totalChunks);
73
+ let idx = 0;
74
+ const worker = async () => {
75
+ while (true) {
76
+ const cur = idx++;
77
+ if (cur >= totalChunks)
78
+ return;
79
+ const chunk = chunks[cur];
80
+ const compressed = nativeZstdCompress
81
+ ? Buffer.from(nativeZstdCompress(chunk, level))
82
+ : Buffer.from(await zstdCompress(chunk, level));
83
+ compressedChunks[cur] = compressed;
84
+ completedChunks++;
85
+ if (onProgress)
86
+ onProgress(completedChunks, totalChunks);
87
+ }
88
+ };
89
+ await Promise.all(new Array(concurrency).fill(0).map(() => worker()));
90
+ const chunkSizes = Buffer.alloc(compressedChunks.length * 4);
91
+ for (let i = 0; i < compressedChunks.length; i++) {
92
+ chunkSizes.writeUInt32BE(compressedChunks[i].length, i * 4);
93
+ }
94
+ const header = Buffer.alloc(8);
95
+ header.writeUInt32BE(0x5a535444, 0);
96
+ header.writeUInt32BE(compressedChunks.length, 4);
97
+ return [header, chunkSizes, ...compressedChunks];
98
+ }
99
+ export async function parallelZstdDecompress(payload, onProgress) {
100
+ if (payload.length < 8) {
101
+ onProgress?.({ phase: 'decompress_start', total: 1 });
102
+ const d = nativeZstdDecompress
103
+ ? Buffer.from(nativeZstdDecompress(payload))
104
+ : Buffer.from(await zstdDecompress(payload));
105
+ onProgress?.({ phase: 'decompress_progress', loaded: 1, total: 1 });
106
+ onProgress?.({ phase: 'decompress_done', loaded: 1, total: 1 });
107
+ return d;
108
+ }
109
+ const magic = payload.readUInt32BE(0);
110
+ if (magic !== 0x5a535444) {
111
+ if (process.env.ROX_DEBUG)
112
+ console.log('tryZstdDecompress: invalid magic');
113
+ onProgress?.({ phase: 'decompress_start', total: 1 });
114
+ const d = nativeZstdDecompress
115
+ ? Buffer.from(nativeZstdDecompress(payload))
116
+ : Buffer.from(await zstdDecompress(payload));
117
+ onProgress?.({ phase: 'decompress_progress', loaded: 1, total: 1 });
118
+ onProgress?.({ phase: 'decompress_done', loaded: 1, total: 1 });
119
+ return d;
120
+ }
121
+ const numChunks = payload.readUInt32BE(4);
122
+ const chunkSizes = [];
123
+ let offset = 8;
124
+ for (let i = 0; i < numChunks; i++) {
125
+ chunkSizes.push(payload.readUInt32BE(offset));
126
+ offset += 4;
127
+ }
128
+ onProgress?.({ phase: 'decompress_start', total: numChunks });
129
+ const decompressedChunks = [];
130
+ for (let i = 0; i < numChunks; i++) {
131
+ const size = chunkSizes[i];
132
+ const chunk = payload.slice(offset, offset + size);
133
+ offset += size;
134
+ const dec = nativeZstdDecompress
135
+ ? Buffer.from(nativeZstdDecompress(chunk))
136
+ : Buffer.from(await zstdDecompress(chunk));
137
+ decompressedChunks.push(dec);
138
+ onProgress?.({
139
+ phase: 'decompress_progress',
140
+ loaded: i + 1,
141
+ total: numChunks,
142
+ });
143
+ }
144
+ onProgress?.({
145
+ phase: 'decompress_done',
146
+ loaded: numChunks,
147
+ total: numChunks,
148
+ });
149
+ return Buffer.concat(decompressedChunks);
150
+ }
151
+ export async function tryZstdDecompress(payload, onProgress) {
152
+ return await parallelZstdDecompress(payload, onProgress);
153
+ }
Binary file
package/package.json CHANGED
@@ -1,65 +1,47 @@
1
- {
2
- "name": "roxify",
3
- "version": "1.2.7",
4
- "description": "Encode binary data into PNG images with Zstd compression and decode them back. Supports CLI and programmatic API (Node.js ESM).",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "bin": {
9
- "rox": "dist/cli.js",
10
- "roxify": "dist/cli.js"
11
- },
12
- "files": [
13
- "dist"
14
- ],
15
- "scripts": {
16
- "build": "tsc",
17
- "check-publish": "node ../scripts/check-publish.js roxify",
18
- "cli": "node dist/cli.js",
19
- "test": "npm run build && node test/pack.test.js && node test/screenshot.test.js && node test/list.test.js && node test/minpng.test.js && node test/optimize.test.js"
20
- },
21
- "keywords": [
22
- "steganography",
23
- "png",
24
- "zstd",
25
- "compression",
26
- "encryption",
27
- "encode",
28
- "decode",
29
- "cli",
30
- "nodejs",
31
- "esm",
32
- "data-embedding",
33
- "file-archive",
34
- "lossless",
35
- "aes-gcm",
36
- "binary-data"
37
- ],
38
- "author": "RoxCompressor",
39
- "license": "UNLICENSED",
40
- "publishConfig": {
41
- "access": "public"
42
- },
43
- "engines": {
44
- "node": ">=18"
45
- },
46
- "dependencies": {
47
- "@mongodb-js/zstd": "^2.0.1",
48
- "fflate": "^0.7.4",
49
- "lzma-purejs": "^0.9.3",
50
- "png-chunks-encode": "^1.0.0",
51
- "png-chunks-extract": "^1.0.0",
52
- "sharp": "^0.34.5",
53
- "cli-progress": "^3.9.1"
54
- },
55
- "optionalDependencies": {
56
- "zopflipng-bin": "^1.0.1"
57
- },
58
- "overrides": {
59
- "graceful-fs": "^4.2.10"
60
- },
61
- "devDependencies": {
62
- "typescript": "^4.9.5",
63
- "@types/cli-progress": "^3.9.0"
64
- }
65
- }
1
+ {
2
+ "name": "roxify",
3
+ "version": "1.2.8",
4
+ "description": "Encode binary data into PNG images and decode them back. CLI and programmatic API with native Rust acceleration.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "rox": "dist/cli.js",
10
+ "roxify": "dist/cli.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "libroxify_native.node",
15
+ "README.md",
16
+ "LICENSE",
17
+ "CHANGELOG.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "build:native": "cargo build --release --lib && cp target/release/libroxify_native.so libroxify_native.node",
22
+ "build:all": "npm run build:native && npm run build",
23
+ "prepublishOnly": "npm run build:all",
24
+ "test": "node test/roundtrip.js && node test/pixel-fallback-preview.js && node test/size-fallback-choice.js && node test/screenshot-roundtrip.js && node test/screenshot-fallback.js",
25
+ "cli": "node dist/cli.js"
26
+ },
27
+ "keywords": [
28
+ "steganography",
29
+ "png",
30
+ "brotli",
31
+ "rox"
32
+ ],
33
+ "author": "",
34
+ "license": "MIT",
35
+ "dependencies": {
36
+ "@mongodb-js/zstd": "^7.0.0",
37
+ "cli-progress": "^3.12.0",
38
+ "png-chunks-encode": "^1.0.0",
39
+ "png-chunks-extract": "^1.0.0",
40
+ "sharp": "^0.34.5"
41
+ },
42
+ "devDependencies": {
43
+ "@types/cli-progress": "^3.11.6",
44
+ "@types/node": "^25.0.3",
45
+ "typescript": "^4.9.5"
46
+ }
47
+ }