byte-codec 1.5.6 → 1.5.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.
- package/dist/index.cjs +66 -39
- package/dist/index.js +66 -39
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -195,20 +195,45 @@ function unfilterScanlines(data, height, bytesPerRow, bpp) {
|
|
|
195
195
|
}
|
|
196
196
|
return out;
|
|
197
197
|
}
|
|
198
|
-
function
|
|
198
|
+
function filterRowInto(current, previous, bpp, filterType, target) {
|
|
199
199
|
let sum = 0;
|
|
200
|
-
|
|
200
|
+
switch (filterType) {
|
|
201
|
+
case 1:
|
|
202
|
+
target.forEach((_byte, x) => {
|
|
203
|
+
const filtered = current[x + bpp] - current[x] & 255;
|
|
204
|
+
target[x] = filtered;
|
|
205
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
206
|
+
});
|
|
207
|
+
break;
|
|
208
|
+
case 2:
|
|
209
|
+
target.forEach((_byte, x) => {
|
|
210
|
+
const filtered = current[x + bpp] - previous[x + bpp] & 255;
|
|
211
|
+
target[x] = filtered;
|
|
212
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
case 3:
|
|
216
|
+
target.forEach((_byte, x) => {
|
|
217
|
+
const filtered = current[x + bpp] - Math.floor((current[x] + previous[x + bpp]) / 2) & 255;
|
|
218
|
+
target[x] = filtered;
|
|
219
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
220
|
+
});
|
|
221
|
+
break;
|
|
222
|
+
case 4:
|
|
223
|
+
target.forEach((_byte, x) => {
|
|
224
|
+
const filtered = current[x + bpp] - paethPredictor(current[x], previous[x + bpp], previous[x]) & 255;
|
|
225
|
+
target[x] = filtered;
|
|
226
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
227
|
+
});
|
|
228
|
+
break;
|
|
229
|
+
case 0: target.forEach((_byte, x) => {
|
|
230
|
+
const filtered = current[x + bpp];
|
|
231
|
+
target[x] = filtered;
|
|
232
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
201
235
|
return sum;
|
|
202
236
|
}
|
|
203
|
-
function filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, filterType, out, outOffset) {
|
|
204
|
-
out.subarray(outOffset, outOffset + bytesPerRow).forEach((_byte, x) => {
|
|
205
|
-
const rawByte = raw[rowStart + x];
|
|
206
|
-
const a = x >= bpp ? raw[rowStart + x - bpp] : 0;
|
|
207
|
-
const b = prevRowStart === void 0 ? 0 : raw[prevRowStart + x];
|
|
208
|
-
const c = x >= bpp && prevRowStart !== void 0 ? raw[prevRowStart + x - bpp] : 0;
|
|
209
|
-
out[outOffset + x] = rawByte - predictorValue(filterType, a, b, c) & 255;
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
237
|
const ALL_FILTER_TYPES = [
|
|
213
238
|
0,
|
|
214
239
|
1,
|
|
@@ -219,31 +244,27 @@ const ALL_FILTER_TYPES = [
|
|
|
219
244
|
function filterScanlines(raw, height, bytesPerRow, bpp, strategy = "adaptive") {
|
|
220
245
|
const stride = bytesPerRow + 1;
|
|
221
246
|
const out = new Uint8Array(height * stride);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, 0, out, outRowStart + 1);
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
247
|
+
let current = new Uint8Array(bytesPerRow + bpp);
|
|
248
|
+
let previous = new Uint8Array(bytesPerRow + bpp);
|
|
249
|
+
let candidate = new Uint8Array(bytesPerRow);
|
|
250
|
+
let best = new Uint8Array(bytesPerRow);
|
|
251
|
+
const filterTypes = strategy === "none" ? [0] : ALL_FILTER_TYPES;
|
|
252
|
+
Array.from({ length: height }).forEach((_row, y) => {
|
|
253
|
+
current.set(raw.subarray(y * bytesPerRow, (y + 1) * bytesPerRow), bpp);
|
|
232
254
|
let bestType = 0;
|
|
233
255
|
let bestSum = Number.POSITIVE_INFINITY;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, filterType, candidate, 0);
|
|
237
|
-
const sum = sumOfAbsSigned(candidate);
|
|
256
|
+
for (const filterType of filterTypes) {
|
|
257
|
+
const sum = filterRowInto(current, previous, bpp, filterType, candidate);
|
|
238
258
|
if (sum < bestSum) {
|
|
239
259
|
bestSum = sum;
|
|
240
260
|
bestType = filterType;
|
|
241
|
-
best = candidate
|
|
261
|
+
[best, candidate] = [candidate, best];
|
|
242
262
|
}
|
|
243
263
|
}
|
|
244
|
-
out[
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
out[y * stride] = bestType;
|
|
265
|
+
out.set(best, y * stride + 1);
|
|
266
|
+
[previous, current] = [current, previous];
|
|
267
|
+
});
|
|
247
268
|
return out;
|
|
248
269
|
}
|
|
249
270
|
//#endregion
|
|
@@ -432,15 +453,19 @@ function channelsForColorType(colorType) {
|
|
|
432
453
|
function filterBpp(bitDepth, channels) {
|
|
433
454
|
return Math.max(1, Math.ceil(bitDepth * channels / 8));
|
|
434
455
|
}
|
|
435
|
-
function unpackRow(rowBytes,
|
|
436
|
-
|
|
437
|
-
|
|
456
|
+
function unpackRow(rowBytes, samples, bitDepth) {
|
|
457
|
+
if (bitDepth === 16) {
|
|
458
|
+
samples.forEach((_sample, i) => {
|
|
459
|
+
samples[i] = rowBytes[i * 2];
|
|
460
|
+
});
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
438
463
|
const mask = (1 << bitDepth) - 1;
|
|
439
|
-
|
|
464
|
+
samples.forEach((_sample, i) => {
|
|
440
465
|
const bitOffset = i * bitDepth;
|
|
441
466
|
const byteIndex = bitOffset >> 3;
|
|
442
467
|
const shift = 8 - bitDepth - (bitOffset & 7);
|
|
443
|
-
|
|
468
|
+
samples[i] = rowBytes[byteIndex] >> shift & mask;
|
|
444
469
|
});
|
|
445
470
|
}
|
|
446
471
|
function readTrnsGrayValue(trns) {
|
|
@@ -486,10 +511,12 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
486
511
|
const alpha = colorType === 4 || colorType === 6 || trns !== void 0 ? new Uint8Array(width * height).fill(255) : void 0;
|
|
487
512
|
const trnsGray = colorType === 0 && trns !== void 0 ? readTrnsGrayValue(trns) : void 0;
|
|
488
513
|
const trnsRgb = colorType === 2 && trns !== void 0 ? readTrnsRgbKey(trns) : void 0;
|
|
489
|
-
|
|
514
|
+
const samples = new Uint8Array(width * channels);
|
|
515
|
+
const columns = new Uint32Array(width);
|
|
516
|
+
Array.from({ length: height }).forEach((_row, y) => {
|
|
490
517
|
const rowStart = y * bytesPerRow;
|
|
491
|
-
|
|
492
|
-
|
|
518
|
+
unpackRow(unfiltered.subarray(rowStart, rowStart + bytesPerRow), samples, bitDepth);
|
|
519
|
+
columns.forEach((_column, x) => {
|
|
493
520
|
const pixelBase = x * channels;
|
|
494
521
|
const outBase = (y * width + x) * outChannels;
|
|
495
522
|
const alphaIndex = y * width + x;
|
|
@@ -525,8 +552,8 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
525
552
|
data[outBase + 2] = samples[pixelBase + 2];
|
|
526
553
|
if (alpha !== void 0) alpha[alphaIndex] = samples[pixelBase + 3];
|
|
527
554
|
}
|
|
528
|
-
}
|
|
529
|
-
}
|
|
555
|
+
});
|
|
556
|
+
});
|
|
530
557
|
return alpha === void 0 ? {
|
|
531
558
|
width,
|
|
532
559
|
height,
|
package/dist/index.js
CHANGED
|
@@ -194,20 +194,45 @@ function unfilterScanlines(data, height, bytesPerRow, bpp) {
|
|
|
194
194
|
}
|
|
195
195
|
return out;
|
|
196
196
|
}
|
|
197
|
-
function
|
|
197
|
+
function filterRowInto(current, previous, bpp, filterType, target) {
|
|
198
198
|
let sum = 0;
|
|
199
|
-
|
|
199
|
+
switch (filterType) {
|
|
200
|
+
case 1:
|
|
201
|
+
target.forEach((_byte, x) => {
|
|
202
|
+
const filtered = current[x + bpp] - current[x] & 255;
|
|
203
|
+
target[x] = filtered;
|
|
204
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
205
|
+
});
|
|
206
|
+
break;
|
|
207
|
+
case 2:
|
|
208
|
+
target.forEach((_byte, x) => {
|
|
209
|
+
const filtered = current[x + bpp] - previous[x + bpp] & 255;
|
|
210
|
+
target[x] = filtered;
|
|
211
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
212
|
+
});
|
|
213
|
+
break;
|
|
214
|
+
case 3:
|
|
215
|
+
target.forEach((_byte, x) => {
|
|
216
|
+
const filtered = current[x + bpp] - Math.floor((current[x] + previous[x + bpp]) / 2) & 255;
|
|
217
|
+
target[x] = filtered;
|
|
218
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
case 4:
|
|
222
|
+
target.forEach((_byte, x) => {
|
|
223
|
+
const filtered = current[x + bpp] - paethPredictor(current[x], previous[x + bpp], previous[x]) & 255;
|
|
224
|
+
target[x] = filtered;
|
|
225
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
226
|
+
});
|
|
227
|
+
break;
|
|
228
|
+
case 0: target.forEach((_byte, x) => {
|
|
229
|
+
const filtered = current[x + bpp];
|
|
230
|
+
target[x] = filtered;
|
|
231
|
+
sum += Math.min(filtered, 256 - filtered);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
200
234
|
return sum;
|
|
201
235
|
}
|
|
202
|
-
function filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, filterType, out, outOffset) {
|
|
203
|
-
out.subarray(outOffset, outOffset + bytesPerRow).forEach((_byte, x) => {
|
|
204
|
-
const rawByte = raw[rowStart + x];
|
|
205
|
-
const a = x >= bpp ? raw[rowStart + x - bpp] : 0;
|
|
206
|
-
const b = prevRowStart === void 0 ? 0 : raw[prevRowStart + x];
|
|
207
|
-
const c = x >= bpp && prevRowStart !== void 0 ? raw[prevRowStart + x - bpp] : 0;
|
|
208
|
-
out[outOffset + x] = rawByte - predictorValue(filterType, a, b, c) & 255;
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
236
|
const ALL_FILTER_TYPES = [
|
|
212
237
|
0,
|
|
213
238
|
1,
|
|
@@ -218,31 +243,27 @@ const ALL_FILTER_TYPES = [
|
|
|
218
243
|
function filterScanlines(raw, height, bytesPerRow, bpp, strategy = "adaptive") {
|
|
219
244
|
const stride = bytesPerRow + 1;
|
|
220
245
|
const out = new Uint8Array(height * stride);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, 0, out, outRowStart + 1);
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
246
|
+
let current = new Uint8Array(bytesPerRow + bpp);
|
|
247
|
+
let previous = new Uint8Array(bytesPerRow + bpp);
|
|
248
|
+
let candidate = new Uint8Array(bytesPerRow);
|
|
249
|
+
let best = new Uint8Array(bytesPerRow);
|
|
250
|
+
const filterTypes = strategy === "none" ? [0] : ALL_FILTER_TYPES;
|
|
251
|
+
Array.from({ length: height }).forEach((_row, y) => {
|
|
252
|
+
current.set(raw.subarray(y * bytesPerRow, (y + 1) * bytesPerRow), bpp);
|
|
231
253
|
let bestType = 0;
|
|
232
254
|
let bestSum = Number.POSITIVE_INFINITY;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
filterRowInto(raw, rowStart, prevRowStart, bytesPerRow, bpp, filterType, candidate, 0);
|
|
236
|
-
const sum = sumOfAbsSigned(candidate);
|
|
255
|
+
for (const filterType of filterTypes) {
|
|
256
|
+
const sum = filterRowInto(current, previous, bpp, filterType, candidate);
|
|
237
257
|
if (sum < bestSum) {
|
|
238
258
|
bestSum = sum;
|
|
239
259
|
bestType = filterType;
|
|
240
|
-
best = candidate
|
|
260
|
+
[best, candidate] = [candidate, best];
|
|
241
261
|
}
|
|
242
262
|
}
|
|
243
|
-
out[
|
|
244
|
-
|
|
245
|
-
|
|
263
|
+
out[y * stride] = bestType;
|
|
264
|
+
out.set(best, y * stride + 1);
|
|
265
|
+
[previous, current] = [current, previous];
|
|
266
|
+
});
|
|
246
267
|
return out;
|
|
247
268
|
}
|
|
248
269
|
//#endregion
|
|
@@ -431,15 +452,19 @@ function channelsForColorType(colorType) {
|
|
|
431
452
|
function filterBpp(bitDepth, channels) {
|
|
432
453
|
return Math.max(1, Math.ceil(bitDepth * channels / 8));
|
|
433
454
|
}
|
|
434
|
-
function unpackRow(rowBytes,
|
|
435
|
-
|
|
436
|
-
|
|
455
|
+
function unpackRow(rowBytes, samples, bitDepth) {
|
|
456
|
+
if (bitDepth === 16) {
|
|
457
|
+
samples.forEach((_sample, i) => {
|
|
458
|
+
samples[i] = rowBytes[i * 2];
|
|
459
|
+
});
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
437
462
|
const mask = (1 << bitDepth) - 1;
|
|
438
|
-
|
|
463
|
+
samples.forEach((_sample, i) => {
|
|
439
464
|
const bitOffset = i * bitDepth;
|
|
440
465
|
const byteIndex = bitOffset >> 3;
|
|
441
466
|
const shift = 8 - bitDepth - (bitOffset & 7);
|
|
442
|
-
|
|
467
|
+
samples[i] = rowBytes[byteIndex] >> shift & mask;
|
|
443
468
|
});
|
|
444
469
|
}
|
|
445
470
|
function readTrnsGrayValue(trns) {
|
|
@@ -485,10 +510,12 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
485
510
|
const alpha = colorType === 4 || colorType === 6 || trns !== void 0 ? new Uint8Array(width * height).fill(255) : void 0;
|
|
486
511
|
const trnsGray = colorType === 0 && trns !== void 0 ? readTrnsGrayValue(trns) : void 0;
|
|
487
512
|
const trnsRgb = colorType === 2 && trns !== void 0 ? readTrnsRgbKey(trns) : void 0;
|
|
488
|
-
|
|
513
|
+
const samples = new Uint8Array(width * channels);
|
|
514
|
+
const columns = new Uint32Array(width);
|
|
515
|
+
Array.from({ length: height }).forEach((_row, y) => {
|
|
489
516
|
const rowStart = y * bytesPerRow;
|
|
490
|
-
|
|
491
|
-
|
|
517
|
+
unpackRow(unfiltered.subarray(rowStart, rowStart + bytesPerRow), samples, bitDepth);
|
|
518
|
+
columns.forEach((_column, x) => {
|
|
492
519
|
const pixelBase = x * channels;
|
|
493
520
|
const outBase = (y * width + x) * outChannels;
|
|
494
521
|
const alphaIndex = y * width + x;
|
|
@@ -524,8 +551,8 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
524
551
|
data[outBase + 2] = samples[pixelBase + 2];
|
|
525
552
|
if (alpha !== void 0) alpha[alphaIndex] = samples[pixelBase + 3];
|
|
526
553
|
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
554
|
+
});
|
|
555
|
+
});
|
|
529
556
|
return alpha === void 0 ? {
|
|
530
557
|
width,
|
|
531
558
|
height,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "byte-codec",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
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": {
|