byte-codec 1.5.5 → 1.5.7
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 +57 -37
- package/dist/index.js +57 -37
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -185,29 +185,54 @@ 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
|
-
|
|
188
|
+
out.subarray(outRowStart, outRowStart + bytesPerRow).forEach((_value, x) => {
|
|
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];
|
|
192
192
|
const c = x >= bpp && prevOutRowStart !== void 0 ? out[prevOutRowStart + x - bpp] : 0;
|
|
193
193
|
out[outRowStart + x] = raw + predictorValue(filterByte, a, b, c) & 255;
|
|
194
|
-
}
|
|
194
|
+
});
|
|
195
195
|
}
|
|
196
196
|
return out;
|
|
197
197
|
}
|
|
198
|
-
function
|
|
198
|
+
function filterRowInto(current, previous, bpp, filterType, target) {
|
|
199
199
|
let sum = 0;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
+
});
|
|
210
234
|
}
|
|
235
|
+
return sum;
|
|
211
236
|
}
|
|
212
237
|
const ALL_FILTER_TYPES = [
|
|
213
238
|
0,
|
|
@@ -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
|
|
@@ -348,12 +369,11 @@ function writeTruecolorPng(writer, image, options) {
|
|
|
348
369
|
const bytesPerRow = width * outChannels;
|
|
349
370
|
const pixelCount = width * height;
|
|
350
371
|
const interleaved = new Uint8Array(pixelCount * outChannels);
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
372
|
+
interleaved.forEach((_byte, index) => {
|
|
373
|
+
const pixel = Math.floor(index / outChannels);
|
|
374
|
+
const channel = index % outChannels;
|
|
375
|
+
interleaved[index] = alpha !== void 0 && channel === channels ? alpha[pixel] : data[pixel * channels + channel];
|
|
376
|
+
});
|
|
357
377
|
writeIhdr(writer, width, height, colorTypeFor(image));
|
|
358
378
|
writeChunk(writer, "IDAT", deflate(filterScanlines(interleaved, height, bytesPerRow, outChannels, options.filter ?? "adaptive")));
|
|
359
379
|
}
|
package/dist/index.js
CHANGED
|
@@ -184,29 +184,54 @@ 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
|
-
|
|
187
|
+
out.subarray(outRowStart, outRowStart + bytesPerRow).forEach((_value, x) => {
|
|
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];
|
|
191
191
|
const c = x >= bpp && prevOutRowStart !== void 0 ? out[prevOutRowStart + x - bpp] : 0;
|
|
192
192
|
out[outRowStart + x] = raw + predictorValue(filterByte, a, b, c) & 255;
|
|
193
|
-
}
|
|
193
|
+
});
|
|
194
194
|
}
|
|
195
195
|
return out;
|
|
196
196
|
}
|
|
197
|
-
function
|
|
197
|
+
function filterRowInto(current, previous, bpp, filterType, target) {
|
|
198
198
|
let sum = 0;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
+
});
|
|
209
233
|
}
|
|
234
|
+
return sum;
|
|
210
235
|
}
|
|
211
236
|
const ALL_FILTER_TYPES = [
|
|
212
237
|
0,
|
|
@@ -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
|
|
@@ -347,12 +368,11 @@ function writeTruecolorPng(writer, image, options) {
|
|
|
347
368
|
const bytesPerRow = width * outChannels;
|
|
348
369
|
const pixelCount = width * height;
|
|
349
370
|
const interleaved = new Uint8Array(pixelCount * outChannels);
|
|
350
|
-
|
|
351
|
-
const
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
371
|
+
interleaved.forEach((_byte, index) => {
|
|
372
|
+
const pixel = Math.floor(index / outChannels);
|
|
373
|
+
const channel = index % outChannels;
|
|
374
|
+
interleaved[index] = alpha !== void 0 && channel === channels ? alpha[pixel] : data[pixel * channels + channel];
|
|
375
|
+
});
|
|
356
376
|
writeIhdr(writer, width, height, colorTypeFor(image));
|
|
357
377
|
writeChunk(writer, "IDAT", deflate(filterScanlines(interleaved, height, bytesPerRow, outChannels, options.filter ?? "adaptive")));
|
|
358
378
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "byte-codec",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.7",
|
|
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": {
|