@woosh/meep-engine 3.45.0 → 3.46.0

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 (216) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/assert.d.ts.map +1 -1
  4. package/src/core/assert.js +5 -1
  5. package/src/core/binary/hash/XXH128Hash.d.ts +1 -37
  6. package/src/core/binary/hash/XXH128Hash.d.ts.map +1 -1
  7. package/src/core/binary/hash/XXH128Hash.js +4 -55
  8. package/src/core/binary/hash/XXH3_SECRET.d.ts +1 -12
  9. package/src/core/binary/hash/XXH3_SECRET.d.ts.map +1 -1
  10. package/src/core/binary/hash/XXH3_SECRET.js +4 -25
  11. package/src/core/binary/hash/crc32.d.ts +1 -15
  12. package/src/core/binary/hash/crc32.d.ts.map +1 -1
  13. package/src/core/binary/hash/crc32.js +4 -96
  14. package/src/core/binary/hash/xxh3_128.d.ts +1 -9
  15. package/src/core/binary/hash/xxh3_128.d.ts.map +1 -1
  16. package/src/core/binary/hash/xxh3_128.js +4 -341
  17. package/src/core/binary/hash/xxh3_64.d.ts +1 -8
  18. package/src/core/binary/hash/xxh3_64.d.ts.map +1 -1
  19. package/src/core/binary/hash/xxh3_64.js +4 -241
  20. package/src/core/binary/hash/xxh3_common.d.ts +1 -223
  21. package/src/core/binary/hash/xxh3_common.d.ts.map +1 -1
  22. package/src/core/binary/hash/xxh3_common.js +90 -476
  23. package/src/core/collection/array/combine_hash.d.ts +6 -0
  24. package/src/core/collection/array/combine_hash.d.ts.map +1 -1
  25. package/src/core/collection/array/combine_hash.js +6 -0
  26. package/src/core/function/FunctionCompiler.js +2 -2
  27. package/src/core/geom/3d/mat4/m4_multiply.d.ts +3 -0
  28. package/src/core/geom/3d/mat4/m4_multiply.d.ts.map +1 -1
  29. package/src/core/geom/3d/mat4/m4_multiply.js +3 -0
  30. package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts +30 -0
  31. package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts.map +1 -0
  32. package/src/core/geom/3d/mat4/m4_multiply_f64.js +106 -0
  33. package/src/core/geom/ConicRay.js +2 -2
  34. package/src/core/geom/Vector4.d.ts.map +1 -1
  35. package/src/core/geom/Vector4.js +8 -5
  36. package/src/core/math/hash/XXH128Hash.d.ts +38 -0
  37. package/src/core/math/hash/XXH128Hash.d.ts.map +1 -0
  38. package/src/core/math/hash/XXH128Hash.js +55 -0
  39. package/src/core/math/hash/XXH3_SECRET.d.ts +13 -0
  40. package/src/core/math/hash/XXH3_SECRET.d.ts.map +1 -0
  41. package/src/core/math/hash/XXH3_SECRET.js +25 -0
  42. package/src/core/math/hash/crc32.d.ts +16 -0
  43. package/src/core/math/hash/crc32.d.ts.map +1 -0
  44. package/src/core/math/hash/crc32.js +96 -0
  45. package/src/core/math/hash/xxh3_128.d.ts +10 -0
  46. package/src/core/math/hash/xxh3_128.d.ts.map +1 -0
  47. package/src/core/math/hash/xxh3_128.js +341 -0
  48. package/src/core/math/hash/xxh3_64.d.ts +9 -0
  49. package/src/core/math/hash/xxh3_64.d.ts.map +1 -0
  50. package/src/core/math/hash/xxh3_64.js +241 -0
  51. package/src/core/math/hash/xxh3_common.d.ts +224 -0
  52. package/src/core/math/hash/xxh3_common.d.ts.map +1 -0
  53. package/src/core/math/hash/xxh3_common.js +476 -0
  54. package/src/core/math/lookup/ParameterLookupTable.js +2 -2
  55. package/src/core/model/node-graph/node/NodeInstancePortReference.js +2 -2
  56. package/src/core/model/reactive/model/ReactiveBinaryExpression.js +2 -2
  57. package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -2
  58. package/src/engine/asset/AssetDescription.js +2 -2
  59. package/src/engine/ecs/animation/Animation.js +2 -2
  60. package/src/engine/ecs/animation/AnimationClip.d.ts.map +1 -1
  61. package/src/engine/ecs/animation/AnimationClip.js +7 -5
  62. package/src/engine/ecs/gui/GUIElement.d.ts.map +1 -1
  63. package/src/engine/ecs/gui/GUIElement.js +7 -5
  64. package/src/engine/ecs/gui/hud/HeadsUpDisplay.js +2 -2
  65. package/src/engine/ecs/gui/position/ViewportPosition.d.ts.map +1 -1
  66. package/src/engine/ecs/gui/position/ViewportPosition.js +11 -7
  67. package/src/engine/ecs/transform/Transform64.d.ts +1 -1
  68. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  69. package/src/engine/ecs/transform/Transform64.js +5 -4
  70. package/src/engine/graphics/ecs/animation/animator/AnimationClip.d.ts.map +1 -1
  71. package/src/engine/graphics/ecs/animation/animator/AnimationClip.js +8 -5
  72. package/src/engine/graphics/ecs/animation/animator/AnimationClipDefinition.js +2 -2
  73. package/src/engine/graphics/ecs/animation/animator/AnimationNotification.js +2 -2
  74. package/src/engine/graphics/ecs/animation/animator/AnimationNotificationDefinition.js +2 -2
  75. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +2 -2
  76. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationStateDefinition.js +2 -2
  77. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.d.ts.map +1 -1
  78. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.js +8 -5
  79. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
  80. package/src/engine/graphics/ecs/decal/v2/Decal.js +9 -8
  81. package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.d.ts.map +1 -1
  82. package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.js +9 -6
  83. package/src/engine/graphics3/ParticipatingMedia.js +204 -204
  84. package/src/engine/graphics3/animation/AnimationClips.d.ts +5 -0
  85. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -1
  86. package/src/engine/graphics3/animation/AnimationClips.js +5 -0
  87. package/src/engine/grid/obstacle/GridObstacle.js +2 -2
  88. package/src/engine/intelligence/behavior/selector/WeightedElement.js +2 -2
  89. package/src/engine/interpolation/Interpolated.js +2 -2
  90. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  91. package/src/engine/physics/cloth/ecs/Cloth.js +7 -5
  92. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/ecs/ClothCollider.js +7 -5
  94. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  95. package/src/engine/physics/cloth/ecs/ClothDynamics.js +20 -11
  96. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  97. package/src/engine/physics/fluid/FluidField.js +7 -5
  98. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  99. package/src/engine/physics/fluid/ecs/FluidComponent.js +19 -11
  100. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +2 -2
  101. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +2 -2
  102. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  103. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +11 -7
  104. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
  105. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +11 -7
  106. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  107. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +16 -9
  108. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
  109. package/src/engine/sound/ecs/audio/AudioEmitter.js +12 -7
  110. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
  111. package/src/engine/sound/ecs/trigger/AudioEventTrigger.js +192 -191
  112. package/src/engine/sound/simulation/core/AcousticMedium.js +2 -2
  113. package/src/engine/sound/simulation/definition/AcousticDirectivity.js +2 -2
  114. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
  115. package/src/engine/sound/simulation/definition/AcousticMaterial.js +11 -7
  116. package/src/engine/sound/sopra/definition/BusDefinition.d.ts.map +1 -1
  117. package/src/engine/sound/sopra/definition/BusDefinition.js +5 -4
  118. package/src/engine/sound/sopra/definition/DuckingRule.d.ts.map +1 -1
  119. package/src/engine/sound/sopra/definition/DuckingRule.js +7 -5
  120. package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
  121. package/src/engine/sound/sopra/definition/EventDescription.js +23 -13
  122. package/src/engine/sound/sopra/definition/MixerSnapshot.js +2 -2
  123. package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts.map +1 -1
  124. package/src/engine/sound/sopra/definition/ParameterDefinition.js +7 -5
  125. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +2 -2
  126. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
  127. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +4 -3
  128. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +2 -2
  129. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +3 -3
  130. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
  131. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +16 -9
  132. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +2 -2
  133. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -1
  134. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  135. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +2 -2
  136. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
  137. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +7 -5
  138. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
  139. package/src/engine/sound/sopra/definition/effect/EqEffect.js +8 -5
  140. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +2 -2
  141. package/src/engine/sound/sopra/legacy/SoundEmitter.d.ts.map +1 -1
  142. package/src/engine/sound/sopra/legacy/SoundEmitter.js +357 -352
  143. package/src/engine/sound/sopra/legacy/SoundTrack.d.ts.map +1 -1
  144. package/src/engine/sound/sopra/legacy/SoundTrack.js +281 -278
  145. package/src/format/image/png/PNGReader.js +644 -644
  146. package/src/format/image/png/crc32.d.ts +1 -1
  147. package/src/format/image/png/crc32.js +7 -8
  148. package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +2 -2
  149. package/src/shade/descriptor/binding/BindGroupLayoutEntry.d.ts.map +1 -1
  150. package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +12 -8
  151. package/src/shade/descriptor/binding/StorageTextureBindingLayout.js +2 -2
  152. package/src/shade/descriptor/binding/TextureBindingLayout.js +2 -2
  153. package/src/shade/descriptor/blend/BlendComponent.js +2 -2
  154. package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +2 -2
  155. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +2 -2
  156. package/src/shade/descriptor/pipeline/ProgrammableStage.js +2 -2
  157. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +2 -2
  158. package/src/shade/descriptor/pipeline/render/ColorTargetState.js +2 -2
  159. package/src/shade/descriptor/pipeline/render/FragmentState.js +2 -2
  160. package/src/shade/descriptor/pipeline/render/PrimitiveState.js +2 -2
  161. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
  162. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +8 -5
  163. package/src/shade/descriptor/pipeline/render/VertexAttribute.js +2 -2
  164. package/src/shade/descriptor/texture/SamplerDescriptor.d.ts.map +1 -1
  165. package/src/shade/descriptor/texture/SamplerDescriptor.js +20 -12
  166. package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
  167. package/src/shade/descriptor/texture/TextureDescriptor.js +11 -7
  168. package/src/shade/device/graph/BufferResourceDescriptor.d.ts.map +1 -1
  169. package/src/shade/device/graph/BufferResourceDescriptor.js +196 -193
  170. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  171. package/src/shade/device/graph/TextureResourceDescriptor.js +178 -173
  172. package/src/shade/device/timing/profile/sgpt_read_header.js +1 -1
  173. package/src/shade/device/timing/profile/sgpt_read_records.js +1 -1
  174. package/src/shade/device/timing/profile/sgpt_write_header.js +1 -1
  175. package/src/shade/device/timing/profile/sgpt_write_record.js +1 -1
  176. package/src/shade/renderer/binding/BufferBinding.js +2 -2
  177. package/src/shade/renderer/camera/Camera.js +2 -2
  178. package/src/shade/renderer/geometry/Attribute.js +2 -2
  179. package/src/shade/renderer/geometry/Geometry.js +2 -2
  180. package/src/shade/renderer/geometry/geometry_deduplicate_vertices.js +2 -2
  181. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +2 -2
  182. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
  183. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
  184. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
  185. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
  186. package/src/shade/renderer/material/StandardShadeMaterial.d.ts.map +1 -1
  187. package/src/shade/renderer/material/StandardShadeMaterial.js +13 -8
  188. package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.d.ts.map +1 -1
  189. package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.js +14 -5
  190. package/src/shade/renderer/scene/optimization/sampler2d_from_image_bitmap.js +1 -1
  191. package/src/shade/renderer/shader/type/WGSLStructField.js +2 -2
  192. package/src/shade/renderer/shader/type/WebGPUArray.js +2 -2
  193. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  194. package/src/shade/renderer/shader/type/WebGPUStruct.js +9 -6
  195. package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
  196. package/src/shade/renderer/texture/ShadeTexture.js +17 -10
  197. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +2 -2
  198. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -4
  199. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +6 -6
  200. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  201. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +46 -55
  202. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +3 -3
  203. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  204. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +14 -4
  205. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +10 -1
  206. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  207. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +82 -40
  208. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +4 -1
  209. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  210. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +8 -4
  211. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +98 -86
  212. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  213. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +440 -298
  214. package/src/view/common/HTMLElementCacheKey.d.ts.map +1 -1
  215. package/src/view/common/HTMLElementCacheKey.js +4 -3
  216. package/src/view/minimap/MinimapMarker.js +2 -2
@@ -1,657 +1,657 @@
1
- /*global Uint8Array:true ArrayBuffer:true */
2
- "use strict";
3
-
4
- import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
5
- import { EndianType } from "../../../core/binary/EndianType.js";
6
- import { platform_compute_endianness } from "../../../core/binary/platform_compute_endianness.js";
7
- import { isArrayEqualStrict } from "../../../core/collection/array/isArrayEqualStrict.js";
8
- import { png_chunk_decode_iTXt } from "./chunk/png_chunk_decode_iTXt.js";
9
- import { png_inflate } from "./png_inflate.js";
10
- import { png_chunk_decode_zTXt } from "./chunk/png_chunk_decode_zTXt.js";
11
- import { crc32 } from "../../../core/binary/hash/crc32.js";
12
- import { png_unfilter } from "./filter/png_unfilter.js";
13
- import { png_unpack_samples } from "./png_unpack_samples.js";
14
-
15
- import { PNG } from './PNG.js';
16
- import { PNG_HEADER_BYTES } from "./PNG_HEADER_BYTES.js";
17
-
18
- /**
19
- *
20
- * @param {Uint8Array} buffer
21
- * @param {number} offset
22
- * @return {number}
23
- */
24
- function readUInt32(buffer, offset) {
25
- return (buffer[offset] << 24)
26
- | (buffer[offset + 1] << 16)
27
- | (buffer[offset + 2] << 8)
28
- | (buffer[offset + 3]);
29
- }
30
-
31
-
32
- /**
33
- *
34
- * @param {Uint8Array} buffer
35
- * @param {number} offset
36
- * @return {number}
37
- */
38
- function readUInt8(buffer, offset) {
39
- return buffer[offset];
40
- }
41
-
42
- /**
43
- *
44
- * @param {ArrayBuffer} bytes
45
- * @constructor
46
- */
47
- export function PNGReader(bytes) {
48
- /**
49
- * Output object
50
- * @type {PNG}
51
- */
52
- this.png = new PNG();
53
-
54
- /**
55
- *
56
- * @type {Uint8Array[]}
57
- */
58
- this.dataChunks = [];
59
-
60
- /**
61
- *
62
- * @type {BinaryBuffer}
63
- */
64
- this.buffer = new BinaryBuffer();
65
-
66
- // see https://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order
67
- this.buffer.endianness = EndianType.BigEndian;
68
-
69
- this.buffer.fromArrayBuffer(bytes);
70
-
71
- /**
72
- * Whether CRC should be performed or not
73
- * @type {boolean}
74
- */
75
- this.crc_enabled = false;
76
- }
77
-
78
- /**
79
- *
80
- * @param {number} length
81
- * @return {Uint8Array}
82
- */
83
- PNGReader.prototype.readBytes = function (length) {
84
-
85
- const buffer = this.buffer;
86
-
87
- // Reference instead of a copy
88
- const result = new Uint8Array(buffer.data, buffer.position, length);
89
-
90
- buffer.skip(length);
91
-
92
- return result;
93
-
94
- };
95
-
96
- /**
97
- * http://www.w3.org/TR/2003/REC-PNG-20031110/#5PNG-file-signature
98
- */
99
- PNGReader.prototype.decodeHeader = function () {
100
-
101
- const buffer = this.buffer;
102
-
103
- const header = new Uint8Array(PNG_HEADER_BYTES.length);
104
-
105
- buffer.readBytes(header, 0, header.length);
106
-
107
- // see https://www.w3.org/TR/PNG-Structure.html
108
- if (!isArrayEqualStrict(header, PNG_HEADER_BYTES)) {
109
- throw new Error('invalid PNGReader file (bad signature)');
110
- }
111
-
112
-
113
- };
114
-
115
- /**
116
- * http://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-layout
117
- *
118
- * length = 4 bytes
119
- * type = 4 bytes (IHDR, PLTE, IDAT, IEND or others)
120
- * chunk = length bytes
121
- * crc = 4 bytes
122
- *
1
+ /*global Uint8Array:true ArrayBuffer:true */
2
+ "use strict";
3
+
4
+ import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
5
+ import { EndianType } from "../../../core/binary/EndianType.js";
6
+ import { platform_compute_endianness } from "../../../core/binary/platform_compute_endianness.js";
7
+ import { isArrayEqualStrict } from "../../../core/collection/array/isArrayEqualStrict.js";
8
+ import { png_chunk_decode_iTXt } from "./chunk/png_chunk_decode_iTXt.js";
9
+ import { png_inflate } from "./png_inflate.js";
10
+ import { png_chunk_decode_zTXt } from "./chunk/png_chunk_decode_zTXt.js";
11
+ import { crc32 } from "../../../core/math/hash/crc32.js";
12
+ import { png_unfilter } from "./filter/png_unfilter.js";
13
+ import { png_unpack_samples } from "./png_unpack_samples.js";
14
+
15
+ import { PNG } from './PNG.js';
16
+ import { PNG_HEADER_BYTES } from "./PNG_HEADER_BYTES.js";
17
+
18
+ /**
19
+ *
20
+ * @param {Uint8Array} buffer
21
+ * @param {number} offset
22
+ * @return {number}
23
+ */
24
+ function readUInt32(buffer, offset) {
25
+ return (buffer[offset] << 24)
26
+ | (buffer[offset + 1] << 16)
27
+ | (buffer[offset + 2] << 8)
28
+ | (buffer[offset + 3]);
29
+ }
30
+
31
+
32
+ /**
33
+ *
34
+ * @param {Uint8Array} buffer
35
+ * @param {number} offset
36
+ * @return {number}
37
+ */
38
+ function readUInt8(buffer, offset) {
39
+ return buffer[offset];
40
+ }
41
+
42
+ /**
43
+ *
44
+ * @param {ArrayBuffer} bytes
45
+ * @constructor
46
+ */
47
+ export function PNGReader(bytes) {
48
+ /**
49
+ * Output object
50
+ * @type {PNG}
51
+ */
52
+ this.png = new PNG();
53
+
54
+ /**
55
+ *
56
+ * @type {Uint8Array[]}
57
+ */
58
+ this.dataChunks = [];
59
+
60
+ /**
61
+ *
62
+ * @type {BinaryBuffer}
63
+ */
64
+ this.buffer = new BinaryBuffer();
65
+
66
+ // see https://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order
67
+ this.buffer.endianness = EndianType.BigEndian;
68
+
69
+ this.buffer.fromArrayBuffer(bytes);
70
+
71
+ /**
72
+ * Whether CRC should be performed or not
73
+ * @type {boolean}
74
+ */
75
+ this.crc_enabled = false;
76
+ }
77
+
78
+ /**
79
+ *
80
+ * @param {number} length
81
+ * @return {Uint8Array}
82
+ */
83
+ PNGReader.prototype.readBytes = function (length) {
84
+
85
+ const buffer = this.buffer;
86
+
87
+ // Reference instead of a copy
88
+ const result = new Uint8Array(buffer.data, buffer.position, length);
89
+
90
+ buffer.skip(length);
91
+
92
+ return result;
93
+
94
+ };
95
+
96
+ /**
97
+ * http://www.w3.org/TR/2003/REC-PNG-20031110/#5PNG-file-signature
98
+ */
99
+ PNGReader.prototype.decodeHeader = function () {
100
+
101
+ const buffer = this.buffer;
102
+
103
+ const header = new Uint8Array(PNG_HEADER_BYTES.length);
104
+
105
+ buffer.readBytes(header, 0, header.length);
106
+
107
+ // see https://www.w3.org/TR/PNG-Structure.html
108
+ if (!isArrayEqualStrict(header, PNG_HEADER_BYTES)) {
109
+ throw new Error('invalid PNGReader file (bad signature)');
110
+ }
111
+
112
+
113
+ };
114
+
115
+ /**
116
+ * http://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-layout
117
+ *
118
+ * length = 4 bytes
119
+ * type = 4 bytes (IHDR, PLTE, IDAT, IEND or others)
120
+ * chunk = length bytes
121
+ * crc = 4 bytes
122
+ *
123
123
  * @returns {Promise<string>} chunk type, after any compressed metadata has been decoded
124
- */
124
+ */
125
125
  PNGReader.prototype.decodeChunk = async function () {
126
-
127
- const buffer = this.buffer;
128
-
129
- const length = buffer.readUint32();
130
-
131
- if (length < 0) {
132
- throw new Error('Bad chunk length ' + (0xFFFFFFFF & length));
133
- }
134
-
135
-
136
- const chunk_address = buffer.position;
137
-
138
- const type = buffer.readASCIICharacters(4);
139
-
140
- /**
141
- *
142
- * @type {Uint8Array}
143
- */
144
- const chunk = this.readBytes(length);
145
-
146
- // checksum
147
- const crc_expected = buffer.readUint32();
148
-
149
- if (this.crc_enabled) {
150
-
151
- // NOTE: CRC includes the "type" tag, not just the chunk bytes
152
- const crc_actual = crc32(buffer.raw_bytes, chunk_address, length + 4);
153
-
154
- if (crc_actual !== crc_expected) {
155
- console.warn(`CRC (Cyclic Redundancy Check) error at block '${type}' at address ${chunk_address}`);
156
- }
157
-
158
- }
159
-
160
- // console.log(`chunk: ${type}`);
161
-
162
-
163
- switch (type) {
164
- case 'IHDR':
165
- this.decodeIHDR(chunk);
166
- break;
167
- case 'PLTE':
168
- this.decodePLTE(chunk);
169
- break;
170
- case 'IDAT':
171
- this.decodeIDAT(chunk);
172
- break;
173
- case 'tRNS':
174
- this.decodeTRNS(chunk);
175
- break;
176
- case 'IEND':
177
- this.decodeIEND(chunk);
178
- break;
179
- case 'sRGB':
180
- this.decodesRGB(chunk);
181
- break;
182
- case 'tIME':
183
- this.decodetIME(chunk);
184
- break;
185
- case 'zTXt':
126
+
127
+ const buffer = this.buffer;
128
+
129
+ const length = buffer.readUint32();
130
+
131
+ if (length < 0) {
132
+ throw new Error('Bad chunk length ' + (0xFFFFFFFF & length));
133
+ }
134
+
135
+
136
+ const chunk_address = buffer.position;
137
+
138
+ const type = buffer.readASCIICharacters(4);
139
+
140
+ /**
141
+ *
142
+ * @type {Uint8Array}
143
+ */
144
+ const chunk = this.readBytes(length);
145
+
146
+ // checksum
147
+ const crc_expected = buffer.readUint32();
148
+
149
+ if (this.crc_enabled) {
150
+
151
+ // NOTE: CRC includes the "type" tag, not just the chunk bytes
152
+ const crc_actual = crc32(buffer.raw_bytes, chunk_address, length + 4);
153
+
154
+ if (crc_actual !== crc_expected) {
155
+ console.warn(`CRC (Cyclic Redundancy Check) error at block '${type}' at address ${chunk_address}`);
156
+ }
157
+
158
+ }
159
+
160
+ // console.log(`chunk: ${type}`);
161
+
162
+
163
+ switch (type) {
164
+ case 'IHDR':
165
+ this.decodeIHDR(chunk);
166
+ break;
167
+ case 'PLTE':
168
+ this.decodePLTE(chunk);
169
+ break;
170
+ case 'IDAT':
171
+ this.decodeIDAT(chunk);
172
+ break;
173
+ case 'tRNS':
174
+ this.decodeTRNS(chunk);
175
+ break;
176
+ case 'IEND':
177
+ this.decodeIEND(chunk);
178
+ break;
179
+ case 'sRGB':
180
+ this.decodesRGB(chunk);
181
+ break;
182
+ case 'tIME':
183
+ this.decodetIME(chunk);
184
+ break;
185
+ case 'zTXt':
186
186
  await png_chunk_decode_zTXt(chunk);
187
- break;
188
- case 'iTXt':
187
+ break;
188
+ case 'iTXt':
189
189
  await png_chunk_decode_iTXt(chunk);
190
- break;
191
- default:
192
- // skip unknown block
193
- // console.warn(`Unsupported block ${type}`);
194
- break;
195
- }
196
-
197
- return type;
198
-
199
- };
200
-
201
-
202
- /**
203
- * https://www.w3.org/TR/2003/REC-PNG-20031110/#11sRGB
204
- * @param {Uint8Array} chunk
205
- */
206
- PNGReader.prototype.decodesRGB = function (chunk) {
207
-
208
- const rendering_intent = readUInt8(chunk, 0);
209
-
210
- // TODO add metadata to the PNG representation
211
- }
212
-
213
- /**
214
- * https://www.w3.org/TR/2003/REC-PNG-20031110/#11tIME
215
- * @param {Uint8Array} chunk
216
- */
217
- PNGReader.prototype.decodetIME = function (chunk) {
218
- const year_high = readUInt8(chunk, 0);
219
- const year_low = readUInt8(chunk, 1);
220
-
221
- const year = (year_high << 8) | year_low;
222
-
223
- const month = readUInt8(chunk, 2);
224
- const day = readUInt8(chunk, 3);
225
- const hour = readUInt8(chunk, 4);
226
- const minute = readUInt8(chunk, 5);
227
- const second = readUInt8(chunk, 6);
228
- }
229
-
230
- /**
231
- * https://www.w3.org/TR/PNG/#11tEXt
232
- * @param {Uint8Array} chunk
233
- */
234
- PNGReader.prototype.decodetEXt = function (chunk) {
235
- const buff = BinaryBuffer.fromArrayBuffer(chunk.buffer);
236
- const keyword = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
237
-
238
- const value = buff.readASCIICharacters(keyword.length - 1, false);
239
-
240
- this.png.text[keyword] = value;
241
- }
242
- /**
243
- * NOTE: untested
244
- * https://www.w3.org/TR/PNG/#11iEXt
245
- * @param {Uint8Array} chunk
246
- */
247
- PNGReader.prototype.decodeiEXt = function (chunk) {
248
- const buff = BinaryBuffer.fromArrayBuffer(chunk.buffer);
249
-
250
- const keyword = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
251
-
252
- const compression_flag = buff.readUint8();
253
- const compression_method = buff.readUint8();
254
-
255
- // TODO process compression properly
256
-
257
- const language_tag = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
258
- const translated_keyword = buff.readUTF8String();
259
-
260
- const separator = buff.readUint8();
261
-
262
- if (separator !== 0) {
263
- throw new Error('Expected Null Separator after Translated keyword');
264
- }
265
-
266
- const text = buff.readUTF8String();
267
-
268
- this.png.text[keyword] = text;
269
- }
270
-
271
- /**
272
- * http://www.w3.org/TR/2003/REC-PNG-20031110/#11IHDR
273
- * http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html#C.IHDR
274
- *
275
- * Width 4 bytes
276
- * Height 4 bytes
277
- * Bit depth 1 byte
278
- * Colour type 1 byte
279
- * Compression method 1 byte
280
- * Filter method 1 byte
281
- * Interlace method 1 byte
282
- */
283
- PNGReader.prototype.decodeIHDR = function (chunk) {
284
- const png = this.png;
285
-
286
- png.setWidth(readUInt32(chunk, 0));
287
- png.setHeight(readUInt32(chunk, 4));
288
- png.setBitDepth(readUInt8(chunk, 8));
289
- png.setColorType(readUInt8(chunk, 9));
290
- png.setCompressionMethod(readUInt8(chunk, 10));
291
- png.setFilterMethod(readUInt8(chunk, 11));
292
- png.setInterlaceMethod(readUInt8(chunk, 12));
293
-
294
- };
295
-
296
- /**
297
- *
298
- * http://www.w3.org/TR/PNG/#11PLTE
299
- * @param {Uint8Array} chunk
300
- */
301
- PNGReader.prototype.decodePLTE = function (chunk) {
302
- this.png.setPalette(chunk);
303
- };
304
-
305
- /**
306
- * http://www.w3.org/TR/2003/REC-PNG-20031110/#11IDAT
307
- */
308
- PNGReader.prototype.decodeIDAT = function (chunk) {
309
- // multiple IDAT chunks will concatenated
310
- this.dataChunks.push(chunk);
311
- };
312
-
313
- /**
314
- * https://www.w3.org/TR/PNG/#11tRNS
315
- * @param {Uint8Array} chunk
316
- */
317
- PNGReader.prototype.decodeTRNS = function (chunk) {
318
- this.png.transparency_lookup = chunk;
319
- };
320
-
321
- /**
322
- * http://www.w3.org/TR/2003/REC-PNG-20031110/#11IEND
323
- */
324
- PNGReader.prototype.decodeIEND = function () {
325
- };
326
-
327
- /**
190
+ break;
191
+ default:
192
+ // skip unknown block
193
+ // console.warn(`Unsupported block ${type}`);
194
+ break;
195
+ }
196
+
197
+ return type;
198
+
199
+ };
200
+
201
+
202
+ /**
203
+ * https://www.w3.org/TR/2003/REC-PNG-20031110/#11sRGB
204
+ * @param {Uint8Array} chunk
205
+ */
206
+ PNGReader.prototype.decodesRGB = function (chunk) {
207
+
208
+ const rendering_intent = readUInt8(chunk, 0);
209
+
210
+ // TODO add metadata to the PNG representation
211
+ }
212
+
213
+ /**
214
+ * https://www.w3.org/TR/2003/REC-PNG-20031110/#11tIME
215
+ * @param {Uint8Array} chunk
216
+ */
217
+ PNGReader.prototype.decodetIME = function (chunk) {
218
+ const year_high = readUInt8(chunk, 0);
219
+ const year_low = readUInt8(chunk, 1);
220
+
221
+ const year = (year_high << 8) | year_low;
222
+
223
+ const month = readUInt8(chunk, 2);
224
+ const day = readUInt8(chunk, 3);
225
+ const hour = readUInt8(chunk, 4);
226
+ const minute = readUInt8(chunk, 5);
227
+ const second = readUInt8(chunk, 6);
228
+ }
229
+
230
+ /**
231
+ * https://www.w3.org/TR/PNG/#11tEXt
232
+ * @param {Uint8Array} chunk
233
+ */
234
+ PNGReader.prototype.decodetEXt = function (chunk) {
235
+ const buff = BinaryBuffer.fromArrayBuffer(chunk.buffer);
236
+ const keyword = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
237
+
238
+ const value = buff.readASCIICharacters(keyword.length - 1, false);
239
+
240
+ this.png.text[keyword] = value;
241
+ }
242
+ /**
243
+ * NOTE: untested
244
+ * https://www.w3.org/TR/PNG/#11iEXt
245
+ * @param {Uint8Array} chunk
246
+ */
247
+ PNGReader.prototype.decodeiEXt = function (chunk) {
248
+ const buff = BinaryBuffer.fromArrayBuffer(chunk.buffer);
249
+
250
+ const keyword = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
251
+
252
+ const compression_flag = buff.readUint8();
253
+ const compression_method = buff.readUint8();
254
+
255
+ // TODO process compression properly
256
+
257
+ const language_tag = buff.readASCIICharacters(Number.POSITIVE_INFINITY, true);
258
+ const translated_keyword = buff.readUTF8String();
259
+
260
+ const separator = buff.readUint8();
261
+
262
+ if (separator !== 0) {
263
+ throw new Error('Expected Null Separator after Translated keyword');
264
+ }
265
+
266
+ const text = buff.readUTF8String();
267
+
268
+ this.png.text[keyword] = text;
269
+ }
270
+
271
+ /**
272
+ * http://www.w3.org/TR/2003/REC-PNG-20031110/#11IHDR
273
+ * http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html#C.IHDR
274
+ *
275
+ * Width 4 bytes
276
+ * Height 4 bytes
277
+ * Bit depth 1 byte
278
+ * Colour type 1 byte
279
+ * Compression method 1 byte
280
+ * Filter method 1 byte
281
+ * Interlace method 1 byte
282
+ */
283
+ PNGReader.prototype.decodeIHDR = function (chunk) {
284
+ const png = this.png;
285
+
286
+ png.setWidth(readUInt32(chunk, 0));
287
+ png.setHeight(readUInt32(chunk, 4));
288
+ png.setBitDepth(readUInt8(chunk, 8));
289
+ png.setColorType(readUInt8(chunk, 9));
290
+ png.setCompressionMethod(readUInt8(chunk, 10));
291
+ png.setFilterMethod(readUInt8(chunk, 11));
292
+ png.setInterlaceMethod(readUInt8(chunk, 12));
293
+
294
+ };
295
+
296
+ /**
297
+ *
298
+ * http://www.w3.org/TR/PNG/#11PLTE
299
+ * @param {Uint8Array} chunk
300
+ */
301
+ PNGReader.prototype.decodePLTE = function (chunk) {
302
+ this.png.setPalette(chunk);
303
+ };
304
+
305
+ /**
306
+ * http://www.w3.org/TR/2003/REC-PNG-20031110/#11IDAT
307
+ */
308
+ PNGReader.prototype.decodeIDAT = function (chunk) {
309
+ // multiple IDAT chunks will concatenated
310
+ this.dataChunks.push(chunk);
311
+ };
312
+
313
+ /**
314
+ * https://www.w3.org/TR/PNG/#11tRNS
315
+ * @param {Uint8Array} chunk
316
+ */
317
+ PNGReader.prototype.decodeTRNS = function (chunk) {
318
+ this.png.transparency_lookup = chunk;
319
+ };
320
+
321
+ /**
322
+ * http://www.w3.org/TR/2003/REC-PNG-20031110/#11IEND
323
+ */
324
+ PNGReader.prototype.decodeIEND = function () {
325
+ };
326
+
327
+ /**
328
328
  * Uncompress IDAT chunks
329
329
  * @returns {Promise<void>}
330
- */
330
+ */
331
331
  PNGReader.prototype.decodePixels = async function () {
332
- const png = this.png;
333
-
334
- // leniently: a corrupt adler32 trailer over a sound deflate payload is common enough in the
335
- // wild that Chrome and libpng both accept it, and a texture that refuses to load is worse than
336
- // one whose checksum nobody reads
332
+ const png = this.png;
333
+
334
+ // leniently: a corrupt adler32 trailer over a sound deflate payload is common enough in the
335
+ // wild that Chrome and libpng both accept it, and a texture that refuses to load is worse than
336
+ // one whose checksum nobody reads
337
337
  const decompressed_data = await png_inflate(this.dataChunks, true);
338
-
339
- // https://www.w3.org/TR/png-3/#8InterlaceMethods
340
- if (png.getInterlaceMethod() === 0) {
341
- this.png.pixels = this.interlaceNone(decompressed_data);
342
- } else {
343
- this.png.pixels = this.interlaceAdam7(decompressed_data);
344
- }
345
-
346
- // PNG stores 16-bit samples big-endian. Rewrite the buffer to platform-endian
347
- // here so that downstream consumers can view it as Uint16Array without further
348
- // byte swapping.
349
- if (png.bitDepth === 16 && platform_compute_endianness() === EndianType.LittleEndian) {
350
- const pixels = this.png.pixels;
351
- for (let i = 0; i < pixels.length; i += 2) {
352
- const hi = pixels[i];
353
- pixels[i] = pixels[i + 1];
354
- pixels[i + 1] = hi;
355
- }
356
- }
357
- };
358
-
359
- // Different interlace methods
360
-
361
- /**
362
- * Reconstruct a non-interlaced image.
363
- *
364
- * Filtering is byte-wise, so at bit depths below eight the reconstructed scanline is still packed
365
- * and has to be unpacked into the output separately. At eight bits and above the two are the same
366
- * thing, and the reconstruction is written straight into the output with no intermediate row.
367
- *
368
- * @param {Uint8Array} data
369
- * @returns {Uint8Array}
370
- */
371
- PNGReader.prototype.interlaceNone = function (data) {
372
-
373
- const png = this.png;
374
-
375
- const depth = png.bitDepth;
376
- const channels = png.colors;
377
-
378
- const width = png.width;
379
- const height = png.height;
380
-
381
- // the specification's `bpp`: whole bytes per pixel, and never less than one
382
- const bytes_per_pixel = Math.max(1, Math.ceil(channels * depth / 8));
383
-
384
- const bytes_per_row = Math.ceil(channels * depth * width / 8);
385
-
386
- if (depth < 8) {
387
- return interlace_none_packed(data, depth, channels * width, bytes_per_pixel, bytes_per_row, height);
388
- }
389
-
390
- const pixels = new Uint8Array(bytes_per_row * height);
391
-
392
- let offset = 0;
393
-
394
- const data_length = data.length;
395
-
396
- for (let i = 0; i < data_length; i += bytes_per_row + 1) {
397
-
398
- const scanline_address = i + 1;
399
-
400
- const filter_type = data[i];
401
-
402
- png_unfilter(
403
- filter_type,
404
- data,
405
- scanline_address,
406
- pixels,
407
- bytes_per_pixel,
408
- offset,
409
- offset - bytes_per_row,
410
- bytes_per_row
411
- );
412
-
413
- offset += bytes_per_row;
414
-
415
- }
416
-
417
- return pixels;
418
-
419
- };
420
-
421
- /**
422
- * The sub-byte half of {@link PNGReader#interlaceNone}.
423
- *
424
- * Two packed rows are kept, alternating, because the `Up`, `Average` and `Paeth` filters predict
425
- * from the previous scanline as it was *packed*, not as it was unpacked.
426
- *
427
- * @param {Uint8Array} data
428
- * @param {number} depth `1`, `2` or `4`
429
- * @param {number} samples_per_row
430
- * @param {number} bytes_per_pixel
431
- * @param {number} bytes_per_row packed
432
- * @param {number} height
433
- * @returns {Uint8Array} one byte per sample
434
- */
435
- function interlace_none_packed(data, depth, samples_per_row, bytes_per_pixel, bytes_per_row, height) {
436
- const pixels = new Uint8Array(samples_per_row * height);
437
-
438
- const rows = new Uint8Array(bytes_per_row * 2);
439
-
440
- const rows_available = Math.floor(data.length / (bytes_per_row + 1));
441
- const row_count = height < rows_available ? height : rows_available;
442
-
443
- let at = 0;
444
- let previous_row_offset = -1;
445
-
446
- for (let y = 0; y < row_count; y++) {
447
- const filter_type = data[at++];
448
-
449
- const row_offset = (y & 1) * bytes_per_row;
450
-
451
- png_unfilter(
452
- filter_type,
453
- data,
454
- at,
455
- rows,
456
- bytes_per_pixel,
457
- row_offset,
458
- previous_row_offset,
459
- bytes_per_row
460
- );
461
-
462
- at += bytes_per_row;
463
-
464
- png_unpack_samples(rows, row_offset, depth, samples_per_row, pixels, y * samples_per_row);
465
-
466
- previous_row_offset = row_offset;
467
- }
468
-
469
- return pixels;
470
- }
471
-
472
-
473
- /**
474
- * De-interlace an image according to the Adam7 scheme.
475
- *
476
- * Each of the seven passes is its own little image with its own scanline width, so its own
477
- * filtering and — below eight bits — its own packing. Reconstructed rows land in a two-row scratch
478
- * (the filters predict from the previous row of the same pass) and are scattered into the output.
479
- *
480
- * @param {Uint8Array} data
481
- * @returns {Uint8Array}
482
- */
483
- PNGReader.prototype.interlaceAdam7 = function (data) {
484
-
485
- const png = this.png;
486
-
487
- const depth = png.bitDepth;
488
- const channels = png.colors;
489
-
490
- const width = png.width;
491
- const height = png.height;
492
-
493
- const packed = depth < 8;
494
-
495
- // the specification's `bpp`, used for filtering
496
- const bytes_per_pixel = Math.max(1, Math.ceil(channels * depth / 8));
497
-
498
- // bytes a pixel occupies in the *output*, where sub-byte samples have been expanded
499
- const output_pixel_bytes = channels * (depth === 16 ? 2 : 1);
500
-
501
- const pixels = new Uint8Array(output_pixel_bytes * width * height);
502
-
503
- // Adam7 interlacing pattern
504
- const passes = [
505
- { x: 0, y: 0, xStep: 8, yStep: 8 }, // Pass 1
506
- { x: 4, y: 0, xStep: 8, yStep: 8 }, // Pass 2
507
- { x: 0, y: 4, xStep: 4, yStep: 8 }, // Pass 3
508
- { x: 2, y: 0, xStep: 4, yStep: 4 }, // Pass 4
509
- { x: 0, y: 2, xStep: 2, yStep: 4 }, // Pass 5
510
- { x: 1, y: 0, xStep: 2, yStep: 2 }, // Pass 6
511
- { x: 0, y: 1, xStep: 1, yStep: 2 }, // Pass 7
512
- ];
513
-
514
- let offset = 0;
515
-
516
- // two reconstructed rows, alternating, so that the previous one is still there to predict from
517
- const line_bytes_buffer = new Uint8Array(Math.ceil(channels * depth * width / 8) * 2);
518
-
519
- // one unpacked row, used only below eight bits
520
- const sample_buffer = packed ? new Uint8Array(channels * width) : null;
521
-
522
- // Process each pass
523
- for (let passIndex = 0; passIndex < 7; passIndex++) {
524
- const pass = passes[passIndex];
525
-
526
- // Calculate pass dimensions
527
- const pass_width = Math.ceil((width - pass.x) / pass.xStep);
528
- const pass_height = Math.ceil((height - pass.y) / pass.yStep);
529
-
530
- if (pass_width <= 0 || pass_height <= 0) {
531
- continue;
532
- }
533
-
534
- const pass_samples = channels * pass_width;
535
- const pass_line_bytes = Math.ceil(pass_samples * depth / 8);
536
-
537
- // Indicate to unfiltering that this is the first line (no previous line)
538
- let previous_line_offset = -1;
539
-
540
- // Process each scanline in this pass
541
- for (let y = 0; y < pass_height; y++) {
542
-
543
- // First byte is the filter type
544
- const filter_type = data[offset++];
545
-
546
- // we use alternating line offsets to save on memory allocations
547
- const line_offset = (y % 2) * pass_line_bytes;
548
-
549
- png_unfilter(
550
- filter_type,
551
- data,
552
- offset,
553
- line_bytes_buffer,
554
- bytes_per_pixel,
555
- line_offset,
556
- previous_line_offset,
557
- pass_line_bytes
558
- );
559
-
560
- offset += pass_line_bytes;
561
- previous_line_offset = line_offset;
562
-
563
- // below eight bits the reconstruction is still packed, so expand it before scattering
564
- let source = line_bytes_buffer;
565
- let source_offset = line_offset;
566
-
567
- if (packed) {
568
- png_unpack_samples(line_bytes_buffer, line_offset, depth, pass_samples, sample_buffer, 0);
569
-
570
- source = sample_buffer;
571
- source_offset = 0;
572
- }
573
-
574
- for (let x = 0; x < pass_width; x++) {
575
-
576
- const outputX = pass.x + x * pass.xStep;
577
- const outputY = pass.y + y * pass.yStep;
578
-
579
- if (outputX >= width || outputY >= height) {
580
- continue;
581
- }
582
-
583
- for (let i = 0; i < output_pixel_bytes; i++) {
584
- const out_offset = (outputY * width + outputX) * output_pixel_bytes + i;
585
-
586
- pixels[out_offset] = source[source_offset + x * output_pixel_bytes + i];
587
- }
588
- }
589
- }
590
- }
591
-
592
- return pixels;
593
- };
594
-
595
- // Unfiltering
596
-
597
- /**
598
- * Reconstruct one filtered scanline. Kept as a method so the reader's surface is unchanged; the
599
- * dispatch itself lives in {@link png_unfilter}.
600
- *
601
- * @param {number} filter_type
602
- * @param {Uint8Array} data
603
- * @param {number} scanline_address
604
- * @param {Uint8Array} output
605
- * @param {number} bytes_per_pixel
606
- * @param {number} output_offset
607
- * @param {number} output_offset_previous where does result of previous scanline begin in the output? Needed for various filters such as `Up`
608
- * @param {number} length
609
- *
610
- * @see https://www.w3.org/TR/PNG-Filters.html
611
- */
612
- PNGReader.prototype.unFilter = function (
613
- filter_type,
614
- data,
615
- scanline_address,
616
- output,
617
- bytes_per_pixel,
618
- output_offset,
619
- output_offset_previous,
620
- length
621
- ) {
622
- png_unfilter(
623
- filter_type,
624
- data,
625
- scanline_address,
626
- output,
627
- bytes_per_pixel,
628
- output_offset,
629
- output_offset_previous,
630
- length
631
- );
632
- }
633
-
634
- /**
338
+
339
+ // https://www.w3.org/TR/png-3/#8InterlaceMethods
340
+ if (png.getInterlaceMethod() === 0) {
341
+ this.png.pixels = this.interlaceNone(decompressed_data);
342
+ } else {
343
+ this.png.pixels = this.interlaceAdam7(decompressed_data);
344
+ }
345
+
346
+ // PNG stores 16-bit samples big-endian. Rewrite the buffer to platform-endian
347
+ // here so that downstream consumers can view it as Uint16Array without further
348
+ // byte swapping.
349
+ if (png.bitDepth === 16 && platform_compute_endianness() === EndianType.LittleEndian) {
350
+ const pixels = this.png.pixels;
351
+ for (let i = 0; i < pixels.length; i += 2) {
352
+ const hi = pixels[i];
353
+ pixels[i] = pixels[i + 1];
354
+ pixels[i + 1] = hi;
355
+ }
356
+ }
357
+ };
358
+
359
+ // Different interlace methods
360
+
361
+ /**
362
+ * Reconstruct a non-interlaced image.
363
+ *
364
+ * Filtering is byte-wise, so at bit depths below eight the reconstructed scanline is still packed
365
+ * and has to be unpacked into the output separately. At eight bits and above the two are the same
366
+ * thing, and the reconstruction is written straight into the output with no intermediate row.
367
+ *
368
+ * @param {Uint8Array} data
369
+ * @returns {Uint8Array}
370
+ */
371
+ PNGReader.prototype.interlaceNone = function (data) {
372
+
373
+ const png = this.png;
374
+
375
+ const depth = png.bitDepth;
376
+ const channels = png.colors;
377
+
378
+ const width = png.width;
379
+ const height = png.height;
380
+
381
+ // the specification's `bpp`: whole bytes per pixel, and never less than one
382
+ const bytes_per_pixel = Math.max(1, Math.ceil(channels * depth / 8));
383
+
384
+ const bytes_per_row = Math.ceil(channels * depth * width / 8);
385
+
386
+ if (depth < 8) {
387
+ return interlace_none_packed(data, depth, channels * width, bytes_per_pixel, bytes_per_row, height);
388
+ }
389
+
390
+ const pixels = new Uint8Array(bytes_per_row * height);
391
+
392
+ let offset = 0;
393
+
394
+ const data_length = data.length;
395
+
396
+ for (let i = 0; i < data_length; i += bytes_per_row + 1) {
397
+
398
+ const scanline_address = i + 1;
399
+
400
+ const filter_type = data[i];
401
+
402
+ png_unfilter(
403
+ filter_type,
404
+ data,
405
+ scanline_address,
406
+ pixels,
407
+ bytes_per_pixel,
408
+ offset,
409
+ offset - bytes_per_row,
410
+ bytes_per_row
411
+ );
412
+
413
+ offset += bytes_per_row;
414
+
415
+ }
416
+
417
+ return pixels;
418
+
419
+ };
420
+
421
+ /**
422
+ * The sub-byte half of {@link PNGReader#interlaceNone}.
423
+ *
424
+ * Two packed rows are kept, alternating, because the `Up`, `Average` and `Paeth` filters predict
425
+ * from the previous scanline as it was *packed*, not as it was unpacked.
426
+ *
427
+ * @param {Uint8Array} data
428
+ * @param {number} depth `1`, `2` or `4`
429
+ * @param {number} samples_per_row
430
+ * @param {number} bytes_per_pixel
431
+ * @param {number} bytes_per_row packed
432
+ * @param {number} height
433
+ * @returns {Uint8Array} one byte per sample
434
+ */
435
+ function interlace_none_packed(data, depth, samples_per_row, bytes_per_pixel, bytes_per_row, height) {
436
+ const pixels = new Uint8Array(samples_per_row * height);
437
+
438
+ const rows = new Uint8Array(bytes_per_row * 2);
439
+
440
+ const rows_available = Math.floor(data.length / (bytes_per_row + 1));
441
+ const row_count = height < rows_available ? height : rows_available;
442
+
443
+ let at = 0;
444
+ let previous_row_offset = -1;
445
+
446
+ for (let y = 0; y < row_count; y++) {
447
+ const filter_type = data[at++];
448
+
449
+ const row_offset = (y & 1) * bytes_per_row;
450
+
451
+ png_unfilter(
452
+ filter_type,
453
+ data,
454
+ at,
455
+ rows,
456
+ bytes_per_pixel,
457
+ row_offset,
458
+ previous_row_offset,
459
+ bytes_per_row
460
+ );
461
+
462
+ at += bytes_per_row;
463
+
464
+ png_unpack_samples(rows, row_offset, depth, samples_per_row, pixels, y * samples_per_row);
465
+
466
+ previous_row_offset = row_offset;
467
+ }
468
+
469
+ return pixels;
470
+ }
471
+
472
+
473
+ /**
474
+ * De-interlace an image according to the Adam7 scheme.
475
+ *
476
+ * Each of the seven passes is its own little image with its own scanline width, so its own
477
+ * filtering and — below eight bits — its own packing. Reconstructed rows land in a two-row scratch
478
+ * (the filters predict from the previous row of the same pass) and are scattered into the output.
479
+ *
480
+ * @param {Uint8Array} data
481
+ * @returns {Uint8Array}
482
+ */
483
+ PNGReader.prototype.interlaceAdam7 = function (data) {
484
+
485
+ const png = this.png;
486
+
487
+ const depth = png.bitDepth;
488
+ const channels = png.colors;
489
+
490
+ const width = png.width;
491
+ const height = png.height;
492
+
493
+ const packed = depth < 8;
494
+
495
+ // the specification's `bpp`, used for filtering
496
+ const bytes_per_pixel = Math.max(1, Math.ceil(channels * depth / 8));
497
+
498
+ // bytes a pixel occupies in the *output*, where sub-byte samples have been expanded
499
+ const output_pixel_bytes = channels * (depth === 16 ? 2 : 1);
500
+
501
+ const pixels = new Uint8Array(output_pixel_bytes * width * height);
502
+
503
+ // Adam7 interlacing pattern
504
+ const passes = [
505
+ { x: 0, y: 0, xStep: 8, yStep: 8 }, // Pass 1
506
+ { x: 4, y: 0, xStep: 8, yStep: 8 }, // Pass 2
507
+ { x: 0, y: 4, xStep: 4, yStep: 8 }, // Pass 3
508
+ { x: 2, y: 0, xStep: 4, yStep: 4 }, // Pass 4
509
+ { x: 0, y: 2, xStep: 2, yStep: 4 }, // Pass 5
510
+ { x: 1, y: 0, xStep: 2, yStep: 2 }, // Pass 6
511
+ { x: 0, y: 1, xStep: 1, yStep: 2 }, // Pass 7
512
+ ];
513
+
514
+ let offset = 0;
515
+
516
+ // two reconstructed rows, alternating, so that the previous one is still there to predict from
517
+ const line_bytes_buffer = new Uint8Array(Math.ceil(channels * depth * width / 8) * 2);
518
+
519
+ // one unpacked row, used only below eight bits
520
+ const sample_buffer = packed ? new Uint8Array(channels * width) : null;
521
+
522
+ // Process each pass
523
+ for (let passIndex = 0; passIndex < 7; passIndex++) {
524
+ const pass = passes[passIndex];
525
+
526
+ // Calculate pass dimensions
527
+ const pass_width = Math.ceil((width - pass.x) / pass.xStep);
528
+ const pass_height = Math.ceil((height - pass.y) / pass.yStep);
529
+
530
+ if (pass_width <= 0 || pass_height <= 0) {
531
+ continue;
532
+ }
533
+
534
+ const pass_samples = channels * pass_width;
535
+ const pass_line_bytes = Math.ceil(pass_samples * depth / 8);
536
+
537
+ // Indicate to unfiltering that this is the first line (no previous line)
538
+ let previous_line_offset = -1;
539
+
540
+ // Process each scanline in this pass
541
+ for (let y = 0; y < pass_height; y++) {
542
+
543
+ // First byte is the filter type
544
+ const filter_type = data[offset++];
545
+
546
+ // we use alternating line offsets to save on memory allocations
547
+ const line_offset = (y % 2) * pass_line_bytes;
548
+
549
+ png_unfilter(
550
+ filter_type,
551
+ data,
552
+ offset,
553
+ line_bytes_buffer,
554
+ bytes_per_pixel,
555
+ line_offset,
556
+ previous_line_offset,
557
+ pass_line_bytes
558
+ );
559
+
560
+ offset += pass_line_bytes;
561
+ previous_line_offset = line_offset;
562
+
563
+ // below eight bits the reconstruction is still packed, so expand it before scattering
564
+ let source = line_bytes_buffer;
565
+ let source_offset = line_offset;
566
+
567
+ if (packed) {
568
+ png_unpack_samples(line_bytes_buffer, line_offset, depth, pass_samples, sample_buffer, 0);
569
+
570
+ source = sample_buffer;
571
+ source_offset = 0;
572
+ }
573
+
574
+ for (let x = 0; x < pass_width; x++) {
575
+
576
+ const outputX = pass.x + x * pass.xStep;
577
+ const outputY = pass.y + y * pass.yStep;
578
+
579
+ if (outputX >= width || outputY >= height) {
580
+ continue;
581
+ }
582
+
583
+ for (let i = 0; i < output_pixel_bytes; i++) {
584
+ const out_offset = (outputY * width + outputX) * output_pixel_bytes + i;
585
+
586
+ pixels[out_offset] = source[source_offset + x * output_pixel_bytes + i];
587
+ }
588
+ }
589
+ }
590
+ }
591
+
592
+ return pixels;
593
+ };
594
+
595
+ // Unfiltering
596
+
597
+ /**
598
+ * Reconstruct one filtered scanline. Kept as a method so the reader's surface is unchanged; the
599
+ * dispatch itself lives in {@link png_unfilter}.
600
+ *
601
+ * @param {number} filter_type
602
+ * @param {Uint8Array} data
603
+ * @param {number} scanline_address
604
+ * @param {Uint8Array} output
605
+ * @param {number} bytes_per_pixel
606
+ * @param {number} output_offset
607
+ * @param {number} output_offset_previous where does result of previous scanline begin in the output? Needed for various filters such as `Up`
608
+ * @param {number} length
609
+ *
610
+ * @see https://www.w3.org/TR/PNG-Filters.html
611
+ */
612
+ PNGReader.prototype.unFilter = function (
613
+ filter_type,
614
+ data,
615
+ scanline_address,
616
+ output,
617
+ bytes_per_pixel,
618
+ output_offset,
619
+ output_offset_previous,
620
+ length
621
+ ) {
622
+ png_unfilter(
623
+ filter_type,
624
+ data,
625
+ scanline_address,
626
+ output,
627
+ bytes_per_pixel,
628
+ output_offset,
629
+ output_offset_previous,
630
+ length
631
+ );
632
+ }
633
+
634
+ /**
635
635
  * Parse the PNG file. Keep this reader and its input buffer unchanged until the promise settles.
636
636
  * @returns {Promise<PNG>}
637
- */
637
+ */
638
638
  PNGReader.prototype.parse = async function () {
639
-
640
- this.decodeHeader();
641
-
642
- for (; ;) {
643
-
639
+
640
+ this.decodeHeader();
641
+
642
+ for (; ;) {
643
+
644
644
  const type = await this.decodeChunk();
645
-
646
- if (type === 'IEND') {
647
- // reached the end
648
- break;
649
- }
650
-
651
- }
652
-
645
+
646
+ if (type === 'IEND') {
647
+ // reached the end
648
+ break;
649
+ }
650
+
651
+ }
652
+
653
653
  await this.decodePixels();
654
-
655
- return this.png;
656
-
657
- };
654
+
655
+ return this.png;
656
+
657
+ };