roxify 1.4.0 → 1.5.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/dist/cli.js +4 -3
- package/dist/hybrid-compression.d.ts +0 -2
- package/dist/hybrid-compression.js +1 -1
- package/dist/minpng.d.ts +0 -2
- package/dist/minpng.js +45 -12
- package/dist/pack.d.ts +0 -2
- package/dist/roxify-cli +0 -0
- package/dist/stub-progress.d.ts +9 -0
- package/dist/stub-progress.js +9 -0
- package/dist/utils/constants.d.ts +22 -7
- package/dist/utils/constants.js +5 -0
- package/dist/utils/crc.d.ts +0 -2
- package/dist/utils/decoder.d.ts +0 -2
- package/dist/utils/decoder.js +121 -123
- package/dist/utils/encoder.d.ts +0 -2
- package/dist/utils/encoder.js +12 -57
- package/dist/utils/helpers.d.ts +0 -2
- package/dist/utils/helpers.js +2 -4
- package/dist/utils/inspection.d.ts +0 -2
- package/dist/utils/inspection.js +23 -40
- package/dist/utils/native.d.ts +1 -0
- package/dist/utils/native.js +7 -0
- package/dist/utils/optimization.d.ts +0 -2
- package/dist/utils/optimization.js +19 -15
- package/dist/utils/reconstitution.d.ts +0 -2
- package/dist/utils/reconstitution.js +1 -264
- package/dist/utils/rust-cli-wrapper.d.ts +1 -1
- package/dist/utils/rust-cli-wrapper.js +6 -8
- package/dist/utils/types.d.ts +1 -2
- package/dist/utils/zstd.d.ts +0 -2
- package/dist/utils/zstd.js +32 -37
- package/libroxify_native.node +0 -0
- package/package.json +21 -23
- package/README.md +0 -391
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import cliProgress from 'cli-progress';
|
|
3
2
|
import { mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
4
3
|
import { open } from 'fs/promises';
|
|
5
4
|
import { basename, dirname, join, resolve } from 'path';
|
|
6
5
|
import { DataFormatError, decodePngToBinary, encodeBinaryToPng, hasPassphraseInPng, IncorrectPassphraseError, listFilesInPng, PassphraseRequiredError, } from './index.js';
|
|
7
6
|
import { packPathsGenerator, unpackBuffer } from './pack.js';
|
|
7
|
+
import * as cliProgress from './stub-progress.js';
|
|
8
8
|
import { encodeWithRustCLI, isRustBinaryAvailable, } from './utils/rust-cli-wrapper.js';
|
|
9
9
|
const VERSION = '1.4.0';
|
|
10
10
|
async function readLargeFile(filePath) {
|
|
@@ -211,7 +211,8 @@ async function encodeCommand(args) {
|
|
|
211
211
|
});
|
|
212
212
|
}, 500);
|
|
213
213
|
const encryptType = parsed.encrypt === 'xor' ? 'xor' : 'aes';
|
|
214
|
-
|
|
214
|
+
const fileName = basename(inputPaths[0]);
|
|
215
|
+
await encodeWithRustCLI(inputPaths.length === 1 ? resolvedInputs[0] : resolvedInputs[0], resolvedOutput, 12, parsed.passphrase, encryptType, fileName);
|
|
215
216
|
clearInterval(progressInterval);
|
|
216
217
|
const encodeTime = Date.now() - startTime;
|
|
217
218
|
encodeBar.update(100, {
|
|
@@ -284,7 +285,7 @@ async function encodeCommand(args) {
|
|
|
284
285
|
mode,
|
|
285
286
|
name: parsed.outputName || 'archive',
|
|
286
287
|
skipOptimization: false,
|
|
287
|
-
compressionLevel:
|
|
288
|
+
compressionLevel: 12,
|
|
288
289
|
outputFormat: 'auto',
|
|
289
290
|
});
|
|
290
291
|
if (parsed.verbose)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { native } from './utils/native.js';
|
|
1
2
|
let check_gpu_status;
|
|
2
3
|
let entropy_estimate;
|
|
3
4
|
let get_compression_stats;
|
|
4
5
|
let hybrid_compress;
|
|
5
6
|
let hybrid_decompress;
|
|
6
7
|
try {
|
|
7
|
-
const native = require('../libroxify_native.node');
|
|
8
8
|
check_gpu_status = native.check_gpu_status;
|
|
9
9
|
entropy_estimate = native.entropy_estimate;
|
|
10
10
|
get_compression_stats = native.get_compression_stats;
|
package/dist/minpng.d.ts
CHANGED
package/dist/minpng.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import { compress as zstdCompress, decompress as zstdDecompress, } from '@mongodb-js/zstd';
|
|
2
|
-
import encode from 'png-chunks-encode';
|
|
3
1
|
import { deflateSync } from 'zlib';
|
|
2
|
+
import { native } from './utils/native.js';
|
|
3
|
+
let nativeZstdCompress = null;
|
|
4
|
+
let nativeZstdDecompress = null;
|
|
5
|
+
let nativeEncodePngChunks = null;
|
|
6
|
+
try {
|
|
7
|
+
if (native?.nativeZstdCompress) {
|
|
8
|
+
nativeZstdCompress = native.nativeZstdCompress;
|
|
9
|
+
}
|
|
10
|
+
if (native?.nativeZstdDecompress) {
|
|
11
|
+
nativeZstdDecompress = native.nativeZstdDecompress;
|
|
12
|
+
}
|
|
13
|
+
if (native?.encodePngChunks) {
|
|
14
|
+
nativeEncodePngChunks = native.encodePngChunks;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (e) { }
|
|
4
18
|
const PIXEL_MAGIC = Buffer.from('MNPG');
|
|
5
19
|
const MARKER_START = [
|
|
6
20
|
{ r: 255, g: 0, b: 0 },
|
|
@@ -82,7 +96,10 @@ export async function encodeMinPng(rgb, width, height) {
|
|
|
82
96
|
transformed[tIdx++] = b;
|
|
83
97
|
}
|
|
84
98
|
const transformedBuf = Buffer.from(transformed);
|
|
85
|
-
|
|
99
|
+
if (!nativeZstdCompress) {
|
|
100
|
+
throw new Error('Native zstd compression not available');
|
|
101
|
+
}
|
|
102
|
+
const compressed = Buffer.from(nativeZstdCompress(transformedBuf, 19));
|
|
86
103
|
const header = Buffer.alloc(4 + 1 + 4 + 4);
|
|
87
104
|
PIXEL_MAGIC.copy(header, 0);
|
|
88
105
|
header[4] = 1;
|
|
@@ -142,16 +159,29 @@ export async function encodeMinPng(rgb, width, height) {
|
|
|
142
159
|
{ name: 'IDAT', data: idat },
|
|
143
160
|
{ name: 'IEND', data: Buffer.alloc(0) },
|
|
144
161
|
];
|
|
145
|
-
|
|
162
|
+
if (nativeEncodePngChunks) {
|
|
163
|
+
return Buffer.from(nativeEncodePngChunks(chunks));
|
|
164
|
+
}
|
|
165
|
+
const PNG_SIG = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
166
|
+
const output = [PNG_SIG];
|
|
167
|
+
for (const chunk of chunks) {
|
|
168
|
+
const type = Buffer.from(chunk.name, 'ascii');
|
|
169
|
+
const length = Buffer.alloc(4);
|
|
170
|
+
length.writeUInt32BE(chunk.data.length, 0);
|
|
171
|
+
const crcData = Buffer.concat([type, chunk.data]);
|
|
172
|
+
const crc = Buffer.alloc(4);
|
|
173
|
+
const crc32fast = native?.nativeCrc32;
|
|
174
|
+
const crcVal = crc32fast ? crc32fast(crcData) : 0;
|
|
175
|
+
crc.writeUInt32BE(crcVal, 0);
|
|
176
|
+
output.push(length, type, chunk.data, crc);
|
|
177
|
+
}
|
|
178
|
+
return Buffer.concat(output);
|
|
146
179
|
}
|
|
147
180
|
export async function decodeMinPng(pngBuf) {
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
.toBuffer({ resolveWithObject: true });
|
|
153
|
-
const currentWidth = info.width;
|
|
154
|
-
const currentHeight = info.height;
|
|
181
|
+
const rawData = native.sharpToRaw(pngBuf);
|
|
182
|
+
const data = rawData.pixels;
|
|
183
|
+
const currentWidth = rawData.width;
|
|
184
|
+
const currentHeight = rawData.height;
|
|
155
185
|
const rawRGB = Buffer.alloc(currentWidth * currentHeight * 3);
|
|
156
186
|
for (let i = 0; i < currentWidth * currentHeight; i++) {
|
|
157
187
|
rawRGB[i * 3] = data[i * 3];
|
|
@@ -190,7 +220,10 @@ export async function decodeMinPng(pngBuf) {
|
|
|
190
220
|
if (compStart + compressedLen > rawRGB.length)
|
|
191
221
|
return null;
|
|
192
222
|
const compressed = rawRGB.subarray(compStart, compStart + compressedLen);
|
|
193
|
-
|
|
223
|
+
if (!nativeZstdDecompress) {
|
|
224
|
+
throw new Error('Native zstd decompression not available');
|
|
225
|
+
}
|
|
226
|
+
const decompressed = Buffer.from(nativeZstdDecompress(compressed));
|
|
194
227
|
const indices = zigzagOrderIndices(origW, origH);
|
|
195
228
|
const residualR = new Uint8Array(origW * origH);
|
|
196
229
|
const residualG = new Uint8Array(origW * origH);
|
package/dist/pack.d.ts
CHANGED
package/dist/roxify-cli
CHANGED
|
Binary file
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
1
|
export declare const CHUNK_TYPE = "rXDT";
|
|
4
|
-
export declare const MAGIC: Buffer
|
|
5
|
-
export declare const PIXEL_MAGIC: Buffer
|
|
6
|
-
export declare const PIXEL_MAGIC_BLOCK: Buffer
|
|
2
|
+
export declare const MAGIC: Buffer<ArrayBuffer>;
|
|
3
|
+
export declare const PIXEL_MAGIC: Buffer<ArrayBuffer>;
|
|
4
|
+
export declare const PIXEL_MAGIC_BLOCK: Buffer<ArrayBuffer>;
|
|
7
5
|
export declare const ENC_NONE = 0;
|
|
8
6
|
export declare const ENC_AES = 1;
|
|
9
7
|
export declare const ENC_XOR = 2;
|
|
10
|
-
export declare const FILTER_ZERO: Buffer
|
|
11
|
-
export declare const PNG_HEADER: Buffer
|
|
8
|
+
export declare const FILTER_ZERO: Buffer<ArrayBuffer>;
|
|
9
|
+
export declare const PNG_HEADER: Buffer<ArrayBuffer>;
|
|
12
10
|
export declare const PNG_HEADER_HEX: string;
|
|
13
11
|
export declare const MARKER_COLORS: {
|
|
14
12
|
r: number;
|
|
@@ -37,3 +35,20 @@ export declare const COMPRESSION_MARKERS: {
|
|
|
37
35
|
b: number;
|
|
38
36
|
}[];
|
|
39
37
|
};
|
|
38
|
+
export declare const FORMAT_MARKERS: {
|
|
39
|
+
png: {
|
|
40
|
+
r: number;
|
|
41
|
+
g: number;
|
|
42
|
+
b: number;
|
|
43
|
+
};
|
|
44
|
+
webp: {
|
|
45
|
+
r: number;
|
|
46
|
+
g: number;
|
|
47
|
+
b: number;
|
|
48
|
+
};
|
|
49
|
+
jxl: {
|
|
50
|
+
r: number;
|
|
51
|
+
g: number;
|
|
52
|
+
b: number;
|
|
53
|
+
};
|
|
54
|
+
};
|
package/dist/utils/constants.js
CHANGED
package/dist/utils/crc.d.ts
CHANGED
package/dist/utils/decoder.d.ts
CHANGED
package/dist/utils/decoder.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
5
|
import { unpackBuffer } from '../pack.js';
|
|
6
6
|
import { CHUNK_TYPE, MAGIC, MARKER_END, MARKER_START, PIXEL_MAGIC, PIXEL_MAGIC_BLOCK, PNG_HEADER, } from './constants.js';
|
|
7
7
|
import { DataFormatError, IncorrectPassphraseError, PassphraseRequiredError, } from './errors.js';
|
|
8
8
|
import { colorsToBytes, deltaDecode, tryDecryptIfNeeded } from './helpers.js';
|
|
9
|
+
import { native } from './native.js';
|
|
9
10
|
import { cropAndReconstitute } from './reconstitution.js';
|
|
10
11
|
import { parallelZstdDecompress, tryZstdDecompress } from './zstd.js';
|
|
11
12
|
async function tryDecompress(payload, onProgress) {
|
|
@@ -34,6 +35,52 @@ async function tryDecompress(payload, onProgress) {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
function detectImageFormat(buf) {
|
|
39
|
+
if (buf.length < 12)
|
|
40
|
+
return 'unknown';
|
|
41
|
+
if (buf[0] === 0x89 &&
|
|
42
|
+
buf[1] === 0x50 &&
|
|
43
|
+
buf[2] === 0x4e &&
|
|
44
|
+
buf[3] === 0x47) {
|
|
45
|
+
return 'png';
|
|
46
|
+
}
|
|
47
|
+
if (buf[0] === 0x52 &&
|
|
48
|
+
buf[1] === 0x49 &&
|
|
49
|
+
buf[2] === 0x46 &&
|
|
50
|
+
buf[3] === 0x46 &&
|
|
51
|
+
buf[8] === 0x57 &&
|
|
52
|
+
buf[9] === 0x45 &&
|
|
53
|
+
buf[10] === 0x42 &&
|
|
54
|
+
buf[11] === 0x50) {
|
|
55
|
+
return 'webp';
|
|
56
|
+
}
|
|
57
|
+
if (buf[0] === 0xff && buf[1] === 0x0a) {
|
|
58
|
+
return 'jxl';
|
|
59
|
+
}
|
|
60
|
+
return 'unknown';
|
|
61
|
+
}
|
|
62
|
+
function convertToPng(buf, format) {
|
|
63
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'rox-decode-'));
|
|
64
|
+
const inputPath = join(tempDir, format === 'webp' ? 'input.webp' : 'input.jxl');
|
|
65
|
+
const outputPath = join(tempDir, 'output.png');
|
|
66
|
+
try {
|
|
67
|
+
writeFileSync(inputPath, buf);
|
|
68
|
+
if (format === 'webp') {
|
|
69
|
+
execFileSync('dwebp', [inputPath, '-o', outputPath]);
|
|
70
|
+
}
|
|
71
|
+
else if (format === 'jxl') {
|
|
72
|
+
execFileSync('djxl', [inputPath, outputPath]);
|
|
73
|
+
}
|
|
74
|
+
const pngBuf = readFileSync(outputPath);
|
|
75
|
+
return pngBuf;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
try {
|
|
79
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
80
|
+
}
|
|
81
|
+
catch (e) { }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
37
84
|
export async function decodePngToBinary(input, opts = {}) {
|
|
38
85
|
let pngBuf;
|
|
39
86
|
if (Buffer.isBuffer(input)) {
|
|
@@ -41,11 +88,17 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
41
88
|
}
|
|
42
89
|
else {
|
|
43
90
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
91
|
+
if (native?.sharpMetadata) {
|
|
92
|
+
const inputBuf = readFileSync(input);
|
|
93
|
+
const metadata = native.sharpMetadata(inputBuf);
|
|
94
|
+
const rawBytesEstimate = metadata.width * metadata.height * 4;
|
|
95
|
+
const MAX_RAW_BYTES = 200 * 1024 * 1024;
|
|
96
|
+
if (rawBytesEstimate > MAX_RAW_BYTES) {
|
|
97
|
+
pngBuf = inputBuf;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
pngBuf = inputBuf;
|
|
101
|
+
}
|
|
49
102
|
}
|
|
50
103
|
else {
|
|
51
104
|
pngBuf = readFileSync(input);
|
|
@@ -62,10 +115,11 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
62
115
|
}
|
|
63
116
|
let progressBar = null;
|
|
64
117
|
if (opts.showProgress) {
|
|
65
|
-
progressBar =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
118
|
+
progressBar = {
|
|
119
|
+
start: () => { },
|
|
120
|
+
update: () => { },
|
|
121
|
+
stop: () => { },
|
|
122
|
+
};
|
|
69
123
|
const startTime = Date.now();
|
|
70
124
|
if (!opts.onProgress) {
|
|
71
125
|
opts.onProgress = (info) => {
|
|
@@ -79,10 +133,6 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
79
133
|
else if (info.phase === 'done') {
|
|
80
134
|
pct = 100;
|
|
81
135
|
}
|
|
82
|
-
progressBar.update(Math.floor(pct), {
|
|
83
|
-
step: info.phase.replace('_', ' '),
|
|
84
|
-
elapsed: String(Math.floor((Date.now() - startTime) / 1000)),
|
|
85
|
-
});
|
|
86
136
|
};
|
|
87
137
|
}
|
|
88
138
|
}
|
|
@@ -90,28 +140,17 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
90
140
|
opts.onProgress({ phase: 'start' });
|
|
91
141
|
let processedBuf = pngBuf;
|
|
92
142
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const doubledBuffer = await sharp(pngBuf)
|
|
102
|
-
.resize({
|
|
103
|
-
width: info.width * 2,
|
|
104
|
-
height: info.height * 2,
|
|
105
|
-
kernel: 'nearest',
|
|
106
|
-
})
|
|
107
|
-
.png()
|
|
108
|
-
.toBuffer();
|
|
109
|
-
processedBuf = await cropAndReconstitute(doubledBuffer, opts.debugDir);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
processedBuf = pngBuf;
|
|
143
|
+
if (native?.sharpMetadata) {
|
|
144
|
+
const info = native.sharpMetadata(pngBuf);
|
|
145
|
+
if (info.width && info.height) {
|
|
146
|
+
const MAX_RAW_BYTES = 1200 * 1024 * 1024;
|
|
147
|
+
const rawBytesEstimate = info.width * info.height * 4;
|
|
148
|
+
if (rawBytesEstimate > MAX_RAW_BYTES) {
|
|
149
|
+
throw new DataFormatError(`Image too large to decode in-process (${Math.round(rawBytesEstimate / 1024 / 1024)} MB). Increase Node heap or use a smaller image/compact mode.`);
|
|
150
|
+
}
|
|
113
151
|
}
|
|
114
152
|
}
|
|
153
|
+
processedBuf = pngBuf;
|
|
115
154
|
}
|
|
116
155
|
catch (e) {
|
|
117
156
|
if (e instanceof DataFormatError)
|
|
@@ -155,24 +194,30 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
155
194
|
}
|
|
156
195
|
let chunks = [];
|
|
157
196
|
try {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
197
|
+
if (native?.extractPngChunks) {
|
|
198
|
+
const chunksRaw = native.extractPngChunks(processedBuf);
|
|
199
|
+
chunks = chunksRaw.map((c) => ({
|
|
200
|
+
name: c.name,
|
|
201
|
+
data: Buffer.from(c.data),
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
throw new Error('Native PNG chunk extraction not available');
|
|
206
|
+
}
|
|
165
207
|
}
|
|
166
208
|
catch (e) {
|
|
167
209
|
try {
|
|
168
210
|
const withHeader = Buffer.concat([PNG_HEADER, pngBuf]);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
211
|
+
if (native?.extractPngChunks) {
|
|
212
|
+
const chunksRaw = native.extractPngChunks(withHeader);
|
|
213
|
+
chunks = chunksRaw.map((c) => ({
|
|
214
|
+
name: c.name,
|
|
215
|
+
data: Buffer.from(c.data),
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
throw new Error('Native PNG chunk extraction not available');
|
|
220
|
+
}
|
|
176
221
|
}
|
|
177
222
|
catch (e2) {
|
|
178
223
|
chunks = [];
|
|
@@ -225,28 +270,21 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
225
270
|
return { buf: payload, meta: { name } };
|
|
226
271
|
}
|
|
227
272
|
try {
|
|
228
|
-
const metadata =
|
|
273
|
+
const metadata = native.sharpMetadata(processedBuf);
|
|
229
274
|
const currentWidth = metadata.width;
|
|
230
275
|
const currentHeight = metadata.height;
|
|
231
276
|
let rawRGB = Buffer.alloc(0);
|
|
232
277
|
let isBlockEncoded = false;
|
|
233
278
|
if (currentWidth % 2 === 0 && currentHeight % 2 === 0) {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
left: 0,
|
|
237
|
-
top: 0,
|
|
238
|
-
width: Math.min(4, currentWidth),
|
|
239
|
-
height: Math.min(4, currentHeight),
|
|
240
|
-
})
|
|
241
|
-
.raw()
|
|
242
|
-
.toBuffer({ resolveWithObject: true });
|
|
279
|
+
const rawData = native.sharpToRaw(processedBuf);
|
|
280
|
+
const testData = rawData.pixels;
|
|
243
281
|
let hasBlockPattern = true;
|
|
244
282
|
for (let y = 0; y < Math.min(2, currentHeight / 2); y++) {
|
|
245
283
|
for (let x = 0; x < Math.min(2, currentWidth / 2); x++) {
|
|
246
|
-
const px00 = (y * 2 *
|
|
247
|
-
const px01 = (y * 2 *
|
|
248
|
-
const px10 = ((y * 2 + 1) *
|
|
249
|
-
const px11 = ((y * 2 + 1) *
|
|
284
|
+
const px00 = (y * 2 * currentWidth + x * 2) * 3;
|
|
285
|
+
const px01 = (y * 2 * currentWidth + (x * 2 + 1)) * 3;
|
|
286
|
+
const px10 = ((y * 2 + 1) * currentWidth + x * 2) * 3;
|
|
287
|
+
const px11 = ((y * 2 + 1) * currentWidth + (x * 2 + 1)) * 3;
|
|
250
288
|
if (testData[px00] !== testData[px01] ||
|
|
251
289
|
testData[px00] !== testData[px10] ||
|
|
252
290
|
testData[px00] !== testData[px11] ||
|
|
@@ -265,56 +303,28 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
265
303
|
const blocksWide = currentWidth / 2;
|
|
266
304
|
const blocksHigh = currentHeight / 2;
|
|
267
305
|
rawRGB = Buffer.alloc(blocksWide * blocksHigh * 3);
|
|
306
|
+
const fullRaw = native.sharpToRaw(processedBuf);
|
|
307
|
+
const fullData = fullRaw.pixels;
|
|
268
308
|
let outIdx = 0;
|
|
269
309
|
for (let by = 0; by < blocksHigh; by++) {
|
|
270
310
|
for (let bx = 0; bx < blocksWide; bx++) {
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
rawRGB[outIdx++] = blockData[0];
|
|
276
|
-
rawRGB[outIdx++] = blockData[1];
|
|
277
|
-
rawRGB[outIdx++] = blockData[2];
|
|
311
|
+
const pixelOffset = (by * 2 * currentWidth + bx * 2) * 3;
|
|
312
|
+
rawRGB[outIdx++] = fullData[pixelOffset];
|
|
313
|
+
rawRGB[outIdx++] = fullData[pixelOffset + 1];
|
|
314
|
+
rawRGB[outIdx++] = fullData[pixelOffset + 2];
|
|
278
315
|
}
|
|
279
316
|
}
|
|
280
317
|
}
|
|
281
318
|
}
|
|
282
319
|
if (!isBlockEncoded) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
left: 0,
|
|
292
|
-
top: startRow,
|
|
293
|
-
width: currentWidth,
|
|
294
|
-
height: chunkHeight,
|
|
295
|
-
})
|
|
296
|
-
.raw()
|
|
297
|
-
.toBuffer({ resolveWithObject: true });
|
|
298
|
-
const channels = chunkInfo.channels;
|
|
299
|
-
const pixelsInChunk = currentWidth * chunkHeight;
|
|
300
|
-
if (channels === 3) {
|
|
301
|
-
chunkData.copy(rawRGB, writeOffset);
|
|
302
|
-
writeOffset += pixelsInChunk * 3;
|
|
303
|
-
}
|
|
304
|
-
else if (channels === 4) {
|
|
305
|
-
for (let i = 0; i < pixelsInChunk; i++) {
|
|
306
|
-
rawRGB[writeOffset++] = chunkData[i * 4];
|
|
307
|
-
rawRGB[writeOffset++] = chunkData[i * 4 + 1];
|
|
308
|
-
rawRGB[writeOffset++] = chunkData[i * 4 + 2];
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
if (opts.onProgress) {
|
|
312
|
-
opts.onProgress({
|
|
313
|
-
phase: 'extract_pixels',
|
|
314
|
-
loaded: endRow,
|
|
315
|
-
total: currentHeight,
|
|
316
|
-
});
|
|
317
|
-
}
|
|
320
|
+
const rawData = native.sharpToRaw(processedBuf);
|
|
321
|
+
rawRGB = Buffer.from(rawData.pixels);
|
|
322
|
+
if (opts.onProgress) {
|
|
323
|
+
opts.onProgress({
|
|
324
|
+
phase: 'extract_pixels',
|
|
325
|
+
loaded: currentHeight,
|
|
326
|
+
total: currentHeight,
|
|
327
|
+
});
|
|
318
328
|
}
|
|
319
329
|
}
|
|
320
330
|
const firstPixels = [];
|
|
@@ -361,22 +371,10 @@ export async function decodePngToBinary(input, opts = {}) {
|
|
|
361
371
|
}
|
|
362
372
|
else {
|
|
363
373
|
const reconstructed = await cropAndReconstitute(processedBuf, opts.debugDir);
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
logicalHeight = rinfo.height;
|
|
369
|
-
logicalData = Buffer.alloc(rinfo.width * rinfo.height * 3);
|
|
370
|
-
if (rinfo.channels === 3) {
|
|
371
|
-
rdata.copy(logicalData);
|
|
372
|
-
}
|
|
373
|
-
else if (rinfo.channels === 4) {
|
|
374
|
-
for (let i = 0; i < logicalWidth * logicalHeight; i++) {
|
|
375
|
-
logicalData[i * 3] = rdata[i * 4];
|
|
376
|
-
logicalData[i * 3 + 1] = rdata[i * 4 + 1];
|
|
377
|
-
logicalData[i * 3 + 2] = rdata[i * 4 + 2];
|
|
378
|
-
}
|
|
379
|
-
}
|
|
374
|
+
const rawData = native.sharpToRaw(reconstructed);
|
|
375
|
+
logicalWidth = rawData.width;
|
|
376
|
+
logicalHeight = rawData.height;
|
|
377
|
+
logicalData = Buffer.from(rawData.pixels);
|
|
380
378
|
}
|
|
381
379
|
if (process.env.ROX_DEBUG) {
|
|
382
380
|
console.log('DEBUG: Logical grid reconstructed:', logicalWidth, 'x', logicalHeight, '=', logicalWidth * logicalHeight, 'pixels');
|
package/dist/utils/encoder.d.ts
CHANGED