@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.
Files changed (92) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/platform_compute_endianness.d.ts.map +1 -1
  4. package/src/core/binary/platform_compute_endianness.js +5 -1
  5. package/src/core/color/hunt/xyz_to_hpe.d.ts +7 -0
  6. package/src/core/color/hunt/xyz_to_hpe.d.ts.map +1 -0
  7. package/src/core/color/hunt/xyz_to_hpe.js +15 -0
  8. package/src/core/color/xyz/rgb_to_xyz.d.ts +2 -0
  9. package/src/core/color/xyz/rgb_to_xyz.d.ts.map +1 -1
  10. package/src/core/color/xyz/rgb_to_xyz.js +2 -0
  11. package/src/core/color/xyz/xyz_to_rgb.d.ts +2 -0
  12. package/src/core/color/xyz/xyz_to_rgb.d.ts.map +1 -1
  13. package/src/core/color/xyz/xyz_to_rgb.js +2 -0
  14. package/src/core/math/idct_1d.d.ts +14 -0
  15. package/src/core/math/idct_1d.d.ts.map +1 -0
  16. package/src/core/math/idct_1d.js +69 -0
  17. package/src/core/math/idct_2d.d.ts +11 -0
  18. package/src/core/math/idct_2d.d.ts.map +1 -0
  19. package/src/core/math/idct_2d.js +22 -0
  20. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -1
  21. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  22. package/src/core/model/object/objectKeyByValue.d.ts.map +1 -1
  23. package/src/core/model/object/objectKeyByValue.js +4 -0
  24. package/src/engine/asset/Asset.d.ts.map +1 -1
  25. package/src/engine/asset/Asset.js +2 -5
  26. package/src/engine/asset/AssetTransformer.js +1 -1
  27. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts +20 -1
  28. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts.map +1 -1
  29. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +56 -13
  30. package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts +42 -0
  31. package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts.map +1 -0
  32. package/src/engine/asset/loaders/image/jpeg/JpegFrame.js +45 -0
  33. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts +42 -0
  34. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts.map +1 -0
  35. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.js +48 -0
  36. package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts +60 -0
  37. package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts.map +1 -0
  38. package/src/engine/asset/loaders/image/jpeg/JpegImage.js +624 -0
  39. package/src/engine/asset/loaders/image/jpeg/NOTES.md +3 -0
  40. package/src/engine/asset/loaders/image/jpeg/buildComponentData.d.ts +7 -0
  41. package/src/engine/asset/loaders/image/jpeg/buildComponentData.d.ts.map +1 -0
  42. package/src/engine/asset/loaders/image/jpeg/buildComponentData.js +59 -0
  43. package/src/engine/asset/loaders/image/jpeg/buildHuffmanTable.d.ts +8 -0
  44. package/src/engine/asset/loaders/image/jpeg/buildHuffmanTable.d.ts.map +1 -0
  45. package/src/engine/asset/loaders/image/jpeg/buildHuffmanTable.js +46 -0
  46. package/src/engine/asset/loaders/image/jpeg/decodeScan.d.ts +17 -0
  47. package/src/engine/asset/loaders/image/jpeg/decodeScan.d.ts.map +1 -0
  48. package/src/engine/asset/loaders/image/jpeg/decodeScan.js +351 -0
  49. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts +23 -0
  50. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts.map +1 -0
  51. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.js +214 -0
  52. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts +9 -0
  53. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts.map +1 -0
  54. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.js +32 -0
  55. package/src/engine/asset/loaders/image/jpeg/jpeg_decode.d.ts +13 -0
  56. package/src/engine/asset/loaders/image/jpeg/jpeg_decode.d.ts.map +1 -0
  57. package/src/engine/asset/loaders/image/jpeg/jpeg_decode.js +41 -0
  58. package/src/engine/asset/loaders/image/png/PNG.d.ts +18 -11
  59. package/src/engine/asset/loaders/image/png/PNG.d.ts.map +1 -1
  60. package/src/engine/asset/loaders/image/png/PNG.js +17 -22
  61. package/src/engine/asset/loaders/image/png/PNGReader.d.ts +71 -10
  62. package/src/engine/asset/loaders/image/png/PNGReader.d.ts.map +1 -1
  63. package/src/engine/asset/loaders/image/png/PNGReader.js +422 -101
  64. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  65. package/src/engine/ecs/EntityComponentDataset.js +2 -1
  66. package/src/engine/graphics/geometry/AttributeSpec.d.ts.map +1 -1
  67. package/src/engine/graphics/geometry/AttributeSpec.js +2 -1
  68. package/src/engine/graphics/render/frame_graph/RenderGraph.d.ts +50 -7
  69. package/src/engine/graphics/render/frame_graph/RenderGraph.d.ts.map +1 -1
  70. package/src/engine/graphics/render/frame_graph/RenderGraph.js +108 -8
  71. package/src/engine/graphics/render/frame_graph/RenderPassBuilder.d.ts +44 -0
  72. package/src/engine/graphics/render/frame_graph/RenderPassBuilder.d.ts.map +1 -0
  73. package/src/engine/graphics/render/frame_graph/{RenderGraphBuilder.js → RenderPassBuilder.js} +25 -6
  74. package/src/engine/graphics/render/frame_graph/RenderPassNode.d.ts +1 -0
  75. package/src/engine/graphics/render/frame_graph/RenderPassNode.d.ts.map +1 -1
  76. package/src/engine/graphics/render/frame_graph/RenderPassNode.js +1 -0
  77. package/src/engine/graphics/render/frame_graph/ResourceEntry.d.ts +8 -0
  78. package/src/engine/graphics/render/frame_graph/ResourceEntry.d.ts.map +1 -1
  79. package/src/engine/graphics/render/frame_graph/ResourceEntry.js +8 -0
  80. package/src/engine/graphics/texture/sampler/downloadSamplerAsPNG.d.ts.map +1 -1
  81. package/src/engine/graphics/texture/sampler/downloadSamplerAsPNG.js +6 -1
  82. package/src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.d.ts.map +1 -1
  83. package/src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js +7 -2
  84. package/src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.d.ts.map +1 -1
  85. package/src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.js +12 -1
  86. package/src/engine/logging/elastic/ElasticSearchLogger.d.ts +1 -1
  87. package/src/engine/logging/elastic/ElasticSearchLogger.d.ts.map +1 -1
  88. package/src/engine/graphics/render/frame_graph/RenderGraphBuilder.d.ts +0 -33
  89. package/src/engine/graphics/render/frame_graph/RenderGraphBuilder.d.ts.map +0 -1
  90. package/src/engine/graphics/render/frame_graph/RenderPass.d.ts +0 -50
  91. package/src/engine/graphics/render/frame_graph/RenderPass.d.ts.map +0 -1
  92. 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.readBytes(result, 0, length);
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.setTRNS(chunk);
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 output_bytes_per_row = Math.ceil(bytes_per_pixel) * width;
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 header = readUInt8(data, i);
486
-
487
- switch (header) {
488
- case 0:
489
- // NONE
490
- if (depth === 1) {
491
- for (let x = 0; x < output_bytes_per_row; x++) {
492
- const q = x >>> 4;
493
- const datum = data[q + scanline_address];
494
- const shift = ((x) & 0x7);
495
- const out_value = (datum >>> shift) & 0x1;
496
- pixels[offset + x] = out_value;
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 += output_bytes_per_row;
522
+ offset += color_bytes_per_row;
539
523
 
540
524
  }
541
525
 
542
- png.pixels = pixels;
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
- throw new Error("Adam7 interlacing is not implemented yet");
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 (scanline, scanline_offset, pixels, bpp, of, length) {
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[of + i] = scanline[i + scanline_offset];
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 = 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 (scanline, scanline_offset, pixels, bpp, of, length) {
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 ((of - length) < 0) for (; i < length; i++) {
586
- pixels[of + i] = scanline[i + scanline_offset];
587
- } else for (; i < length; i++) {
588
- // Raw(x)
589
- byte = scanline[i + scanline_offset];
590
- // Prior(x)
591
- prev = pixels[of + i - length];
592
- pixels[of + i] = (byte + prev) & 0xFF;
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 (scanline, scanline_offset, pixels, bpp, of, length) {
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
- if ((of - length) < 0) {
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[of + i] = scanline[i + scanline_offset];
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 = 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
- const of_i = of + i;
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
- const of_i = of + i;
925
+ prev = pixels[offset + i - bpp];
926
+ prior = pixels[output_offset_previous + i];
625
927
 
626
- prev = pixels[of_i - bpp];
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. This technique is due
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 (scanline, scanline_offset, pixels, bpp, of, length) {
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
- if ((of - length) < 0) {
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[of + i] = scanline[i + scanline_offset];
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[of + i] = (scanline[i + scanline_offset] + pixels[of + i - bpp]) & 0xFF;
985
+ pixels[offset + i] = (scanline[i + scanline_offset] + pixels[offset + i - bpp]) & 0xFF;
666
986
  }
987
+
667
988
  } else {
668
- const of1 = of - length;
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[of + i] = (scanline[i + scanline_offset] + pixels[of1 + i]) & 0xFF;
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
- const offset_0 = of + i;
679
-
680
- c = pixels[offset_0 - length - bpp];
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[offset_0] = (raw + pr) & 0xFF;
1018
+ pixels[offset + i] = (raw + pr) & 0xFF;
699
1019
  }
1020
+
700
1021
  }
701
1022
  };
702
1023