byte-codec 1.5.2 → 1.5.4
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/index.cjs +23 -28
- package/dist/index.js +23 -28
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,6 @@ var ByteWriter = class {
|
|
|
8
8
|
return this.byteLength;
|
|
9
9
|
}
|
|
10
10
|
writeBytes(bytes) {
|
|
11
|
-
if (bytes.length === 0) return;
|
|
12
11
|
this.chunks.push(bytes);
|
|
13
12
|
this.byteLength += bytes.length;
|
|
14
13
|
}
|
|
@@ -128,8 +127,8 @@ function inflateTolerant(data) {
|
|
|
128
127
|
};
|
|
129
128
|
} catch {}
|
|
130
129
|
let offset = 0;
|
|
131
|
-
while (
|
|
132
|
-
|
|
130
|
+
while (isAsciiWhitespace(data[offset])) offset++;
|
|
131
|
+
try {
|
|
133
132
|
return {
|
|
134
133
|
bytes: inflate(data.subarray(offset)),
|
|
135
134
|
recovered: true
|
|
@@ -161,8 +160,9 @@ function paethPredictor(a, b, c) {
|
|
|
161
160
|
const pa = Math.abs(p - a);
|
|
162
161
|
const pb = Math.abs(p - b);
|
|
163
162
|
const pc = Math.abs(p - c);
|
|
164
|
-
|
|
165
|
-
if (
|
|
163
|
+
const smallest = Math.min(pa, pb, pc);
|
|
164
|
+
if (smallest === pa) return a;
|
|
165
|
+
if (smallest === pb) return b;
|
|
166
166
|
return c;
|
|
167
167
|
}
|
|
168
168
|
function isPngFilterType(value) {
|
|
@@ -185,7 +185,7 @@ function unfilterScanlines(data, height, bytesPerRow, bpp) {
|
|
|
185
185
|
const rowStart = y * stride + 1;
|
|
186
186
|
const outRowStart = y * bytesPerRow;
|
|
187
187
|
const prevOutRowStart = y > 0 ? outRowStart - bytesPerRow : void 0;
|
|
188
|
-
for (
|
|
188
|
+
for (const x of Array.from({ length: bytesPerRow }, (_, i) => i)) {
|
|
189
189
|
const raw = data[rowStart + x];
|
|
190
190
|
const a = x >= bpp ? out[outRowStart + x - bpp] : 0;
|
|
191
191
|
const b = prevOutRowStart === void 0 ? 0 : out[prevOutRowStart + x];
|
|
@@ -197,11 +197,11 @@ function unfilterScanlines(data, height, bytesPerRow, bpp) {
|
|
|
197
197
|
}
|
|
198
198
|
function sumOfAbsSigned(bytes) {
|
|
199
199
|
let sum = 0;
|
|
200
|
-
for (const byte of bytes) sum += byte
|
|
200
|
+
for (const byte of bytes) sum += Math.min(byte, 256 - byte);
|
|
201
201
|
return sum;
|
|
202
202
|
}
|
|
203
203
|
function filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, filterType, out, outOffset) {
|
|
204
|
-
for (
|
|
204
|
+
for (const x of Array.from({ length: bytesPerRow }, (_, i) => i)) {
|
|
205
205
|
const rawByte = raw[rowStart + x];
|
|
206
206
|
const a = x >= bpp ? raw[rowStart + x - bpp] : 0;
|
|
207
207
|
const b = prevRowStart === void 0 ? 0 : raw[prevRowStart + x];
|
|
@@ -305,7 +305,7 @@ function detectPalette(image) {
|
|
|
305
305
|
const g = data[base + 1] ?? 0;
|
|
306
306
|
const b = data[base + 2] ?? 0;
|
|
307
307
|
const a = alpha === void 0 ? 255 : alpha[i] ?? 0;
|
|
308
|
-
const key = r
|
|
308
|
+
const key = r | g << 8 | b << 16 | a << 24;
|
|
309
309
|
let index = colorToIndex.get(key);
|
|
310
310
|
if (index === void 0) {
|
|
311
311
|
if (colorToIndex.size >= MAX_PALETTE_ENTRIES) return;
|
|
@@ -348,10 +348,10 @@ function writeTruecolorPng(writer, image, options) {
|
|
|
348
348
|
const bytesPerRow = width * outChannels;
|
|
349
349
|
const pixelCount = width * height;
|
|
350
350
|
const interleaved = new Uint8Array(pixelCount * outChannels);
|
|
351
|
-
for (
|
|
351
|
+
for (const i of Array.from({ length: pixelCount }, (_, index) => index)) {
|
|
352
352
|
const srcBase = i * channels;
|
|
353
353
|
const dstBase = i * outChannels;
|
|
354
|
-
for (
|
|
354
|
+
for (const c of Array.from({ length: channels }, (_, index) => index)) interleaved[dstBase + c] = data[srcBase + c];
|
|
355
355
|
if (alpha !== void 0) interleaved[dstBase + channels] = alpha[i];
|
|
356
356
|
}
|
|
357
357
|
writeIhdr(writer, width, height, colorTypeFor(image));
|
|
@@ -435,19 +435,14 @@ function filterBpp(bitDepth, channels) {
|
|
|
435
435
|
}
|
|
436
436
|
function unpackRow(rowBytes, width, channels, bitDepth) {
|
|
437
437
|
const sampleCount = width * channels;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const shift = 8 - bitDepth - (bitOffset & 7);
|
|
447
|
-
samples[i] = rowBytes[byteIndex] >> shift & mask;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return samples;
|
|
438
|
+
if (bitDepth === 16) return Array.from({ length: sampleCount }, (_, i) => rowBytes[i * 2]);
|
|
439
|
+
const mask = (1 << bitDepth) - 1;
|
|
440
|
+
return Array.from({ length: sampleCount }, (_, i) => {
|
|
441
|
+
const bitOffset = i * bitDepth;
|
|
442
|
+
const byteIndex = bitOffset >> 3;
|
|
443
|
+
const shift = 8 - bitDepth - (bitOffset & 7);
|
|
444
|
+
return rowBytes[byteIndex] >> shift & mask;
|
|
445
|
+
});
|
|
451
446
|
}
|
|
452
447
|
function readTrnsGrayValue(trns) {
|
|
453
448
|
return requireDataView(trns).getUint16(0);
|
|
@@ -480,7 +475,7 @@ function decodePng(bytes, options = {}) {
|
|
|
480
475
|
const { bytes: inflated, recovered } = inflateTolerant(concatBytes(idatChunks));
|
|
481
476
|
if (recovered && options.onWarning !== void 0) options.onWarning("PNG IDAT stream required tolerant recovery (truncated or malformed)");
|
|
482
477
|
const unfiltered = unfilterScanlines(inflated, ihdr.height, bytesPerRow, bpp);
|
|
483
|
-
const palette =
|
|
478
|
+
const palette = chunks.find((c) => c.type === "PLTE")?.data;
|
|
484
479
|
if (ihdr.colorType === 3 && palette === void 0) throw new Error("indexed-colour PNG has no PLTE chunk");
|
|
485
480
|
const trns = chunks.find((c) => c.type === "tRNS")?.data;
|
|
486
481
|
return buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns);
|
|
@@ -492,10 +487,10 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
492
487
|
const alpha = colorType === 4 || colorType === 6 || trns !== void 0 ? new Uint8Array(width * height).fill(255) : void 0;
|
|
493
488
|
const trnsGray = colorType === 0 && trns !== void 0 ? readTrnsGrayValue(trns) : void 0;
|
|
494
489
|
const trnsRgb = colorType === 2 && trns !== void 0 ? readTrnsRgbKey(trns) : void 0;
|
|
495
|
-
for (
|
|
490
|
+
for (const y of Array.from({ length: height }, (_, i) => i)) {
|
|
496
491
|
const rowStart = y * bytesPerRow;
|
|
497
492
|
const samples = unpackRow(unfiltered.subarray(rowStart, rowStart + bytesPerRow), width, channels, bitDepth);
|
|
498
|
-
for (
|
|
493
|
+
for (const x of Array.from({ length: width }, (_, i) => i)) {
|
|
499
494
|
const pixelBase = x * channels;
|
|
500
495
|
const outBase = (y * width + x) * outChannels;
|
|
501
496
|
const alphaIndex = y * width + x;
|
|
@@ -584,7 +579,7 @@ function readJpegInfo(bytes) {
|
|
|
584
579
|
if (requireByte(bytes, 0) !== 255 || requireByte(bytes, 1) !== SOI) throw new Error("not a valid JPEG file: missing SOI marker");
|
|
585
580
|
let offset = 2;
|
|
586
581
|
let adobeTransform;
|
|
587
|
-
while (offset
|
|
582
|
+
while (bytes[offset] !== void 0) {
|
|
588
583
|
if (bytes[offset] !== 255) {
|
|
589
584
|
offset++;
|
|
590
585
|
continue;
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,6 @@ var ByteWriter = class {
|
|
|
7
7
|
return this.byteLength;
|
|
8
8
|
}
|
|
9
9
|
writeBytes(bytes) {
|
|
10
|
-
if (bytes.length === 0) return;
|
|
11
10
|
this.chunks.push(bytes);
|
|
12
11
|
this.byteLength += bytes.length;
|
|
13
12
|
}
|
|
@@ -127,8 +126,8 @@ function inflateTolerant(data) {
|
|
|
127
126
|
};
|
|
128
127
|
} catch {}
|
|
129
128
|
let offset = 0;
|
|
130
|
-
while (
|
|
131
|
-
|
|
129
|
+
while (isAsciiWhitespace(data[offset])) offset++;
|
|
130
|
+
try {
|
|
132
131
|
return {
|
|
133
132
|
bytes: inflate(data.subarray(offset)),
|
|
134
133
|
recovered: true
|
|
@@ -160,8 +159,9 @@ function paethPredictor(a, b, c) {
|
|
|
160
159
|
const pa = Math.abs(p - a);
|
|
161
160
|
const pb = Math.abs(p - b);
|
|
162
161
|
const pc = Math.abs(p - c);
|
|
163
|
-
|
|
164
|
-
if (
|
|
162
|
+
const smallest = Math.min(pa, pb, pc);
|
|
163
|
+
if (smallest === pa) return a;
|
|
164
|
+
if (smallest === pb) return b;
|
|
165
165
|
return c;
|
|
166
166
|
}
|
|
167
167
|
function isPngFilterType(value) {
|
|
@@ -184,7 +184,7 @@ function unfilterScanlines(data, height, bytesPerRow, bpp) {
|
|
|
184
184
|
const rowStart = y * stride + 1;
|
|
185
185
|
const outRowStart = y * bytesPerRow;
|
|
186
186
|
const prevOutRowStart = y > 0 ? outRowStart - bytesPerRow : void 0;
|
|
187
|
-
for (
|
|
187
|
+
for (const x of Array.from({ length: bytesPerRow }, (_, i) => i)) {
|
|
188
188
|
const raw = data[rowStart + x];
|
|
189
189
|
const a = x >= bpp ? out[outRowStart + x - bpp] : 0;
|
|
190
190
|
const b = prevOutRowStart === void 0 ? 0 : out[prevOutRowStart + x];
|
|
@@ -196,11 +196,11 @@ function unfilterScanlines(data, height, bytesPerRow, bpp) {
|
|
|
196
196
|
}
|
|
197
197
|
function sumOfAbsSigned(bytes) {
|
|
198
198
|
let sum = 0;
|
|
199
|
-
for (const byte of bytes) sum += byte
|
|
199
|
+
for (const byte of bytes) sum += Math.min(byte, 256 - byte);
|
|
200
200
|
return sum;
|
|
201
201
|
}
|
|
202
202
|
function filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, filterType, out, outOffset) {
|
|
203
|
-
for (
|
|
203
|
+
for (const x of Array.from({ length: bytesPerRow }, (_, i) => i)) {
|
|
204
204
|
const rawByte = raw[rowStart + x];
|
|
205
205
|
const a = x >= bpp ? raw[rowStart + x - bpp] : 0;
|
|
206
206
|
const b = prevRowStart === void 0 ? 0 : raw[prevRowStart + x];
|
|
@@ -304,7 +304,7 @@ function detectPalette(image) {
|
|
|
304
304
|
const g = data[base + 1] ?? 0;
|
|
305
305
|
const b = data[base + 2] ?? 0;
|
|
306
306
|
const a = alpha === void 0 ? 255 : alpha[i] ?? 0;
|
|
307
|
-
const key = r
|
|
307
|
+
const key = r | g << 8 | b << 16 | a << 24;
|
|
308
308
|
let index = colorToIndex.get(key);
|
|
309
309
|
if (index === void 0) {
|
|
310
310
|
if (colorToIndex.size >= MAX_PALETTE_ENTRIES) return;
|
|
@@ -347,10 +347,10 @@ function writeTruecolorPng(writer, image, options) {
|
|
|
347
347
|
const bytesPerRow = width * outChannels;
|
|
348
348
|
const pixelCount = width * height;
|
|
349
349
|
const interleaved = new Uint8Array(pixelCount * outChannels);
|
|
350
|
-
for (
|
|
350
|
+
for (const i of Array.from({ length: pixelCount }, (_, index) => index)) {
|
|
351
351
|
const srcBase = i * channels;
|
|
352
352
|
const dstBase = i * outChannels;
|
|
353
|
-
for (
|
|
353
|
+
for (const c of Array.from({ length: channels }, (_, index) => index)) interleaved[dstBase + c] = data[srcBase + c];
|
|
354
354
|
if (alpha !== void 0) interleaved[dstBase + channels] = alpha[i];
|
|
355
355
|
}
|
|
356
356
|
writeIhdr(writer, width, height, colorTypeFor(image));
|
|
@@ -434,19 +434,14 @@ function filterBpp(bitDepth, channels) {
|
|
|
434
434
|
}
|
|
435
435
|
function unpackRow(rowBytes, width, channels, bitDepth) {
|
|
436
436
|
const sampleCount = width * channels;
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const shift = 8 - bitDepth - (bitOffset & 7);
|
|
446
|
-
samples[i] = rowBytes[byteIndex] >> shift & mask;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return samples;
|
|
437
|
+
if (bitDepth === 16) return Array.from({ length: sampleCount }, (_, i) => rowBytes[i * 2]);
|
|
438
|
+
const mask = (1 << bitDepth) - 1;
|
|
439
|
+
return Array.from({ length: sampleCount }, (_, i) => {
|
|
440
|
+
const bitOffset = i * bitDepth;
|
|
441
|
+
const byteIndex = bitOffset >> 3;
|
|
442
|
+
const shift = 8 - bitDepth - (bitOffset & 7);
|
|
443
|
+
return rowBytes[byteIndex] >> shift & mask;
|
|
444
|
+
});
|
|
450
445
|
}
|
|
451
446
|
function readTrnsGrayValue(trns) {
|
|
452
447
|
return requireDataView(trns).getUint16(0);
|
|
@@ -479,7 +474,7 @@ function decodePng(bytes, options = {}) {
|
|
|
479
474
|
const { bytes: inflated, recovered } = inflateTolerant(concatBytes(idatChunks));
|
|
480
475
|
if (recovered && options.onWarning !== void 0) options.onWarning("PNG IDAT stream required tolerant recovery (truncated or malformed)");
|
|
481
476
|
const unfiltered = unfilterScanlines(inflated, ihdr.height, bytesPerRow, bpp);
|
|
482
|
-
const palette =
|
|
477
|
+
const palette = chunks.find((c) => c.type === "PLTE")?.data;
|
|
483
478
|
if (ihdr.colorType === 3 && palette === void 0) throw new Error("indexed-colour PNG has no PLTE chunk");
|
|
484
479
|
const trns = chunks.find((c) => c.type === "tRNS")?.data;
|
|
485
480
|
return buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns);
|
|
@@ -491,10 +486,10 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
491
486
|
const alpha = colorType === 4 || colorType === 6 || trns !== void 0 ? new Uint8Array(width * height).fill(255) : void 0;
|
|
492
487
|
const trnsGray = colorType === 0 && trns !== void 0 ? readTrnsGrayValue(trns) : void 0;
|
|
493
488
|
const trnsRgb = colorType === 2 && trns !== void 0 ? readTrnsRgbKey(trns) : void 0;
|
|
494
|
-
for (
|
|
489
|
+
for (const y of Array.from({ length: height }, (_, i) => i)) {
|
|
495
490
|
const rowStart = y * bytesPerRow;
|
|
496
491
|
const samples = unpackRow(unfiltered.subarray(rowStart, rowStart + bytesPerRow), width, channels, bitDepth);
|
|
497
|
-
for (
|
|
492
|
+
for (const x of Array.from({ length: width }, (_, i) => i)) {
|
|
498
493
|
const pixelBase = x * channels;
|
|
499
494
|
const outBase = (y * width + x) * outChannels;
|
|
500
495
|
const alphaIndex = y * width + x;
|
|
@@ -583,7 +578,7 @@ function readJpegInfo(bytes) {
|
|
|
583
578
|
if (requireByte(bytes, 0) !== 255 || requireByte(bytes, 1) !== SOI) throw new Error("not a valid JPEG file: missing SOI marker");
|
|
584
579
|
let offset = 2;
|
|
585
580
|
let adobeTransform;
|
|
586
|
-
while (offset
|
|
581
|
+
while (bytes[offset] !== void 0) {
|
|
587
582
|
if (bytes[offset] !== 255) {
|
|
588
583
|
offset++;
|
|
589
584
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "byte-codec",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "Generic byte-level primitives (ByteWriter, ByteReader, CRC-32, deflate/inflate) and PNG/JPEG image encoding/decoding with zero PDF knowledge — the shared utility package for the documents.js family.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|