roxify 1.2.4 → 1.2.5
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/dist/cli.js +44 -48
- package/dist/index.d.ts +11 -132
- package/dist/index.js +11 -2639
- package/dist/minpng.js +31 -24
- package/dist/pack.d.ts +11 -10
- package/dist/pack.js +104 -62
- package/dist/utils/constants.d.ts +38 -0
- package/dist/utils/constants.js +22 -0
- package/dist/utils/crc.d.ts +4 -0
- package/dist/utils/crc.js +29 -0
- package/dist/utils/decoder.d.ts +4 -0
- package/dist/utils/decoder.js +626 -0
- package/dist/utils/encoder.d.ts +4 -0
- package/dist/utils/encoder.js +305 -0
- package/dist/utils/errors.d.ts +9 -0
- package/dist/utils/errors.js +18 -0
- package/dist/utils/helpers.d.ts +11 -0
- package/dist/utils/helpers.js +76 -0
- package/dist/utils/inspection.d.ts +14 -0
- package/dist/utils/inspection.js +388 -0
- package/dist/utils/optimization.d.ts +3 -0
- package/dist/utils/optimization.js +636 -0
- package/dist/utils/reconstitution.d.ts +3 -0
- package/dist/utils/reconstitution.js +266 -0
- package/dist/utils/types.d.ts +41 -0
- package/dist/utils/types.js +1 -0
- package/dist/utils/zstd.d.ts +17 -0
- package/dist/utils/zstd.js +118 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import cliProgress from 'cli-progress';
|
|
|
3
3
|
import { mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
4
4
|
import { basename, dirname, join, resolve } from 'path';
|
|
5
5
|
import { DataFormatError, decodePngToBinary, encodeBinaryToPng, hasPassphraseInPng, IncorrectPassphraseError, listFilesInPng, PassphraseRequiredError, } from './index.js';
|
|
6
|
-
import {
|
|
6
|
+
import { packPathsGenerator, unpackBuffer } from './pack.js';
|
|
7
7
|
const VERSION = '1.2.4';
|
|
8
8
|
function showHelp() {
|
|
9
9
|
console.log(`
|
|
@@ -20,8 +20,7 @@ Commands:
|
|
|
20
20
|
|
|
21
21
|
Options:
|
|
22
22
|
-p, --passphrase <pass> Use passphrase (AES-256-GCM)
|
|
23
|
-
-m, --mode <mode> Mode:
|
|
24
|
-
-q, --quality <0-11> Brotli quality (default: 11)
|
|
23
|
+
-m, --mode <mode> Mode: screenshot (default)
|
|
25
24
|
-e, --encrypt <type> auto|aes|xor|none
|
|
26
25
|
--no-compress Disable compression
|
|
27
26
|
-o, --output <path> Output file path
|
|
@@ -79,11 +78,6 @@ function parseArgs(args) {
|
|
|
79
78
|
i += 2;
|
|
80
79
|
break;
|
|
81
80
|
case 'm':
|
|
82
|
-
parsed.mode = value;
|
|
83
|
-
i += 2;
|
|
84
|
-
break;
|
|
85
|
-
case 'q':
|
|
86
|
-
parsed.quality = parseInt(value, 10);
|
|
87
81
|
i += 2;
|
|
88
82
|
break;
|
|
89
83
|
case 'e':
|
|
@@ -144,8 +138,6 @@ async function encodeCommand(args) {
|
|
|
144
138
|
const resolvedOutput = parsed.output || outputPath || outputName;
|
|
145
139
|
let options = {};
|
|
146
140
|
try {
|
|
147
|
-
let inputBuffer;
|
|
148
|
-
let displayName;
|
|
149
141
|
const encodeBar = new cliProgress.SingleBar({
|
|
150
142
|
format: ' {bar} {percentage}% | {step} | {elapsed}s',
|
|
151
143
|
}, cliProgress.Presets.shades_classic);
|
|
@@ -176,69 +168,63 @@ async function encodeCommand(args) {
|
|
|
176
168
|
elapsed: String(Math.floor(elapsed / 1000)),
|
|
177
169
|
});
|
|
178
170
|
}, TICK_MS);
|
|
171
|
+
const mode = 'screenshot';
|
|
172
|
+
Object.assign(options, {
|
|
173
|
+
mode,
|
|
174
|
+
name: parsed.outputName || 'archive',
|
|
175
|
+
});
|
|
176
|
+
if (parsed.verbose)
|
|
177
|
+
options.verbose = true;
|
|
178
|
+
if (parsed.noCompress)
|
|
179
|
+
options.compression = 'none';
|
|
180
|
+
if (parsed.passphrase) {
|
|
181
|
+
options.passphrase = parsed.passphrase;
|
|
182
|
+
options.encrypt = parsed.encrypt || 'aes';
|
|
183
|
+
}
|
|
184
|
+
console.log(`Encoding to ${resolvedOutput} (Mode: ${mode})\n`);
|
|
185
|
+
let inputData;
|
|
186
|
+
let inputSizeVal = 0;
|
|
187
|
+
let displayName;
|
|
179
188
|
let totalBytes = 0;
|
|
180
|
-
let lastShownFile;
|
|
181
189
|
const onProgress = (readBytes, total, currentFile) => {
|
|
182
190
|
if (totalBytes === 0)
|
|
183
191
|
totalBytes = total;
|
|
184
192
|
const packPct = Math.floor((readBytes / totalBytes) * 25);
|
|
185
193
|
targetPct = Math.max(targetPct, packPct);
|
|
186
|
-
if (currentFile && currentFile !== lastShownFile) {
|
|
187
|
-
lastShownFile = currentFile;
|
|
188
|
-
}
|
|
189
194
|
currentEncodeStep = currentFile
|
|
190
195
|
? `Reading files: ${currentFile}`
|
|
191
196
|
: 'Reading files';
|
|
192
197
|
};
|
|
193
198
|
if (inputPaths.length > 1) {
|
|
194
199
|
currentEncodeStep = 'Reading files';
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
console.log(`Packed ${packResult.list.length} files -> ${(inputBuffer.length /
|
|
199
|
-
1024 /
|
|
200
|
-
1024).toFixed(2)} MB`);
|
|
200
|
+
const { index, stream, totalSize } = await packPathsGenerator(inputPaths, undefined, onProgress);
|
|
201
|
+
inputData = stream;
|
|
202
|
+
inputSizeVal = totalSize;
|
|
201
203
|
displayName = parsed.outputName || 'archive';
|
|
202
204
|
options.includeFileList = true;
|
|
203
|
-
options.fileList =
|
|
205
|
+
options.fileList = index.map((e) => e.path);
|
|
204
206
|
}
|
|
205
207
|
else {
|
|
206
208
|
const resolvedInput = resolvedInputs[0];
|
|
207
209
|
const st = statSync(resolvedInput);
|
|
208
210
|
if (st.isDirectory()) {
|
|
209
|
-
console.log(`Packing directory...`);
|
|
210
211
|
currentEncodeStep = 'Reading files';
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
console.log(`Packed ${packResult.list.length} files -> ${(inputBuffer.length /
|
|
215
|
-
1024 /
|
|
216
|
-
1024).toFixed(2)} MB`);
|
|
212
|
+
const { index, stream, totalSize } = await packPathsGenerator([resolvedInput], dirname(resolvedInput), onProgress);
|
|
213
|
+
inputData = stream;
|
|
214
|
+
inputSizeVal = totalSize;
|
|
217
215
|
displayName = parsed.outputName || basename(resolvedInput);
|
|
218
216
|
options.includeFileList = true;
|
|
219
|
-
options.fileList =
|
|
217
|
+
options.fileList = index.map((e) => e.path);
|
|
220
218
|
}
|
|
221
219
|
else {
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
inputData = readFileSync(resolvedInput);
|
|
221
|
+
inputSizeVal = inputData.length;
|
|
224
222
|
displayName = basename(resolvedInput);
|
|
225
223
|
options.includeFileList = true;
|
|
226
224
|
options.fileList = [basename(resolvedInput)];
|
|
227
225
|
}
|
|
228
226
|
}
|
|
229
|
-
|
|
230
|
-
mode: parsed.mode || 'screenshot',
|
|
231
|
-
name: displayName,
|
|
232
|
-
brQuality: parsed.quality !== undefined ? parsed.quality : 11,
|
|
233
|
-
});
|
|
234
|
-
if (parsed.noCompress) {
|
|
235
|
-
options.compression = 'none';
|
|
236
|
-
}
|
|
237
|
-
if (parsed.passphrase) {
|
|
238
|
-
options.passphrase = parsed.passphrase;
|
|
239
|
-
options.encrypt = parsed.encrypt || 'aes';
|
|
240
|
-
}
|
|
241
|
-
console.log(`Encoding ${displayName} -> ${resolvedOutput}\n`);
|
|
227
|
+
options.name = displayName;
|
|
242
228
|
options.onProgress = (info) => {
|
|
243
229
|
let stepLabel = 'Processing';
|
|
244
230
|
let pct = 0;
|
|
@@ -291,6 +277,17 @@ async function encodeCommand(args) {
|
|
|
291
277
|
targetPct = Math.max(targetPct, pct);
|
|
292
278
|
currentEncodeStep = stepLabel;
|
|
293
279
|
};
|
|
280
|
+
let inputBuffer;
|
|
281
|
+
if (typeof inputData[Symbol.asyncIterator] === 'function') {
|
|
282
|
+
const chunks = [];
|
|
283
|
+
for await (const chunk of inputData) {
|
|
284
|
+
chunks.push(chunk);
|
|
285
|
+
}
|
|
286
|
+
inputBuffer = Buffer.concat(chunks);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
inputBuffer = inputData;
|
|
290
|
+
}
|
|
294
291
|
const output = await encodeBinaryToPng(inputBuffer, options);
|
|
295
292
|
const encodeTime = Date.now() - startEncode;
|
|
296
293
|
clearInterval(encodeHeartbeat);
|
|
@@ -303,8 +300,8 @@ async function encodeCommand(args) {
|
|
|
303
300
|
}
|
|
304
301
|
writeFileSync(resolvedOutput, output);
|
|
305
302
|
const outputSize = (output.length / 1024 / 1024).toFixed(2);
|
|
306
|
-
const inputSize = (
|
|
307
|
-
const ratio = ((output.length /
|
|
303
|
+
const inputSize = (inputSizeVal / 1024 / 1024).toFixed(2);
|
|
304
|
+
const ratio = ((output.length / inputSizeVal) * 100).toFixed(1);
|
|
308
305
|
console.log(`\nSuccess!`);
|
|
309
306
|
console.log(` Input: ${inputSize} MB`);
|
|
310
307
|
console.log(` Output: ${outputSize} MB (${ratio}% of original)`);
|
|
@@ -483,8 +480,7 @@ async function decodeCommand(args) {
|
|
|
483
480
|
(err.message.includes('decompression failed') ||
|
|
484
481
|
err.message.includes('missing ROX1') ||
|
|
485
482
|
err.message.includes('Pixel payload truncated') ||
|
|
486
|
-
err.message.includes('Marker START not found')
|
|
487
|
-
err.message.includes('Brotli decompression failed')))) {
|
|
483
|
+
err.message.includes('Marker START not found')))) {
|
|
488
484
|
console.log(' ');
|
|
489
485
|
console.error('Data corrupted or unsupported format. Use --verbose for details.');
|
|
490
486
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,134 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Options for encoding binary data into PNG format.
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
export interface EncodeOptions {
|
|
18
|
-
compression?: 'zstd';
|
|
19
|
-
passphrase?: string;
|
|
20
|
-
name?: string;
|
|
21
|
-
mode?: 'compact' | 'pixel' | 'screenshot';
|
|
22
|
-
encrypt?: 'auto' | 'aes' | 'xor' | 'none';
|
|
23
|
-
_skipAuto?: boolean;
|
|
24
|
-
output?: 'auto' | 'png' | 'rox';
|
|
25
|
-
includeName?: boolean;
|
|
26
|
-
includeFileList?: boolean;
|
|
27
|
-
fileList?: string[];
|
|
28
|
-
brQuality?: number;
|
|
29
|
-
onProgress?: (info: {
|
|
30
|
-
phase: string;
|
|
31
|
-
loaded?: number;
|
|
32
|
-
total?: number;
|
|
33
|
-
}) => void;
|
|
34
|
-
showProgress?: boolean;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Result of decoding a PNG back to binary data.
|
|
38
|
-
* @public
|
|
39
|
-
*/
|
|
40
|
-
export interface DecodeResult {
|
|
41
|
-
buf?: Buffer;
|
|
42
|
-
meta?: {
|
|
43
|
-
name?: string;
|
|
44
|
-
};
|
|
45
|
-
files?: PackedFile[];
|
|
46
|
-
}
|
|
47
|
-
export declare function optimizePngBuffer(pngBuf: Buffer, fast?: boolean): Promise<Buffer>;
|
|
48
|
-
/**
|
|
49
|
-
* Path to write decoded output directly to disk (streamed) to avoid high memory usage.
|
|
50
|
-
*/
|
|
51
|
-
export interface DecodeOptions {
|
|
52
|
-
/**
|
|
53
|
-
* Passphrase for encrypted inputs.
|
|
54
|
-
*/
|
|
55
|
-
passphrase?: string;
|
|
56
|
-
/**
|
|
57
|
-
* Directory to save debug images (doubled.png, reconstructed.png).
|
|
58
|
-
*/
|
|
59
|
-
debugDir?: string;
|
|
60
|
-
/**
|
|
61
|
-
* Path to write decoded output directly to disk (streamed) to avoid high memory usage.
|
|
62
|
-
*/
|
|
63
|
-
outPath?: string;
|
|
64
|
-
/**
|
|
65
|
-
* List of files to extract selectively from archives.
|
|
66
|
-
*/
|
|
67
|
-
files?: string[];
|
|
68
|
-
/**
|
|
69
|
-
* Progress callback for decoding phases.
|
|
70
|
-
*/
|
|
71
|
-
onProgress?: (info: {
|
|
72
|
-
phase: string;
|
|
73
|
-
loaded?: number;
|
|
74
|
-
total?: number;
|
|
75
|
-
}) => void;
|
|
76
|
-
/**
|
|
77
|
-
* Whether to display a progress bar in the console.
|
|
78
|
-
* @defaultValue `false`
|
|
79
|
-
*/
|
|
80
|
-
showProgress?: boolean;
|
|
81
|
-
}
|
|
82
|
-
export declare function cropAndReconstitute(input: Buffer, debugDir?: string): Promise<Buffer>;
|
|
83
|
-
/**
|
|
84
|
-
* Encode a Buffer into a PNG wrapper. Supports optional compression and
|
|
85
|
-
* encryption. Defaults are chosen for a good balance between speed and size.
|
|
86
|
-
*
|
|
87
|
-
* @param input - Data to encode
|
|
88
|
-
* @param opts - Encoding options
|
|
89
|
-
* @public
|
|
90
|
-
* @example
|
|
91
|
-
* ```typescript
|
|
92
|
-
* import { readFileSync, writeFileSync } from 'fs';
|
|
93
|
-
* import { encodeBinaryToPng } from 'roxify';
|
|
94
|
-
*
|
|
95
|
-
* const fileName = 'input.bin'; //Path of your input file here
|
|
96
|
-
* const inputBuffer = readFileSync(fileName);
|
|
97
|
-
* const pngBuffer = await encodeBinaryToPng(inputBuffer, {
|
|
98
|
-
* name: fileName,
|
|
99
|
-
* });
|
|
100
|
-
* writeFileSync('output.png', pngBuffer);
|
|
101
|
-
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
|
-
export declare function encodeBinaryToPng(input: Buffer, opts?: EncodeOptions): Promise<Buffer>;
|
|
105
|
-
/**
|
|
106
|
-
* Decode a PNG produced by this library back to the original Buffer.
|
|
107
|
-
* Supports the ROX binary format, rXDT chunk, and pixel encodings.
|
|
108
|
-
*
|
|
109
|
-
* @param pngBuf - PNG data
|
|
110
|
-
* @param opts - Options (passphrase for encrypted inputs)
|
|
111
|
-
* @public
|
|
112
|
-
* @example
|
|
113
|
-
* import { readFileSync, writeFileSync } from 'fs';
|
|
114
|
-
* import { decodePngToBinary } from 'roxify';
|
|
115
|
-
*
|
|
116
|
-
* const pngFromDisk = readFileSync('output.png'); //Path of the encoded PNG here
|
|
117
|
-
* const { buf, meta } = await decodePngToBinary(pngFromDisk);
|
|
118
|
-
* writeFileSync(meta?.name ?? 'decoded.txt', buf);
|
|
119
|
-
*/
|
|
120
|
-
export declare function decodePngToBinary(pngBuf: Buffer, opts?: DecodeOptions): Promise<DecodeResult>;
|
|
1
|
+
export * from './utils/constants.js';
|
|
2
|
+
export * from './utils/crc.js';
|
|
3
|
+
export * from './utils/decoder.js';
|
|
4
|
+
export * from './utils/encoder.js';
|
|
5
|
+
export * from './utils/errors.js';
|
|
6
|
+
export * from './utils/helpers.js';
|
|
7
|
+
export * from './utils/inspection.js';
|
|
8
|
+
export * from './utils/optimization.js';
|
|
9
|
+
export * from './utils/reconstitution.js';
|
|
10
|
+
export * from './utils/types.js';
|
|
11
|
+
export * from './utils/zstd.js';
|
|
121
12
|
export { decodeMinPng, encodeMinPng } from './minpng.js';
|
|
122
13
|
export { packPaths, unpackBuffer } from './pack.js';
|
|
123
|
-
/**
|
|
124
|
-
* List files in a Rox PNG archive without decoding the full payload.
|
|
125
|
-
* Returns the file list if available, otherwise null.
|
|
126
|
-
* @param pngBuf - PNG data
|
|
127
|
-
* @public
|
|
128
|
-
*/
|
|
129
|
-
export declare function listFilesInPng(pngBuf: Buffer): Promise<string[] | null>;
|
|
130
|
-
/**
|
|
131
|
-
* Detect if a PNG/ROX buffer contains an encrypted payload (requires passphrase)
|
|
132
|
-
* Returns true if encryption flag indicates AES or XOR.
|
|
133
|
-
*/
|
|
134
|
-
export declare function hasPassphraseInPng(pngBuf: Buffer): Promise<boolean>;
|