@woosh/meep-engine 2.126.75 → 2.127.1
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/build/bundle-worker-image-decoder.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/platform_compute_endianness.d.ts.map +1 -1
- package/src/core/binary/platform_compute_endianness.js +5 -1
- package/src/core/color/hunt/xyz_to_hpe.d.ts +7 -0
- package/src/core/color/hunt/xyz_to_hpe.d.ts.map +1 -0
- package/src/core/color/hunt/xyz_to_hpe.js +15 -0
- package/src/core/color/xyz/rgb_to_xyz.d.ts +2 -0
- package/src/core/color/xyz/rgb_to_xyz.d.ts.map +1 -1
- package/src/core/color/xyz/rgb_to_xyz.js +2 -0
- package/src/core/color/xyz/xyz_to_rgb.d.ts +2 -0
- package/src/core/color/xyz/xyz_to_rgb.d.ts.map +1 -1
- package/src/core/color/xyz/xyz_to_rgb.js +2 -0
- package/src/core/math/idct_1d.d.ts +14 -0
- package/src/core/math/idct_1d.d.ts.map +1 -0
- package/src/core/math/idct_1d.js +69 -0
- package/src/core/math/idct_2d.d.ts +11 -0
- package/src/core/math/idct_2d.d.ts.map +1 -0
- package/src/core/math/idct_2d.js +22 -0
- package/src/core/model/DebouncedObservedBoolean.d.ts +1 -1
- package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
- package/src/core/model/object/objectKeyByValue.d.ts.map +1 -1
- package/src/core/model/object/objectKeyByValue.js +4 -0
- package/src/engine/asset/Asset.d.ts.map +1 -1
- package/src/engine/asset/Asset.js +2 -5
- package/src/engine/asset/AssetTransformer.js +1 -1
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts +20 -1
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +56 -13
- package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts +42 -0
- package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/JpegFrame.js +45 -0
- package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts +42 -0
- package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.js +48 -0
- package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts +60 -0
- package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/JpegImage.js +624 -0
- package/src/engine/asset/loaders/image/jpeg/NOTES.md +3 -0
- package/src/engine/asset/loaders/image/jpeg/buildComponentData.d.ts +7 -0
- package/src/engine/asset/loaders/image/jpeg/buildComponentData.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/buildComponentData.js +59 -0
- package/src/engine/asset/loaders/image/jpeg/buildHuffmanTable.d.ts +8 -0
- package/src/engine/asset/loaders/image/jpeg/buildHuffmanTable.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/buildHuffmanTable.js +46 -0
- package/src/engine/asset/loaders/image/jpeg/decodeScan.d.ts +17 -0
- package/src/engine/asset/loaders/image/jpeg/decodeScan.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/decodeScan.js +351 -0
- package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts +23 -0
- package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.js +214 -0
- package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts +9 -0
- package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/idct8x8_float.js +32 -0
- package/src/engine/asset/loaders/image/jpeg/jpeg_decode.d.ts +13 -0
- package/src/engine/asset/loaders/image/jpeg/jpeg_decode.d.ts.map +1 -0
- package/src/engine/asset/loaders/image/jpeg/jpeg_decode.js +41 -0
- package/src/engine/asset/loaders/image/png/PNG.d.ts +18 -11
- package/src/engine/asset/loaders/image/png/PNG.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/png/PNG.js +17 -22
- package/src/engine/asset/loaders/image/png/PNGReader.d.ts +71 -10
- package/src/engine/asset/loaders/image/png/PNGReader.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/png/PNGReader.js +422 -101
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +2 -1
- package/src/engine/graphics/geometry/AttributeSpec.d.ts.map +1 -1
- package/src/engine/graphics/geometry/AttributeSpec.js +2 -1
- package/src/engine/graphics/render/frame_graph/RenderGraph.d.ts +50 -7
- package/src/engine/graphics/render/frame_graph/RenderGraph.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/RenderGraph.js +108 -8
- package/src/engine/graphics/render/frame_graph/RenderPassBuilder.d.ts +44 -0
- package/src/engine/graphics/render/frame_graph/RenderPassBuilder.d.ts.map +1 -0
- package/src/engine/graphics/render/frame_graph/{RenderGraphBuilder.js → RenderPassBuilder.js} +25 -6
- package/src/engine/graphics/render/frame_graph/RenderPassNode.d.ts +1 -0
- package/src/engine/graphics/render/frame_graph/RenderPassNode.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/RenderPassNode.js +1 -0
- package/src/engine/graphics/render/frame_graph/ResourceEntry.d.ts +8 -0
- package/src/engine/graphics/render/frame_graph/ResourceEntry.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/ResourceEntry.js +8 -0
- package/src/engine/graphics/texture/sampler/downloadSamplerAsPNG.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/downloadSamplerAsPNG.js +6 -1
- package/src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js +7 -2
- package/src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.js +12 -1
- package/src/engine/logging/elastic/ElasticSearchLogger.d.ts +1 -1
- package/src/engine/logging/elastic/ElasticSearchLogger.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/RenderGraphBuilder.d.ts +0 -33
- package/src/engine/graphics/render/frame_graph/RenderGraphBuilder.d.ts.map +0 -1
- package/src/engine/graphics/render/frame_graph/RenderPass.d.ts +0 -50
- package/src/engine/graphics/render/frame_graph/RenderPass.d.ts.map +0 -1
- package/src/engine/graphics/render/frame_graph/RenderPass.js +0 -74
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
import zlib from 'pako';
|
|
5
|
+
import { assert } from "../../../../../core/assert.js";
|
|
5
6
|
import { BinaryBuffer } from "../../../../../core/binary/BinaryBuffer.js";
|
|
6
7
|
import { EndianType } from "../../../../../core/binary/EndianType.js";
|
|
8
|
+
import { platform_compute_endianness } from "../../../../../core/binary/platform_compute_endianness.js";
|
|
7
9
|
import { isArrayEqualStrict } from "../../../../../core/collection/array/isArrayEqualStrict.js";
|
|
8
10
|
import { crc32 } from "./crc32.js";
|
|
9
11
|
|
|
@@ -77,6 +79,10 @@ export function PNGReader(bytes) {
|
|
|
77
79
|
*/
|
|
78
80
|
this.png = new PNG();
|
|
79
81
|
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @type {Uint8Array[]}
|
|
85
|
+
*/
|
|
80
86
|
this.dataChunks = [];
|
|
81
87
|
|
|
82
88
|
/**
|
|
@@ -109,11 +115,16 @@ export function PNGReader(bytes) {
|
|
|
109
115
|
* @return {Uint8Array}
|
|
110
116
|
*/
|
|
111
117
|
PNGReader.prototype.readBytes = function (length) {
|
|
112
|
-
const result = new Uint8Array(length);
|
|
113
118
|
|
|
114
|
-
this.buffer
|
|
119
|
+
const buffer = this.buffer;
|
|
120
|
+
|
|
121
|
+
// Reference instead of a copy
|
|
122
|
+
const result = new Uint8Array(buffer.data, buffer.position, length);
|
|
123
|
+
|
|
124
|
+
buffer.skip(length);
|
|
115
125
|
|
|
116
126
|
return result;
|
|
127
|
+
|
|
117
128
|
};
|
|
118
129
|
|
|
119
130
|
/**
|
|
@@ -265,6 +276,7 @@ PNGReader.prototype.decodeiTXt = function (chunk) {
|
|
|
265
276
|
const compression_flag = buffer.readUint8();
|
|
266
277
|
const compression_method = buffer.readUint8();
|
|
267
278
|
|
|
279
|
+
|
|
268
280
|
const language_tag = buffer.readASCIICharacters(Infinity, true);
|
|
269
281
|
const translated_keyword = buffer.readASCIICharacters(Infinity, true);
|
|
270
282
|
|
|
@@ -275,6 +287,11 @@ PNGReader.prototype.decodeiTXt = function (chunk) {
|
|
|
275
287
|
if (compression_flag === 0) {
|
|
276
288
|
text = buffer.readASCIICharacters(remaining_bytes);
|
|
277
289
|
} else if (compression_flag === 1) {
|
|
290
|
+
|
|
291
|
+
if(compression_method !== 0){
|
|
292
|
+
throw new Error('only compression_method 0 is supported');
|
|
293
|
+
}
|
|
294
|
+
|
|
278
295
|
const decoded = inflate(new Uint8Array(buffer.data, buffer.position, remaining_bytes));
|
|
279
296
|
|
|
280
297
|
buffer.fromArrayBuffer(decoded);
|
|
@@ -310,6 +327,10 @@ PNGReader.prototype.decodezTXt = function (chunk) {
|
|
|
310
327
|
if (compression_method === 0) {
|
|
311
328
|
// deflate method
|
|
312
329
|
|
|
330
|
+
if(compression_method !== 0){
|
|
331
|
+
throw new Error('only compression_method 0 is supported');
|
|
332
|
+
}
|
|
333
|
+
|
|
313
334
|
const encoded_chunk = new Uint8Array(chunk.buffer, buffer.position);
|
|
314
335
|
|
|
315
336
|
const decompressed_data = inflate(encoded_chunk);
|
|
@@ -351,6 +372,9 @@ PNGReader.prototype.decodeiEXt = function (chunk) {
|
|
|
351
372
|
|
|
352
373
|
const compression_flag = buff.readUint8();
|
|
353
374
|
const compression_method = buff.readUint8();
|
|
375
|
+
|
|
376
|
+
// TODO process compression properly
|
|
377
|
+
|
|
354
378
|
const language_tag = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
|
|
355
379
|
const translated_keyword = buff.readUTF8String();
|
|
356
380
|
|
|
@@ -393,6 +417,7 @@ PNGReader.prototype.decodeIHDR = function (chunk) {
|
|
|
393
417
|
/**
|
|
394
418
|
*
|
|
395
419
|
* http://www.w3.org/TR/PNG/#11PLTE
|
|
420
|
+
* @param {Uint8Array} chunk
|
|
396
421
|
*/
|
|
397
422
|
PNGReader.prototype.decodePLTE = function (chunk) {
|
|
398
423
|
this.png.setPalette(chunk);
|
|
@@ -411,7 +436,7 @@ PNGReader.prototype.decodeIDAT = function (chunk) {
|
|
|
411
436
|
* @param {Uint8Array} chunk
|
|
412
437
|
*/
|
|
413
438
|
PNGReader.prototype.decodeTRNS = function (chunk) {
|
|
414
|
-
this.png.
|
|
439
|
+
this.png.transparency_lookup = chunk;
|
|
415
440
|
};
|
|
416
441
|
|
|
417
442
|
/**
|
|
@@ -442,10 +467,11 @@ PNGReader.prototype.decodePixels = function () {
|
|
|
442
467
|
|
|
443
468
|
const decompressed_data = inflator.result;
|
|
444
469
|
|
|
470
|
+
// https://www.w3.org/TR/png-3/#8InterlaceMethods
|
|
445
471
|
if (png.getInterlaceMethod() === 0) {
|
|
446
|
-
this.interlaceNone(decompressed_data);
|
|
472
|
+
this.png.pixels = this.interlaceNone(decompressed_data);
|
|
447
473
|
} else {
|
|
448
|
-
this.interlaceAdam7(decompressed_data);
|
|
474
|
+
this.png.pixels = this.interlaceAdam7(decompressed_data);
|
|
449
475
|
}
|
|
450
476
|
};
|
|
451
477
|
|
|
@@ -468,9 +494,7 @@ PNGReader.prototype.interlaceNone = function (data) {
|
|
|
468
494
|
// color bytes per row
|
|
469
495
|
const color_bytes_per_row = Math.ceil(bytes_per_pixel * width);
|
|
470
496
|
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
const pixels = new Uint8Array(output_bytes_per_row * height);
|
|
497
|
+
const pixels = new Uint8Array(color_bytes_per_row * height);
|
|
474
498
|
|
|
475
499
|
let offset = 0;
|
|
476
500
|
|
|
@@ -482,95 +506,324 @@ PNGReader.prototype.interlaceNone = function (data) {
|
|
|
482
506
|
|
|
483
507
|
// scanline = slice.call(data, scanline_address, scanline_address + cpr);
|
|
484
508
|
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
} else if (depth === 2) {
|
|
499
|
-
for (let x = 0; x < output_bytes_per_row; x++) {
|
|
500
|
-
const q = x >>> 2;
|
|
501
|
-
const datum = data[q + scanline_address];
|
|
502
|
-
const shift = ((~x) & 0x3) << 1;
|
|
503
|
-
const out_value = (datum >>> shift) & 0x3;
|
|
504
|
-
pixels[offset + x] = out_value;
|
|
505
|
-
}
|
|
506
|
-
} else if (depth === 4) {
|
|
507
|
-
for (let x = 0; x < output_bytes_per_row; x++) {
|
|
508
|
-
const q = x >>> 1;
|
|
509
|
-
const datum = data[q + scanline_address];
|
|
510
|
-
const shift = ((~x) & 0x1) << 2;
|
|
511
|
-
const out_value = (datum >>> shift) & 0xF;
|
|
512
|
-
pixels[offset + x] = out_value;
|
|
513
|
-
}
|
|
514
|
-
} else if (depth === 8) {
|
|
515
|
-
for (let x = 0; x < output_bytes_per_row; x++) {
|
|
516
|
-
pixels[offset + x] = data[x + scanline_address];
|
|
517
|
-
}
|
|
518
|
-
} else {
|
|
519
|
-
throw new Error(`unsupported bit depth ${depth}`)
|
|
520
|
-
}
|
|
521
|
-
break;
|
|
522
|
-
case 1:
|
|
523
|
-
this.unFilterSub(data, scanline_address, pixels, bytes_per_pixel, offset, color_bytes_per_row);
|
|
524
|
-
break;
|
|
525
|
-
case 2:
|
|
526
|
-
this.unFilterUp(data, scanline_address, pixels, bytes_per_pixel, offset, color_bytes_per_row);
|
|
527
|
-
break;
|
|
528
|
-
case 3:
|
|
529
|
-
this.unFilterAverage(data, scanline_address, pixels, bytes_per_pixel, offset, color_bytes_per_row);
|
|
530
|
-
break;
|
|
531
|
-
case 4:
|
|
532
|
-
this.unFilterPaeth(data, scanline_address, pixels, bytes_per_pixel, offset, color_bytes_per_row);
|
|
533
|
-
break;
|
|
534
|
-
default:
|
|
535
|
-
throw new Error(`unknown filtered scanline type '${header}'`);
|
|
536
|
-
}
|
|
509
|
+
const filter_type = readUInt8(data, i);
|
|
510
|
+
|
|
511
|
+
this.unFilter(
|
|
512
|
+
filter_type,
|
|
513
|
+
data,
|
|
514
|
+
scanline_address,
|
|
515
|
+
pixels,
|
|
516
|
+
depth,
|
|
517
|
+
offset,
|
|
518
|
+
offset - color_bytes_per_row,
|
|
519
|
+
color_bytes_per_row
|
|
520
|
+
);
|
|
537
521
|
|
|
538
|
-
offset +=
|
|
522
|
+
offset += color_bytes_per_row;
|
|
539
523
|
|
|
540
524
|
}
|
|
541
525
|
|
|
542
|
-
|
|
526
|
+
return pixels;
|
|
543
527
|
|
|
544
528
|
};
|
|
545
529
|
|
|
530
|
+
|
|
546
531
|
/**
|
|
547
532
|
* De-interlace image according to Adam 7 scheme
|
|
548
533
|
* @param {Uint8Array} data
|
|
549
534
|
*/
|
|
550
535
|
PNGReader.prototype.interlaceAdam7 = function (data) {
|
|
551
|
-
|
|
536
|
+
|
|
537
|
+
const png = this.png;
|
|
538
|
+
|
|
539
|
+
const depth = png.bitDepth;
|
|
540
|
+
const bytes_per_pixel = png.colors * depth / 8;
|
|
541
|
+
|
|
542
|
+
const pixels = new Uint8Array(bytes_per_pixel * png.width * png.height);
|
|
543
|
+
|
|
544
|
+
// Adam7 interlacing pattern
|
|
545
|
+
const passes = [
|
|
546
|
+
{ x: 0, y: 0, xStep: 8, yStep: 8 }, // Pass 1
|
|
547
|
+
{ x: 4, y: 0, xStep: 8, yStep: 8 }, // Pass 2
|
|
548
|
+
{ x: 0, y: 4, xStep: 4, yStep: 8 }, // Pass 3
|
|
549
|
+
{ x: 2, y: 0, xStep: 4, yStep: 4 }, // Pass 4
|
|
550
|
+
{ x: 0, y: 2, xStep: 2, yStep: 4 }, // Pass 5
|
|
551
|
+
{ x: 1, y: 0, xStep: 2, yStep: 2 }, // Pass 6
|
|
552
|
+
{ x: 0, y: 1, xStep: 1, yStep: 2 }, // Pass 7
|
|
553
|
+
];
|
|
554
|
+
|
|
555
|
+
const width = png.width;
|
|
556
|
+
const height = png.height;
|
|
557
|
+
|
|
558
|
+
let offset = 0;
|
|
559
|
+
|
|
560
|
+
// Create a new line for the unfiltered data
|
|
561
|
+
const line_bytes_buffer = new Uint8Array(width * bytes_per_pixel);
|
|
562
|
+
|
|
563
|
+
// Process each pass
|
|
564
|
+
for (let passIndex = 0; passIndex < 7; passIndex++) {
|
|
565
|
+
const pass = passes[passIndex];
|
|
566
|
+
|
|
567
|
+
// Calculate pass dimensions
|
|
568
|
+
const pass_width = Math.ceil((width - pass.x) / pass.xStep);
|
|
569
|
+
const pass_height = Math.ceil((height - pass.y) / pass.yStep);
|
|
570
|
+
|
|
571
|
+
if (pass_width <= 0 || pass_height <= 0) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const passLineBytes = pass_width * bytes_per_pixel;
|
|
576
|
+
|
|
577
|
+
// Indicate to unfiltering that this is the first line (no previous line)
|
|
578
|
+
let previous_line_offset = -1;
|
|
579
|
+
|
|
580
|
+
// Process each scanline in this pass
|
|
581
|
+
for (let y = 0; y < pass_height; y++) {
|
|
582
|
+
|
|
583
|
+
// First byte is the filter type
|
|
584
|
+
const filter_type = data[offset++];
|
|
585
|
+
|
|
586
|
+
// we use alternating line offsets to save on memory allocations
|
|
587
|
+
const line_offset = (y % 2) * passLineBytes;
|
|
588
|
+
|
|
589
|
+
// Apply the appropriate unfilter
|
|
590
|
+
this.unFilter(
|
|
591
|
+
filter_type,
|
|
592
|
+
data,
|
|
593
|
+
offset,
|
|
594
|
+
line_bytes_buffer,
|
|
595
|
+
bytes_per_pixel,
|
|
596
|
+
line_offset,
|
|
597
|
+
previous_line_offset,
|
|
598
|
+
passLineBytes,
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
offset += passLineBytes;
|
|
602
|
+
previous_line_offset = line_offset;
|
|
603
|
+
|
|
604
|
+
for (let x = 0; x < pass_width; x++) {
|
|
605
|
+
|
|
606
|
+
const outputX = pass.x + x * pass.xStep;
|
|
607
|
+
const outputY = pass.y + y * pass.yStep;
|
|
608
|
+
|
|
609
|
+
if (outputX >= width || outputY >= height) {
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
for (let i = 0; i < bytes_per_pixel; i++) {
|
|
614
|
+
const out_offset = (outputY * width + outputX) * bytes_per_pixel + i;
|
|
615
|
+
|
|
616
|
+
pixels[out_offset] = line_bytes_buffer[line_offset + x * bytes_per_pixel + i];
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function swap16(val) {
|
|
623
|
+
return ((val & 0xff) << 8) | ((val >> 8) & 0xff);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (depth === 16) {
|
|
627
|
+
const uint16Data = new Uint16Array(pixels.buffer);
|
|
628
|
+
|
|
629
|
+
const osIsLittleEndian = platform_compute_endianness() === EndianType.LittleEndian;
|
|
630
|
+
|
|
631
|
+
if (osIsLittleEndian) {
|
|
632
|
+
for (let k = 0; k < uint16Data.length; k++) {
|
|
633
|
+
// PNG is always big endian. Swap the bytes.
|
|
634
|
+
uint16Data[k] = swap16(uint16Data[k]);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return uint16Data;
|
|
639
|
+
} else {
|
|
640
|
+
return pixels;
|
|
641
|
+
}
|
|
642
|
+
|
|
552
643
|
};
|
|
553
644
|
|
|
554
645
|
// Unfiltering
|
|
555
646
|
|
|
647
|
+
/**
|
|
648
|
+
*
|
|
649
|
+
* @param {number} filter_type
|
|
650
|
+
* @param {Uint8Array} data
|
|
651
|
+
* @param {number} scanline_address
|
|
652
|
+
* @param {Uint8Array} output
|
|
653
|
+
* @param {number} bytes_per_pixel
|
|
654
|
+
* @param {number} output_offset
|
|
655
|
+
* @param {number} output_offset_previous where does result of previous scanline begin in the output? Needed for various filters such as `Up`
|
|
656
|
+
* @param {number} length
|
|
657
|
+
*/
|
|
658
|
+
PNGReader.prototype.unFilter = function (
|
|
659
|
+
filter_type,
|
|
660
|
+
data,
|
|
661
|
+
scanline_address,
|
|
662
|
+
output,
|
|
663
|
+
bytes_per_pixel,
|
|
664
|
+
output_offset,
|
|
665
|
+
output_offset_previous,
|
|
666
|
+
length
|
|
667
|
+
) {
|
|
668
|
+
assert.isInteger(filter_type, 'filter_type');
|
|
669
|
+
assert.isNonNegativeInteger(scanline_address, 'scanline_address');
|
|
670
|
+
assert.isNonNegativeInteger(bytes_per_pixel, 'bytes_per_pixel');
|
|
671
|
+
assert.isNonNegativeInteger(output_offset, 'output_offset');
|
|
672
|
+
assert.isNonNegativeInteger(length, 'length');
|
|
673
|
+
|
|
674
|
+
switch (filter_type) {
|
|
675
|
+
case 0:
|
|
676
|
+
this.unFilterNone(
|
|
677
|
+
data,
|
|
678
|
+
scanline_address,
|
|
679
|
+
output,
|
|
680
|
+
bytes_per_pixel,
|
|
681
|
+
output_offset,
|
|
682
|
+
output_offset_previous,
|
|
683
|
+
length
|
|
684
|
+
);
|
|
685
|
+
break;
|
|
686
|
+
case 1:
|
|
687
|
+
this.unFilterSub(
|
|
688
|
+
data,
|
|
689
|
+
scanline_address,
|
|
690
|
+
output,
|
|
691
|
+
bytes_per_pixel,
|
|
692
|
+
output_offset,
|
|
693
|
+
output_offset_previous,
|
|
694
|
+
length
|
|
695
|
+
);
|
|
696
|
+
break;
|
|
697
|
+
case 2:
|
|
698
|
+
this.unFilterUp(
|
|
699
|
+
data,
|
|
700
|
+
scanline_address,
|
|
701
|
+
output,
|
|
702
|
+
bytes_per_pixel,
|
|
703
|
+
output_offset,
|
|
704
|
+
output_offset_previous,
|
|
705
|
+
length
|
|
706
|
+
);
|
|
707
|
+
break;
|
|
708
|
+
case 3:
|
|
709
|
+
this.unFilterAverage(
|
|
710
|
+
data,
|
|
711
|
+
scanline_address,
|
|
712
|
+
output,
|
|
713
|
+
bytes_per_pixel,
|
|
714
|
+
output_offset,
|
|
715
|
+
output_offset_previous,
|
|
716
|
+
length
|
|
717
|
+
);
|
|
718
|
+
break;
|
|
719
|
+
case 4:
|
|
720
|
+
this.unFilterPaeth(
|
|
721
|
+
data,
|
|
722
|
+
scanline_address,
|
|
723
|
+
output,
|
|
724
|
+
bytes_per_pixel,
|
|
725
|
+
output_offset,
|
|
726
|
+
output_offset_previous,
|
|
727
|
+
length
|
|
728
|
+
);
|
|
729
|
+
break;
|
|
730
|
+
default:
|
|
731
|
+
throw new Error(`unknown filtered scanline type '${filter_type}'`);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
*
|
|
737
|
+
* @param {Uint8Array} data
|
|
738
|
+
* @param {number} scanline_address
|
|
739
|
+
* @param {Uint8Array} output
|
|
740
|
+
* @param {number} bytes_per_pixel
|
|
741
|
+
* @param {number} output_offset
|
|
742
|
+
* @param {number} output_offset_previous
|
|
743
|
+
* @param {number} length
|
|
744
|
+
*/
|
|
745
|
+
PNGReader.prototype.unFilterNone = function (
|
|
746
|
+
data,
|
|
747
|
+
scanline_address,
|
|
748
|
+
output,
|
|
749
|
+
bytes_per_pixel,
|
|
750
|
+
output_offset,
|
|
751
|
+
output_offset_previous,
|
|
752
|
+
length
|
|
753
|
+
) {
|
|
754
|
+
|
|
755
|
+
const png = this.png;
|
|
756
|
+
const depth = png.bitDepth;
|
|
757
|
+
|
|
758
|
+
if (depth === 1) {
|
|
759
|
+
for (let x = 0; x < length; x++) {
|
|
760
|
+
const q = x >>> 4;
|
|
761
|
+
const datum = data[q + scanline_address];
|
|
762
|
+
const shift = ((x) & 0x7);
|
|
763
|
+
const out_value = (datum >>> shift) & 0x1;
|
|
764
|
+
output[output_offset + x] = out_value;
|
|
765
|
+
}
|
|
766
|
+
} else if (depth === 2) {
|
|
767
|
+
for (let x = 0; x < length; x++) {
|
|
768
|
+
const q = x >>> 2;
|
|
769
|
+
const datum = data[q + scanline_address];
|
|
770
|
+
const shift = ((~x) & 0x3) << 1;
|
|
771
|
+
const out_value = (datum >>> shift) & 0x3;
|
|
772
|
+
output[output_offset + x] = out_value;
|
|
773
|
+
}
|
|
774
|
+
} else if (depth === 4) {
|
|
775
|
+
for (let x = 0; x < length; x++) {
|
|
776
|
+
const q = x >>> 1;
|
|
777
|
+
const datum = data[q + scanline_address];
|
|
778
|
+
const shift = ((~x) & 0x1) << 2;
|
|
779
|
+
const out_value = (datum >>> shift) & 0xF;
|
|
780
|
+
output[output_offset + x] = out_value;
|
|
781
|
+
}
|
|
782
|
+
} else if (depth === 8) {
|
|
783
|
+
for (let x = 0; x < length; x++) {
|
|
784
|
+
// straight copy
|
|
785
|
+
output[output_offset + x] = data[x + scanline_address];
|
|
786
|
+
}
|
|
787
|
+
} else {
|
|
788
|
+
throw new Error(`unsupported bit depth ${depth}`)
|
|
789
|
+
}
|
|
790
|
+
};
|
|
556
791
|
|
|
557
792
|
/**
|
|
558
793
|
* The Sub() filter transmits the difference between each byte and the value
|
|
559
794
|
* of the corresponding byte of the prior pixel.
|
|
560
795
|
* Sub(x) = Raw(x) + Raw(x - bpp)
|
|
796
|
+
*
|
|
797
|
+
* @param {Uint8Array} scanline raw data
|
|
798
|
+
* @param {number} scanline_offset
|
|
799
|
+
* @param {Uint8Array} pixels processed output
|
|
800
|
+
* @param {number} bpp bytes-per-pixel
|
|
801
|
+
* @param {number} offset
|
|
802
|
+
* @param {number} output_offset_previous
|
|
803
|
+
* @param {number} length
|
|
561
804
|
*/
|
|
562
|
-
PNGReader.prototype.unFilterSub = function (
|
|
805
|
+
PNGReader.prototype.unFilterSub = function (
|
|
806
|
+
scanline,
|
|
807
|
+
scanline_offset,
|
|
808
|
+
pixels,
|
|
809
|
+
bpp,
|
|
810
|
+
offset,
|
|
811
|
+
output_offset_previous,
|
|
812
|
+
length
|
|
813
|
+
) {
|
|
814
|
+
|
|
563
815
|
let i = 0;
|
|
564
816
|
|
|
565
817
|
for (; i < bpp; i++) {
|
|
566
|
-
pixels[
|
|
818
|
+
pixels[offset + i] = scanline[i + scanline_offset];
|
|
567
819
|
}
|
|
568
820
|
|
|
569
821
|
for (; i < length; i++) {
|
|
570
822
|
// Raw(x) + Raw(x - bpp)
|
|
571
|
-
const of_i =
|
|
823
|
+
const of_i = offset + i;
|
|
572
824
|
pixels[of_i] = (scanline[i + scanline_offset] + pixels[of_i - bpp]) & 0xFF;
|
|
573
825
|
}
|
|
826
|
+
|
|
574
827
|
};
|
|
575
828
|
|
|
576
829
|
/**
|
|
@@ -578,18 +831,46 @@ PNGReader.prototype.unFilterSub = function (scanline, scanline_offset, pixels, b
|
|
|
578
831
|
* immediately above the current pixel, rather than just to its left, is used
|
|
579
832
|
* as the predictor.
|
|
580
833
|
* Up(x) = Raw(x) + Prior(x)
|
|
834
|
+
*
|
|
835
|
+
* @param {Uint8Array} scanline raw data
|
|
836
|
+
* @param {number} scanline_offset
|
|
837
|
+
* @param {Uint8Array} pixels processed output
|
|
838
|
+
* @param {number} bpp bytes-per-pixel
|
|
839
|
+
* @param {number} offset
|
|
840
|
+
* @param {number} output_offset_previous
|
|
841
|
+
* @param {number} length
|
|
581
842
|
*/
|
|
582
|
-
PNGReader.prototype.unFilterUp = function (
|
|
843
|
+
PNGReader.prototype.unFilterUp = function (
|
|
844
|
+
scanline,
|
|
845
|
+
scanline_offset,
|
|
846
|
+
pixels,
|
|
847
|
+
bpp,
|
|
848
|
+
offset,
|
|
849
|
+
output_offset_previous,
|
|
850
|
+
length
|
|
851
|
+
) {
|
|
583
852
|
let i = 0, byte, prev;
|
|
853
|
+
|
|
584
854
|
// Prior(x) is 0 for all x on the first scanline
|
|
585
|
-
if (
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
855
|
+
if (output_offset_previous < 0) {
|
|
856
|
+
|
|
857
|
+
for (; i < length; i++) {
|
|
858
|
+
pixels[offset + i] = scanline[i + scanline_offset];
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
} else {
|
|
862
|
+
|
|
863
|
+
for (; i < length; i++) {
|
|
864
|
+
|
|
865
|
+
// Raw(x)
|
|
866
|
+
byte = scanline[i + scanline_offset];
|
|
867
|
+
|
|
868
|
+
// Prior(x)
|
|
869
|
+
prev = pixels[output_offset_previous + i];
|
|
870
|
+
|
|
871
|
+
pixels[offset + i] = (byte + prev) & 0xFF;
|
|
872
|
+
}
|
|
873
|
+
|
|
593
874
|
}
|
|
594
875
|
};
|
|
595
876
|
|
|
@@ -597,45 +878,65 @@ PNGReader.prototype.unFilterUp = function (scanline, scanline_offset, pixels, bp
|
|
|
597
878
|
* The Average() filter uses the average of the two neighboring pixels (left
|
|
598
879
|
* and above) to predict the value of a pixel.
|
|
599
880
|
* Average(x) = Raw(x) + floor((Raw(x-bpp)+Prior(x))/2)
|
|
881
|
+
*
|
|
882
|
+
* @param {Uint8Array} scanline raw data
|
|
883
|
+
* @param {number} scanline_offset
|
|
884
|
+
* @param {Uint8Array} pixels processed output
|
|
885
|
+
* @param {number} bpp bytes-per-pixel
|
|
886
|
+
* @param {number} offset
|
|
887
|
+
* @param {number} output_offset_previous
|
|
888
|
+
* @param {number} length
|
|
600
889
|
*/
|
|
601
|
-
PNGReader.prototype.unFilterAverage = function (
|
|
890
|
+
PNGReader.prototype.unFilterAverage = function (
|
|
891
|
+
scanline,
|
|
892
|
+
scanline_offset,
|
|
893
|
+
pixels,
|
|
894
|
+
bpp,
|
|
895
|
+
offset,
|
|
896
|
+
output_offset_previous,
|
|
897
|
+
length
|
|
898
|
+
) {
|
|
602
899
|
let i = 0, byte, prev, prior;
|
|
603
|
-
|
|
900
|
+
|
|
901
|
+
if (output_offset_previous < 0) {
|
|
902
|
+
|
|
604
903
|
// Prior(x) == 0 && Raw(x - bpp) == 0
|
|
605
904
|
for (; i < bpp; i++) {
|
|
606
|
-
pixels[
|
|
905
|
+
pixels[offset + i] = scanline[i + scanline_offset];
|
|
607
906
|
}
|
|
907
|
+
|
|
608
908
|
// Prior(x) == 0 && Raw(x - bpp) != 0 (right shift, prevent doubles)
|
|
609
909
|
for (; i < length; i++) {
|
|
610
|
-
const of_i =
|
|
910
|
+
const of_i = offset + i;
|
|
611
911
|
pixels[of_i] = (scanline[i + scanline_offset] + (pixels[of_i - bpp] >> 1)) & 0xFF;
|
|
612
912
|
}
|
|
913
|
+
|
|
613
914
|
} else {
|
|
915
|
+
|
|
614
916
|
// Prior(x) != 0 && Raw(x - bpp) == 0
|
|
615
917
|
for (; i < bpp; i++) {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
pixels[of_i] = (scanline[i + scanline_offset] + (pixels[of_i - length] >> 1)) & 0xFF;
|
|
918
|
+
pixels[offset + i] = (scanline[i + scanline_offset] + (pixels[output_offset_previous + i] >> 1)) & 0xFF;
|
|
619
919
|
}
|
|
920
|
+
|
|
620
921
|
// Prior(x) != 0 && Raw(x - bpp) != 0
|
|
621
922
|
for (; i < length; i++) {
|
|
622
923
|
byte = scanline[i + scanline_offset];
|
|
623
924
|
|
|
624
|
-
|
|
925
|
+
prev = pixels[offset + i - bpp];
|
|
926
|
+
prior = pixels[output_offset_previous + i];
|
|
625
927
|
|
|
626
|
-
|
|
627
|
-
prior = pixels[of_i - length];
|
|
628
|
-
|
|
629
|
-
pixels[of_i] = (byte + (prev + prior >> 1)) & 0xFF;
|
|
928
|
+
pixels[offset + i] = (byte + (prev + prior >> 1)) & 0xFF;
|
|
630
929
|
}
|
|
930
|
+
|
|
631
931
|
}
|
|
632
932
|
};
|
|
633
933
|
|
|
634
934
|
/**
|
|
635
935
|
* The Paeth() filter computes a simple linear function of the three
|
|
636
936
|
* neighboring pixels (left, above, upper left), then chooses as predictor
|
|
637
|
-
* the neighboring pixel closest to the computed value.
|
|
638
|
-
* to Alan W. Paeth.
|
|
937
|
+
* the neighboring pixel closest to the computed value.
|
|
938
|
+
* This technique is due to Alan W. Paeth.
|
|
939
|
+
*
|
|
639
940
|
* Paeth(x) = Raw(x) +
|
|
640
941
|
* PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
|
|
641
942
|
* function PaethPredictor (a, b, c)
|
|
@@ -651,35 +952,54 @@ PNGReader.prototype.unFilterAverage = function (scanline, scanline_offset, pixel
|
|
|
651
952
|
* else if pb <= pc then return b
|
|
652
953
|
* else return c
|
|
653
954
|
* end
|
|
955
|
+
*
|
|
956
|
+
* @param {Uint8Array} scanline raw data
|
|
957
|
+
* @param {number} scanline_offset
|
|
958
|
+
* @param {Uint8Array} pixels processed output
|
|
959
|
+
* @param {number} bpp bytes-per-pixel
|
|
960
|
+
* @param {number} offset
|
|
961
|
+
* @param {number} output_offset_previous
|
|
962
|
+
* @param {number} length
|
|
654
963
|
*/
|
|
655
|
-
PNGReader.prototype.unFilterPaeth = function (
|
|
964
|
+
PNGReader.prototype.unFilterPaeth = function (
|
|
965
|
+
scanline,
|
|
966
|
+
scanline_offset,
|
|
967
|
+
pixels,
|
|
968
|
+
bpp,
|
|
969
|
+
offset,
|
|
970
|
+
output_offset_previous,
|
|
971
|
+
length
|
|
972
|
+
) {
|
|
656
973
|
let i = 0, raw, a, b, c, p, pa, pb, pc, pr;
|
|
657
|
-
|
|
974
|
+
|
|
975
|
+
if (output_offset_previous < 0) {
|
|
976
|
+
|
|
658
977
|
// Prior(x) == 0 && Raw(x - bpp) == 0
|
|
659
978
|
for (; i < bpp; i++) {
|
|
660
|
-
pixels[
|
|
979
|
+
pixels[offset + i] = scanline[i + scanline_offset];
|
|
661
980
|
}
|
|
981
|
+
|
|
662
982
|
// Prior(x) == 0 && Raw(x - bpp) != 0
|
|
663
983
|
// paethPredictor(x, 0, 0) is always x
|
|
664
984
|
for (; i < length; i++) {
|
|
665
|
-
pixels[
|
|
985
|
+
pixels[offset + i] = (scanline[i + scanline_offset] + pixels[offset + i - bpp]) & 0xFF;
|
|
666
986
|
}
|
|
987
|
+
|
|
667
988
|
} else {
|
|
668
|
-
|
|
989
|
+
|
|
669
990
|
// Prior(x) != 0 && Raw(x - bpp) == 0
|
|
670
991
|
// paethPredictor(x, 0, 0) is always x
|
|
671
992
|
for (; i < bpp; i++) {
|
|
672
|
-
pixels[
|
|
993
|
+
pixels[offset + i] = (scanline[i + scanline_offset] + pixels[output_offset_previous + i]) & 0xFF;
|
|
673
994
|
}
|
|
995
|
+
|
|
674
996
|
// Prior(x) != 0 && Raw(x - bpp) != 0
|
|
675
997
|
for (; i < length; i++) {
|
|
676
998
|
raw = scanline[i + scanline_offset];
|
|
677
999
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
b = pixels[offset_0 - length];
|
|
682
|
-
a = pixels[offset_0 - bpp];
|
|
1000
|
+
c = pixels[output_offset_previous + i - bpp];
|
|
1001
|
+
b = pixels[output_offset_previous + i];
|
|
1002
|
+
a = pixels[offset + i - bpp];
|
|
683
1003
|
|
|
684
1004
|
p = a + b - c;
|
|
685
1005
|
|
|
@@ -695,8 +1015,9 @@ PNGReader.prototype.unFilterPaeth = function (scanline, scanline_offset, pixels,
|
|
|
695
1015
|
pr = c;
|
|
696
1016
|
}
|
|
697
1017
|
|
|
698
|
-
pixels[
|
|
1018
|
+
pixels[offset + i] = (raw + pr) & 0xFF;
|
|
699
1019
|
}
|
|
1020
|
+
|
|
700
1021
|
}
|
|
701
1022
|
};
|
|
702
1023
|
|