@carbonenginejs/runtime-resource 0.12.1 → 0.13.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.
- package/LICENSE +21 -21
- package/NOTICE +32 -32
- package/README.md +129 -108
- package/dist/CjsMotherLode.js +1271 -1271
- package/dist/CjsResMan.js +3858 -3494
- package/dist/CjsResMan.js.map +1 -1
- package/dist/CjsResManFetchProvider.js +94 -94
- package/dist/CjsResManWorkQueue.js +301 -301
- package/dist/_virtual/_rollupPluginBabelHelpers.js +150 -150
- package/dist/format/CjsBlueReader.js +358 -358
- package/dist/format/CjsByteReader.js +310 -310
- package/dist/format/CjsByteWriter.js +242 -242
- package/dist/format/CjsFormat.js +223 -223
- package/dist/format/CjsFormatError.js +41 -41
- package/dist/format/CjsReader.js +22 -22
- package/dist/format/CjsResourceProbe.js +279 -279
- package/dist/format/CjsStringTable.js +268 -268
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js +408 -361
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js.map +1 -1
- package/dist/format/carbonEffect/CjsCarbonEffectWriter.js +373 -373
- package/dist/format/carbonEffect/buildCarbonEffectContainer.js +182 -0
- package/dist/format/carbonEffect/buildCarbonEffectContainer.js.map +1 -0
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js +321 -427
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js.map +1 -1
- package/dist/format/carbonEffect/carbonEffectRecords.js +1147 -955
- package/dist/format/carbonEffect/carbonEffectRecords.js.map +1 -1
- package/dist/format/carbonEffect/carbonEffectResourceTransform.js +197 -0
- package/dist/format/carbonEffect/carbonEffectResourceTransform.js.map +1 -0
- package/dist/format/compareUtf8.js +36 -36
- package/dist/format/effect/effectBodyInventory.js +146 -0
- package/dist/format/effect/effectBodyInventory.js.map +1 -0
- package/dist/format/effect/effectPermutationGraph.js +257 -257
- package/dist/format/effect/effectPermutationGraph.js.map +1 -1
- package/dist/format/effect/sha256.js +114 -114
- package/dist/format/index.js +11 -11
- package/dist/format/payloadContract.js +193 -193
- package/dist/formats/black/CjsBlackFormat.js +310 -292
- package/dist/formats/black/CjsBlackFormat.js.map +1 -1
- package/dist/formats/black/core/CjsBlackBinaryReader.js +260 -260
- package/dist/formats/black/core/CjsBlackPropertyReaders.js +448 -448
- package/dist/formats/black/core/CjsBlackReader.js +764 -764
- package/dist/formats/black/core/CjsBlackSchemaRegistry.js +540 -540
- package/dist/formats/black/core/black-schema-v1-2026-07-23.json.js +4 -4
- package/dist/formats/black/core/blackConstants.js +7 -7
- package/dist/formats/black/core/blackDefinitions.js +10 -10
- package/dist/formats/black/core/blackEnums.js +6 -6
- package/dist/formats/black/core/blackSchema.js +3 -3
- package/dist/formats/black/core/blackVersion.js +22 -22
- package/dist/formats/black/core/helpers.js +199 -199
- package/dist/formats/black/core/schema.js +4 -4
- package/dist/formats/black/index.js +2 -2
- package/dist/formats/bnk/CjsBnkFormat.js +175 -156
- package/dist/formats/bnk/CjsBnkFormat.js.map +1 -1
- package/dist/formats/bnk/core/busNodes.js +252 -0
- package/dist/formats/bnk/core/busNodes.js.map +1 -0
- package/dist/formats/bnk/core/effectNodes.js +147 -0
- package/dist/formats/bnk/core/effectNodes.js.map +1 -0
- package/dist/formats/bnk/core/eventAction.js +416 -305
- package/dist/formats/bnk/core/eventAction.js.map +1 -1
- package/dist/formats/bnk/core/globalSettings.js +215 -0
- package/dist/formats/bnk/core/globalSettings.js.map +1 -0
- package/dist/formats/bnk/core/graph.js +137 -137
- package/dist/formats/bnk/core/helpers.js +512 -480
- package/dist/formats/bnk/core/helpers.js.map +1 -1
- package/dist/formats/bnk/core/musicNodes.js +533 -509
- package/dist/formats/bnk/core/musicNodes.js.map +1 -1
- package/dist/formats/bnk/core/nodeBase.js +553 -532
- package/dist/formats/bnk/core/nodeBase.js.map +1 -1
- package/dist/formats/bnk/core/sfxNodes.js +632 -632
- package/dist/formats/bnk/core/soundbanksInfo.js +209 -209
- package/dist/formats/bnk/index.js +2 -2
- package/dist/formats/cmf/CjsCmfFormat.js +497 -497
- package/dist/formats/cmf/core/binary.js +194 -194
- package/dist/formats/cmf/core/buffers.js +237 -237
- package/dist/formats/cmf/core/constants.js +47 -47
- package/dist/formats/cmf/core/gr2Anim.js +453 -453
- package/dist/formats/cmf/core/helpers.js +318 -318
- package/dist/formats/cmf/core/pack.js +276 -276
- package/dist/formats/cmf/core/schema.js +374 -374
- package/dist/formats/cmf/core/shared.js +277 -277
- package/dist/formats/cmf/core/writer.js +571 -571
- package/dist/formats/cmf/index.js +2 -2
- package/dist/formats/dds/CjsDdsFormat.js +200 -200
- package/dist/formats/dds/core/bc6h.js +298 -298
- package/dist/formats/dds/core/bc7.js +272 -272
- package/dist/formats/dds/core/helpers.js +862 -862
- package/dist/formats/dds/index.js +2 -2
- package/dist/formats/dxbc/CjsDxbcFormat.js +142 -142
- package/dist/formats/dxbc/core/DxbcReader.js +266 -266
- package/dist/formats/dxbc/core/container.js +169 -169
- package/dist/formats/dxbc/core/decoder.js +789 -789
- package/dist/formats/dxbc/core/errors.js +19 -19
- package/dist/formats/dxbc/core/helpers.js +220 -220
- package/dist/formats/dxbc/core/opcodes.js +45 -45
- package/dist/formats/dxbc/core/program.js +91 -91
- package/dist/formats/dxbc/core/signature.js +172 -172
- package/dist/formats/dxbc/index.js +2 -2
- package/dist/formats/fbx/CjsFbxFormat.js +266 -266
- package/dist/formats/fbx/core/helpers.js +3932 -3932
- package/dist/formats/fbx/index.js +2 -2
- package/dist/formats/flac/CjsFlacFormat.js +142 -142
- package/dist/formats/flac/core/helpers.js +315 -315
- package/dist/formats/flac/index.js +2 -2
- package/dist/formats/gif/CjsGifFormat.js +141 -141
- package/dist/formats/gif/core/helpers.js +380 -380
- package/dist/formats/gif/index.js +2 -2
- package/dist/formats/gltf/CjsGltfFormat.js +290 -290
- package/dist/formats/gltf/core/helpers.js +307 -307
- package/dist/formats/gltf/core/json.js +79 -79
- package/dist/formats/gltf/core/parser.js +679 -679
- package/dist/formats/gltf/core/targets.js +173 -173
- package/dist/formats/gltf/index.js +2 -2
- package/dist/formats/gr2/CjsGr2Format.js +289 -289
- package/dist/formats/gr2/core/bitknit2.js +282 -282
- package/dist/formats/gr2/core/curves.js +1047 -1047
- package/dist/formats/gr2/core/gsf.js +72 -72
- package/dist/formats/gr2/core/helpers.js +352 -352
- package/dist/formats/gr2/core/json.js +622 -622
- package/dist/formats/gr2/core/oodle1.js +388 -388
- package/dist/formats/gr2/core/tangents.js +48 -48
- package/dist/formats/gr2/core/targets.js +361 -361
- package/dist/formats/gr2/index.js +2 -2
- package/dist/formats/hlsl/CjsHlslFormat.js +254 -254
- package/dist/formats/hlsl/core/HlslBinaryUtils.js +15 -15
- package/dist/formats/hlsl/core/HlslEffectReadError.js +19 -19
- package/dist/formats/hlsl/core/HlslEffectStateManager.js +130 -130
- package/dist/formats/hlsl/core/HlslRenderStateSetup.js +37 -37
- package/dist/formats/hlsl/core/HlslResourceSetDescription.js +94 -94
- package/dist/formats/hlsl/core/HlslShaderBytecode.js +44 -44
- package/dist/formats/hlsl/core/analysis.js +51 -51
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js +850 -781
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js.map +1 -1
- package/dist/formats/hlsl/core/detailMapFamily.js +128 -0
- package/dist/formats/hlsl/core/detailMapFamily.js.map +1 -0
- package/dist/formats/hlsl/core/helpers.js +270 -270
- package/dist/formats/hlsl/core/json.js +284 -284
- package/dist/formats/hlsl/core/localLightFamily.js +133 -0
- package/dist/formats/hlsl/core/localLightFamily.js.map +1 -0
- package/dist/formats/hlsl/core/metadata.js +327 -327
- package/dist/formats/hlsl/core/render-states.js +280 -280
- package/dist/formats/hlsl/core/tr2/HlslRenderContextEnum.js +43 -43
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +320 -314
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js.map +1 -1
- package/dist/formats/hlsl/core/tr2/resources/HlslShaderPermutation.js +33 -33
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js +416 -416
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectConstant.js +40 -40
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js +62 -742
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js.map +1 -1
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectLibrary.js +52 -52
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectParameterAnnotation.js +38 -38
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectResource.js +50 -50
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectStageInput.js +86 -86
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectTechnique.js +31 -31
- package/dist/formats/hlsl/core/tr2/shader/HlslPass.js +42 -42
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerDescription.js +55 -55
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerSetup.js +29 -29
- package/dist/formats/hlsl/core/tr2/shader/HlslShader.js +220 -220
- package/dist/formats/hlsl/core/tr2/shader/HlslShaderOption.js +30 -30
- package/dist/formats/hlsl/index.js +3 -3
- package/dist/formats/index.js +33 -31
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/jpeg/CjsJpegFormat.js +212 -212
- package/dist/formats/jpeg/core/helpers.js +402 -402
- package/dist/formats/jpeg/core/jpeg.js +480 -480
- package/dist/formats/jpeg/index.js +2 -2
- package/dist/formats/mp3/CjsMp3Format.js +197 -197
- package/dist/formats/mp3/core/helpers.js +375 -375
- package/dist/formats/mp3/index.js +2 -2
- package/dist/formats/mp4/CjsMp4Format.js +197 -197
- package/dist/formats/mp4/core/helpers.js +484 -484
- package/dist/formats/mp4/index.js +2 -2
- package/dist/formats/obj/CjsObjFormat.js +253 -253
- package/dist/formats/obj/core/helpers.js +573 -573
- package/dist/formats/obj/core/json.js +64 -64
- package/dist/formats/obj/core/parser.js +321 -321
- package/dist/formats/obj/index.js +2 -2
- package/dist/formats/ogg/CjsOggFormat.js +143 -143
- package/dist/formats/ogg/core/helpers.js +410 -410
- package/dist/formats/ogg/core/imdct.js +178 -178
- package/dist/formats/ogg/core/vorbis.js +1017 -1017
- package/dist/formats/ogg/index.js +2 -2
- package/dist/formats/pickle/CjsPickleFormat.js +214 -0
- package/dist/formats/pickle/CjsPickleFormat.js.map +1 -0
- package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js +551 -0
- package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js.map +1 -0
- package/dist/formats/pickle/index.js +2 -0
- package/dist/formats/pickle/index.js.map +1 -0
- package/dist/formats/png/CjsPngFormat.js +201 -201
- package/dist/formats/png/core/helpers.js +635 -635
- package/dist/formats/png/index.js +2 -2
- package/dist/formats/red/CjsRedFormat.js +263 -263
- package/dist/formats/red/core/CjsRedReader.js +246 -246
- package/dist/formats/red/core/blackDefinitions.js +3 -3
- package/dist/formats/red/core/helpers.js +158 -158
- package/dist/formats/red/core/redGraph.js +71 -68
- package/dist/formats/red/core/redGraph.js.map +1 -1
- package/dist/formats/red/core/schema.js +4 -4
- package/dist/formats/red/index.js +2 -2
- package/dist/formats/stl/CjsStlFormat.js +365 -365
- package/dist/formats/stl/core/helpers.js +261 -261
- package/dist/formats/stl/core/json.js +51 -51
- package/dist/formats/stl/core/stl.js +642 -642
- package/dist/formats/stl/core/targets.js +173 -173
- package/dist/formats/stl/index.js +2 -2
- package/dist/formats/tga/CjsTgaFormat.js +197 -197
- package/dist/formats/tga/core/helpers.js +493 -493
- package/dist/formats/tga/index.js +2 -2
- package/dist/formats/wav/CjsWavFormat.js +198 -198
- package/dist/formats/wav/core/helpers.js +365 -365
- package/dist/formats/wav/index.js +2 -2
- package/dist/formats/webgl/CjsWebglFormat.js +199 -221
- package/dist/formats/webgl/CjsWebglFormat.js.map +1 -1
- package/dist/formats/webgl/core/buildGlslEffectContainer.js +70 -0
- package/dist/formats/webgl/core/buildGlslEffectContainer.js.map +1 -0
- package/dist/formats/webgl/core/effectPackage.js +900 -792
- package/dist/formats/webgl/core/effectPackage.js.map +1 -1
- package/dist/formats/webgl/core/errors.js +27 -27
- package/dist/formats/webgl/core/errors.js.map +1 -1
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js +2820 -2678
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js.map +1 -1
- package/dist/formats/webgl/core/glsl/DxbcGlslHelpers.js +89 -89
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js +486 -428
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js.map +1 -1
- package/dist/formats/webgl/core/glsl/packedLightFixups.js +98 -0
- package/dist/formats/webgl/core/glsl/packedLightFixups.js.map +1 -0
- package/dist/formats/webgl/core/glslBackendBlock.js +552 -0
- package/dist/formats/webgl/core/glslBackendBlock.js.map +1 -0
- package/dist/formats/webgl/core/glslBackendBodySet.js +243 -0
- package/dist/formats/webgl/core/glslBackendBodySet.js.map +1 -0
- package/dist/formats/webgl/core/{cewgCompleteness.js → glslEffectCompleteness.js} +85 -81
- package/dist/formats/webgl/core/glslEffectCompleteness.js.map +1 -0
- package/dist/formats/webgl/core/helpers.js +167 -306
- package/dist/formats/webgl/core/helpers.js.map +1 -1
- package/dist/formats/webgl/core/inspectGlslEffectContainer.js +122 -0
- package/dist/formats/webgl/core/inspectGlslEffectContainer.js.map +1 -0
- package/dist/formats/webgl/core/readGlslEffectContainer.js +303 -0
- package/dist/formats/webgl/core/readGlslEffectContainer.js.map +1 -0
- package/dist/formats/webgl/index.js +2 -2
- package/dist/formats/webgpu/CjsWebgpuFormat.js +357 -357
- package/dist/formats/webgpu/CjsWebgpuFormat.js.map +1 -1
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js +89 -197
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js.map +1 -1
- package/dist/formats/webgpu/core/{cewgpu/CewgpuContainer.js → carbonWebgpu/CarbonWebgpuContainer.js} +354 -368
- package/dist/formats/webgpu/core/carbonWebgpu/CarbonWebgpuContainer.js.map +1 -0
- package/dist/formats/webgpu/core/{cewgpu → carbonWebgpu}/containerViews.js +355 -355
- package/dist/formats/webgpu/core/carbonWebgpu/containerViews.js.map +1 -0
- package/dist/formats/webgpu/core/{cewgpu → carbonWebgpu}/validateContainer.js +90 -90
- package/dist/formats/webgpu/core/carbonWebgpu/validateContainer.js.map +1 -0
- package/dist/formats/webgpu/core/effectAnalysis.js +82 -82
- package/dist/formats/webgpu/core/effectBackendBodySet.js +289 -289
- package/dist/formats/webgpu/core/effectBackendBodySet.js.map +1 -1
- package/dist/formats/webgpu/core/errors.js +20 -20
- package/dist/formats/webgpu/core/errors.js.map +1 -1
- package/dist/formats/webgpu/core/helpers.js +443 -443
- package/dist/formats/webgpu/core/helpers.js.map +1 -1
- package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js +212 -212
- package/dist/formats/webgpu/core/ir/buildControlFlow.js +220 -220
- package/dist/formats/webgpu/core/ir/indexableTemps.js +137 -137
- package/dist/formats/webgpu/core/ir/inferValueTypes.js +449 -449
- package/dist/formats/webgpu/core/ir/lowerDxbcToIr.js +494 -494
- package/dist/formats/webgpu/core/ir/resolveRegisterFlow.js +177 -177
- package/dist/formats/webgpu/core/ir/sourceLanes.js +61 -61
- package/dist/formats/webgpu/core/packageEffect.js +381 -385
- package/dist/formats/webgpu/core/packageEffect.js.map +1 -1
- package/dist/formats/webgpu/core/packageEffectSelection.js +164 -164
- package/dist/formats/webgpu/core/packageEffectSelection.js.map +1 -1
- package/dist/formats/webgpu/core/packageMetadata.js +17 -17
- package/dist/formats/webgpu/core/schema.js +4 -4
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +263 -263
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js +172 -172
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +320 -320
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/emitWgsl.js +356 -356
- package/dist/formats/webgpu/core/wgsl/hoistEscapingValues.js +77 -77
- package/dist/formats/webgpu/core/wgsl/lowerBindingLayout.js +451 -451
- package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js +735 -735
- package/dist/formats/webgpu/core/wgsl/lowerCreateHistogramsComputeProgram.js +457 -457
- package/dist/formats/webgpu/core/wgsl/lowerFragmentProgram.js +1572 -1572
- package/dist/formats/webgpu/core/wgsl/lowerMergeHistogramsComputeProgram.js +659 -659
- package/dist/formats/webgpu/core/wgsl/lowerParticleClearComputePrograms.js +734 -734
- package/dist/formats/webgpu/core/wgsl/lowerParticleEmitComputeProgram.js +583 -583
- package/dist/formats/webgpu/core/wgsl/lowerSkinVerticesComputeProgram.js +621 -621
- package/dist/formats/webgpu/core/wgsl/lowerSortComputeProgram.js +824 -824
- package/dist/formats/webgpu/core/wgsl/lowerSortInnerComputeProgram.js +697 -697
- package/dist/formats/webgpu/core/wgsl/lowerSortStepComputeProgram.js +559 -559
- package/dist/formats/webgpu/core/wgsl/lowerVertexProgram.js +1328 -1328
- package/dist/formats/webgpu/core/wgsl/particleEmitSemanticDigest.js +110 -110
- package/dist/formats/webgpu/core/wgsl/precisionControls.js +55 -55
- package/dist/formats/webgpu/core/wgsl/selectionPlans.js +717 -717
- package/dist/formats/webgpu/core/wgsl/uniformity.js +78 -78
- package/dist/formats/webgpu/core/wgsl/validateExactComputeIr.js +196 -196
- package/dist/formats/webgpu/core/wgsl/validateHandleOperand.js +37 -37
- package/dist/formats/webgpu/index.js +2 -2
- package/dist/formats/webm/CjsWebmFormat.js +197 -197
- package/dist/formats/webm/core/helpers.js +572 -572
- package/dist/formats/webm/index.js +2 -2
- package/dist/formats/webp/CjsWebpFormat.js +140 -140
- package/dist/formats/webp/core/helpers.js +237 -237
- package/dist/formats/webp/index.js +2 -2
- package/dist/formats/wem/CjsWemFormat.js +250 -250
- package/dist/formats/wem/core/bitStream.js +261 -261
- package/dist/formats/wem/core/codebookLibrary.js +164 -164
- package/dist/formats/wem/core/helpers.js +437 -437
- package/dist/formats/wem/core/packedCodebooksAotuv603.js +30 -30
- package/dist/formats/wem/core/ptadpcm.js +77 -77
- package/dist/formats/wem/core/resolve.js +121 -121
- package/dist/formats/wem/core/wemToOgg.js +485 -485
- package/dist/formats/wem/index.js +2 -2
- package/dist/formats/yaml/CjsYamlFormat.js +134 -134
- package/dist/formats/yaml/CjsYamlFormat.js.map +1 -1
- package/dist/formats/yaml/core/CjsYamlReader.js +400 -402
- package/dist/formats/yaml/core/CjsYamlReader.js.map +1 -1
- package/dist/formats/yaml/core/helpers.js +196 -170
- package/dist/formats/yaml/core/helpers.js.map +1 -1
- package/dist/formats/yaml/index.js +2 -2
- package/dist/index.js +64 -62
- package/dist/index.js.map +1 -1
- package/dist/resource/CjsLoadingObject.js +19 -0
- package/dist/resource/CjsLoadingObject.js.map +1 -0
- package/dist/resource/CjsResource.js +801 -797
- package/dist/resource/CjsResource.js.map +1 -1
- package/dist/resource/ResourceHandlerMode.js +14 -0
- package/dist/resource/ResourceHandlerMode.js.map +1 -0
- package/dist/resource/Tr2LightProfileRes.js +32 -32
- package/dist/resource/audio/AudioGeometryResData.js +47 -47
- package/dist/resource/audio/CjsAudioBufferRes.js +86 -86
- package/dist/resource/audio/CjsAudioRes.js +213 -213
- package/dist/resource/audio/index.js +4 -4
- package/dist/resource/geometry/MeshDecalData.js +37 -37
- package/dist/resource/geometry/MeshDecalLodData.js +34 -34
- package/dist/resource/geometry/TriGeometryRes.js +675 -675
- package/dist/resource/geometry/TriGeometryResAreaData.js +59 -59
- package/dist/resource/geometry/TriGeometryResJointData.js +38 -38
- package/dist/resource/geometry/TriGeometryResLodData.js +88 -88
- package/dist/resource/geometry/TriGeometryResMeshData.js +63 -63
- package/dist/resource/geometry/TriGeometryResSkeletonData.js +34 -34
- package/dist/resource/geometry/TriJointBinding.js +38 -38
- package/dist/resource/geometry/TriMorphTargetGeometryConstants.js +46 -46
- package/dist/resource/geometry/TriRtGeometryConstants.js +88 -88
- package/dist/resource/geometry/granny/GStateBindingCallbackData.js +31 -31
- package/dist/resource/geometry/granny/Tr2GrannyIntersectionResult.js +60 -60
- package/dist/resource/geometry/granny/Tr2GrannyStateRes.js +36 -36
- package/dist/resource/geometry/granny/TriGrannyRes.js +35 -35
- package/dist/resource/geometry/granny/enums.js +10 -10
- package/dist/resource/geometry/granny/index.js +6 -6
- package/dist/resource/geometry/index.js +17 -17
- package/dist/resource/index.js +54 -52
- package/dist/resource/index.js.map +1 -1
- package/dist/resource/resourceBoundary.js +64 -64
- package/dist/resource/shader/Tr2EffectRes.js +336 -431
- package/dist/resource/shader/Tr2EffectRes.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialArea.js +31 -31
- package/dist/resource/shader/Tr2MaterialMesh.js +27 -27
- package/dist/resource/shader/Tr2MaterialRes.js +31 -31
- package/dist/resource/shader/Tr2Shader.js +283 -261
- package/dist/resource/shader/Tr2Shader.js.map +1 -1
- package/dist/resource/shader/Tr2ShaderPermutation.js +43 -43
- package/dist/resource/shader/index.js +17 -17
- package/dist/resource/shader/reflection/Tr2EffectConstant.js +143 -135
- package/dist/resource/shader/reflection/Tr2EffectConstant.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectDefine.js +30 -30
- package/dist/resource/shader/reflection/Tr2EffectDescription.js +114 -109
- package/dist/resource/shader/reflection/Tr2EffectDescription.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js +168 -147
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +125 -105
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectResource.js +120 -86
- package/dist/resource/shader/reflection/Tr2EffectResource.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js +372 -241
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js +78 -68
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2Pass.js +168 -111
- package/dist/resource/shader/reflection/Tr2Pass.js.map +1 -1
- package/dist/resource/shader/reflection/carbonRecordFields.js +159 -0
- package/dist/resource/shader/reflection/carbonRecordFields.js.map +1 -0
- package/dist/resource/shader/reflection/shaderStage.js +22 -0
- package/dist/resource/shader/reflection/shaderStage.js.map +1 -0
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js +135 -77
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js.map +1 -1
- package/dist/resource/texture/CjsTextureArrayRes.js +472 -472
- package/dist/resource/texture/CjsTextureArrayResParameterProxy.js +179 -179
- package/dist/resource/texture/Tr2ImageRes.js +120 -120
- package/dist/resource/texture/Tr2TextureLodManager.js +82 -82
- package/dist/resource/texture/Tr2TextureLodUpdateRequest.js +37 -37
- package/dist/resource/texture/Tr2TexturePackChannel.js +37 -37
- package/dist/resource/texture/Tr2TexturePipeline.js +54 -54
- package/dist/resource/texture/Tr2TexturePipelineParams.js +34 -34
- package/dist/resource/texture/Tr2TexturePipelineStepCompress.js +40 -40
- package/dist/resource/texture/Tr2TexturePipelineStepGenerateMips.js +22 -22
- package/dist/resource/texture/Tr2TexturePipelineStepLimitSize.js +34 -34
- package/dist/resource/texture/Tr2TexturePipelineStepLoad.js +31 -31
- package/dist/resource/texture/Tr2TexturePipelineStepPack.js +43 -43
- package/dist/resource/texture/TriTextureRes.js +359 -359
- package/dist/resource/texture/index.js +15 -15
- package/dist/resource/texture/texturePipelineBehavior.js +308 -308
- package/dist/worker/CjsResManMainThreadLoader.js +89 -87
- package/dist/worker/CjsResManMainThreadLoader.js.map +1 -1
- package/dist/worker/CjsResManWorker.js +218 -217
- package/dist/worker/CjsResManWorker.js.map +1 -1
- package/dist/worker/CjsResManWorkerLoader.js +437 -434
- package/dist/worker/CjsResManWorkerLoader.js.map +1 -1
- package/dist/worker/protocol.js +12 -12
- package/docs/README.md +98 -98
- package/docs/architecture.md +118 -109
- package/docs/concepts/resource-lifecycle.md +226 -225
- package/docs/concepts/shader-resource-model.md +111 -114
- package/docs/concepts/writing-an-engine-adapter.md +115 -115
- package/docs/formats/README.md +138 -136
- package/docs/formats/carbon-effect-container.md +553 -452
- package/docs/formats/dxbc/README.md +68 -68
- package/docs/formats/dxbc/architecture.md +80 -80
- package/docs/formats/dxbc/reference/api.md +77 -77
- package/docs/formats/dxbc/reference/classes/README.md +9 -9
- package/docs/formats/dxbc/reference/decoded-output.md +122 -122
- package/docs/formats/gr2.md +160 -160
- package/docs/formats/hlsl/README.md +54 -54
- package/docs/formats/hlsl/architecture.md +65 -67
- package/docs/formats/hlsl/guides/hydrating-json-output.md +60 -62
- package/docs/formats/hlsl/guides/reading-effects.md +64 -64
- package/docs/formats/hlsl/reference/advanced-analysis.md +61 -66
- package/docs/formats/hlsl/reference/api.md +92 -98
- package/docs/formats/hlsl/reference/classes/README.md +11 -11
- package/docs/formats/hlsl/reference/json-graph.md +97 -100
- package/docs/formats/pickle.md +82 -0
- package/docs/formats/provenance.md +196 -196
- package/docs/formats/stl.md +37 -37
- package/docs/formats/webgl/README.md +115 -57
- package/docs/formats/webgl/architecture.md +69 -70
- package/docs/formats/webgl/carbon-constant-layouts.md +326 -326
- package/docs/formats/webgl/decl-io.md +1234 -1234
- package/docs/formats/webgl/memory-structured.md +890 -871
- package/docs/formats/webgl/reference/classes/README.md +9 -9
- package/docs/formats/webgl/texture-sample.md +964 -964
- package/docs/formats/webgpu/README.md +84 -84
- package/docs/formats/webgpu/architecture.md +95 -96
- package/docs/formats/webgpu/formats/{cewgpu.md → carbon-webgpu.md} +215 -216
- package/docs/formats/webgpu/guides/effect-packaging.md +189 -191
- package/docs/formats/webgpu/reference/api.md +196 -197
- package/docs/formats/webgpu/reference/classes/README.md +9 -9
- package/docs/formats/webgpu/reference/wgsl-compatibility.md +1546 -1543
- package/docs/formats/wwise.md +146 -85
- package/docs/reference/classes/README.md +35 -35
- package/docs/reference/classes/audio.md +30 -30
- package/docs/reference/classes/core.md +216 -206
- package/docs/reference/classes/dropped.md +46 -46
- package/docs/reference/classes/formats.md +944 -952
- package/docs/reference/classes/resources.md +456 -456
- package/docs/reference/classes/texture.md +26 -26
- package/docs/reference/events.md +117 -117
- package/docs/reference/motherlode-cache.md +275 -275
- package/docs/reference/queues.md +194 -110
- package/docs/reference/reload.md +107 -107
- package/docs/reference/texture-arrays.md +113 -113
- package/docs/reference/texture-pipeline.md +53 -53
- package/docs/reference/workers.md +142 -135
- package/docs/roadmap.md +150 -150
- package/format-notices/black/LICENSE +21 -21
- package/format-notices/black/NOTICE +47 -47
- package/format-notices/bnk/LICENSE +21 -21
- package/format-notices/bnk/NOTICE +21 -21
- package/format-notices/cmf/LICENSE +21 -21
- package/format-notices/cmf/NOTICE +36 -36
- package/format-notices/dds/LICENSE +21 -21
- package/format-notices/dds/NOTICE +14 -14
- package/format-notices/dxbc/LICENSE +21 -21
- package/format-notices/dxbc/NOTICE +20 -20
- package/format-notices/fbx/LICENSE +21 -21
- package/format-notices/fbx/NOTICE +14 -14
- package/format-notices/flac/LICENSE +21 -21
- package/format-notices/flac/NOTICE +14 -14
- package/format-notices/gif/LICENSE +21 -21
- package/format-notices/gif/NOTICE +14 -14
- package/format-notices/gltf/LICENSE +21 -21
- package/format-notices/gltf/NOTICE +27 -27
- package/format-notices/gr2/LICENSE +21 -21
- package/format-notices/gr2/NOTICE +60 -60
- package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -93
- package/format-notices/hlsl/LICENSE +21 -21
- package/format-notices/hlsl/NOTICE +25 -25
- package/format-notices/jpeg/LICENSE +21 -21
- package/format-notices/jpeg/NOTICE +14 -14
- package/format-notices/mp3/LICENSE +21 -21
- package/format-notices/mp3/NOTICE +14 -14
- package/format-notices/mp4/LICENSE +21 -21
- package/format-notices/mp4/NOTICE +14 -14
- package/format-notices/obj/LICENSE +21 -21
- package/format-notices/obj/NOTICE +26 -26
- package/format-notices/ogg/LICENSE +21 -21
- package/format-notices/ogg/NOTICE +28 -28
- package/format-notices/png/LICENSE +21 -21
- package/format-notices/png/NOTICE +14 -14
- package/format-notices/red/LICENSE +21 -21
- package/format-notices/red/NOTICE +31 -31
- package/format-notices/stl/LICENSE +21 -21
- package/format-notices/stl/NOTICE +21 -21
- package/format-notices/tga/LICENSE +21 -21
- package/format-notices/tga/NOTICE +14 -14
- package/format-notices/wav/LICENSE +21 -21
- package/format-notices/wav/NOTICE +14 -14
- package/format-notices/webgl/LICENSE +21 -21
- package/format-notices/webgl/NOTICE +35 -35
- package/format-notices/webgpu/LICENSE +21 -21
- package/format-notices/webgpu/NOTICE +31 -31
- package/format-notices/webm/LICENSE +21 -21
- package/format-notices/webm/NOTICE +14 -14
- package/format-notices/webp/LICENSE +21 -21
- package/format-notices/webp/NOTICE +14 -14
- package/format-notices/wem/LICENSE +57 -57
- package/format-notices/wem/NOTICE +33 -33
- package/format-notices/yaml/LICENSE +21 -21
- package/format-notices/yaml/NOTICE +44 -44
- package/package.json +63 -63
- package/dist/format/carbonEffect/carbonDescriptionFromPortable.js +0 -372
- package/dist/format/carbonEffect/carbonDescriptionFromPortable.js.map +0 -1
- package/dist/format/effect/effectReflectionPackage.js +0 -636
- package/dist/format/effect/effectReflectionPackage.js.map +0 -1
- package/dist/formats/hlsl/core/HlslReader.js +0 -16
- package/dist/formats/hlsl/core/HlslReader.js.map +0 -1
- package/dist/formats/hlsl/core/portableReflection.js +0 -848
- package/dist/formats/hlsl/core/portableReflection.js.map +0 -1
- package/dist/formats/hlsl/portable.js +0 -2
- package/dist/formats/hlsl/portable.js.map +0 -1
- package/dist/formats/webgl/core/cewg/CewgPackage.js +0 -340
- package/dist/formats/webgl/core/cewg/CewgPackage.js.map +0 -1
- package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js +0 -104
- package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js.map +0 -1
- package/dist/formats/webgl/core/cewg/binary.js +0 -19
- package/dist/formats/webgl/core/cewg/binary.js.map +0 -1
- package/dist/formats/webgl/core/cewgCompleteness.js.map +0 -1
- package/dist/formats/webgl/core/effectPackageValidation.js +0 -331
- package/dist/formats/webgl/core/effectPackageValidation.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/containerViews.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/validateContainer.js.map +0 -1
- package/dist/resource/shader/portable.js +0 -33
- package/dist/resource/shader/portable.js.map +0 -1
- package/docs/formats/hlsl/reference/portable-reflection.md +0 -141
- package/docs/formats/webgl/effect-reflection.md +0 -127
|
@@ -1,480 +1,480 @@
|
|
|
1
|
-
const ZIGZAG = [0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63];
|
|
2
|
-
const COSINE = Array.from({
|
|
3
|
-
length: 8
|
|
4
|
-
}, (_, x) => Array.from({
|
|
5
|
-
length: 8
|
|
6
|
-
}, (_, u) => Math.cos((2 * x + 1) * u * Math.PI / 16)));
|
|
7
|
-
const SCALE = Array.from({
|
|
8
|
-
length: 8
|
|
9
|
-
}, (_, value) => value === 0 ? 1 / Math.sqrt(2) : 1);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Decodes baseline JPEG bytes into a normalized RGBA payload for the JPEG format
|
|
13
|
-
* reader.
|
|
14
|
-
*/
|
|
15
|
-
function decodeJpegToRgba(bytes, metadata = {}) {
|
|
16
|
-
const decoder = new BaselineJpegDecoder(bytes);
|
|
17
|
-
const image = decoder.decode();
|
|
18
|
-
return {
|
|
19
|
-
payloadType: "rgba",
|
|
20
|
-
sourceFormat: "jpeg",
|
|
21
|
-
mimeType: "image/jpeg",
|
|
22
|
-
containerOnly: false,
|
|
23
|
-
isDecoded: true,
|
|
24
|
-
rgbaDecodeSupported: true,
|
|
25
|
-
width: image.width,
|
|
26
|
-
height: image.height,
|
|
27
|
-
pixelFormat: "rgba8unorm",
|
|
28
|
-
data: image.data,
|
|
29
|
-
strideBytes: image.width * 4,
|
|
30
|
-
origin: "top-left",
|
|
31
|
-
colorSpace: "srgb",
|
|
32
|
-
alphaMode: "opaque",
|
|
33
|
-
metadata: {
|
|
34
|
-
...metadata,
|
|
35
|
-
decoder: "software-baseline"
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Reports whether JPEG metadata is supported by the software decoder for the
|
|
42
|
-
* JPEG format reader.
|
|
43
|
-
*/
|
|
44
|
-
function canDecodeJpeg(metadata = {}) {
|
|
45
|
-
return metadata.sourceFormat === "jpeg" && metadata.precision === 8 && metadata.components >= 1 && metadata.components <= 3 && (metadata.marker === 0xc0 || metadata.marker === 0xc1) && metadata.progressive !== true;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Pure-JS baseline sequential JPEG decoder that parses markers, quantization
|
|
50
|
-
* and Huffman tables, and entropy-coded scans into RGBA pixels.
|
|
51
|
-
*/
|
|
52
|
-
class BaselineJpegDecoder {
|
|
53
|
-
#bytes;
|
|
54
|
-
#offset = 0;
|
|
55
|
-
#quantization = new Map();
|
|
56
|
-
#huffman = new Map();
|
|
57
|
-
#frame = null;
|
|
58
|
-
#scan = null;
|
|
59
|
-
#restartInterval = 0;
|
|
60
|
-
|
|
61
|
-
/** Creates a BaselineJpegDecoder with caller-provided initial state. */
|
|
62
|
-
constructor(bytes) {
|
|
63
|
-
this.#bytes = bytes;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Decodes the current baseline JPEG stream into RGBA pixels for the JPEG
|
|
68
|
-
* decoder.
|
|
69
|
-
*/
|
|
70
|
-
decode() {
|
|
71
|
-
this.readMarker(0xd8);
|
|
72
|
-
while (this.#offset < this.#bytes.length) {
|
|
73
|
-
const marker = this.nextMarker();
|
|
74
|
-
if (marker === 0xd9) break;
|
|
75
|
-
if (marker === 0xda) {
|
|
76
|
-
this.readScanHeader();
|
|
77
|
-
return this.decodeScan();
|
|
78
|
-
}
|
|
79
|
-
if (marker === 0xdb) this.readQuantizationTables();else if (marker === 0xc0 || marker === 0xc1 || marker === 0xc2) this.readFrame(marker);else if (marker === 0xc4) this.readHuffmanTables();else if (marker === 0xdd) this.readRestartInterval();else if (marker >= 0xe0 && marker <= 0xef || marker === 0xfe) this.skipSegment();else if (marker === 0xd8 || marker === 0x01 || marker >= 0xd0 && marker <= 0xd7) continue;else this.skipSegment();
|
|
80
|
-
}
|
|
81
|
-
throw new Error("jpeg: no baseline scan found");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Reads JPEG frame dimensions, sampling, and component metadata for the JPEG
|
|
86
|
-
* decoder.
|
|
87
|
-
*/
|
|
88
|
-
readFrame(marker) {
|
|
89
|
-
const length = this.readU16();
|
|
90
|
-
const precision = this.readU8();
|
|
91
|
-
const height = this.readU16();
|
|
92
|
-
const width = this.readU16();
|
|
93
|
-
const components = this.readU8();
|
|
94
|
-
if (precision !== 8) throw new Error(`jpeg: unsupported sample precision ${precision}`);
|
|
95
|
-
if (!width || !height || !components || components > 3) throw new Error("jpeg: unsupported frame layout");
|
|
96
|
-
const list = [];
|
|
97
|
-
let maxH = 0,
|
|
98
|
-
maxV = 0;
|
|
99
|
-
for (let i = 0; i < components; i++) {
|
|
100
|
-
const id = this.readU8();
|
|
101
|
-
const sampling = this.readU8();
|
|
102
|
-
const component = {
|
|
103
|
-
id,
|
|
104
|
-
h: sampling >>> 4,
|
|
105
|
-
v: sampling & 0x0f,
|
|
106
|
-
quantizationId: this.readU8(),
|
|
107
|
-
dc: 0,
|
|
108
|
-
ac: 0,
|
|
109
|
-
previousDc: 0,
|
|
110
|
-
plane: null,
|
|
111
|
-
planeWidth: 0,
|
|
112
|
-
planeHeight: 0
|
|
113
|
-
};
|
|
114
|
-
if (!component.h || !component.v || component.h > 4 || component.v > 4) {
|
|
115
|
-
throw new Error("jpeg: unsupported component sampling");
|
|
116
|
-
}
|
|
117
|
-
maxH = Math.max(maxH, component.h);
|
|
118
|
-
maxV = Math.max(maxV, component.v);
|
|
119
|
-
list.push(component);
|
|
120
|
-
}
|
|
121
|
-
const consumed = 8 + components * 3;
|
|
122
|
-
if (length !== consumed) this.#offset += Math.max(0, length - consumed);
|
|
123
|
-
if (marker === 0xc2) throw new Error("jpeg: progressive scans are not supported by the software decoder");
|
|
124
|
-
this.#frame = {
|
|
125
|
-
width,
|
|
126
|
-
height,
|
|
127
|
-
precision,
|
|
128
|
-
components: list,
|
|
129
|
-
maxH,
|
|
130
|
-
maxV
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Reads JPEG quantization tables into natural coefficient order for the JPEG
|
|
136
|
-
* decoder.
|
|
137
|
-
*/
|
|
138
|
-
readQuantizationTables() {
|
|
139
|
-
const end = this.#offset + this.readU16() - 2;
|
|
140
|
-
while (this.#offset < end) {
|
|
141
|
-
const info = this.readU8();
|
|
142
|
-
const precision = info >>> 4;
|
|
143
|
-
const id = info & 0x0f;
|
|
144
|
-
if (precision > 1) throw new Error("jpeg: unsupported 16-bit quantization table");
|
|
145
|
-
const table = new Uint16Array(64);
|
|
146
|
-
for (let i = 0; i < 64; i++) table[ZIGZAG[i]] = precision ? this.readU16() : this.readU8();
|
|
147
|
-
this.#quantization.set(id, table);
|
|
148
|
-
}
|
|
149
|
-
this.#offset = end;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Builds JPEG Huffman lookup tables from their canonical definitions for the
|
|
154
|
-
* JPEG decoder.
|
|
155
|
-
*/
|
|
156
|
-
readHuffmanTables() {
|
|
157
|
-
const end = this.#offset + this.readU16() - 2;
|
|
158
|
-
while (this.#offset < end) {
|
|
159
|
-
const info = this.readU8();
|
|
160
|
-
const table = new Array(17).fill(null).map(() => []);
|
|
161
|
-
const counts = [];
|
|
162
|
-
for (let length = 1; length <= 16; length++) counts.push(this.readU8());
|
|
163
|
-
let code = 0;
|
|
164
|
-
let valueIndex = 0;
|
|
165
|
-
for (let length = 1; length <= 16; length++) {
|
|
166
|
-
for (let i = 0; i < counts[length - 1]; i++) {
|
|
167
|
-
table[length].push({
|
|
168
|
-
code,
|
|
169
|
-
value: this.#bytes[this.#offset + valueIndex]
|
|
170
|
-
});
|
|
171
|
-
valueIndex++;
|
|
172
|
-
code++;
|
|
173
|
-
}
|
|
174
|
-
code <<= 1;
|
|
175
|
-
}
|
|
176
|
-
this.#offset += valueIndex;
|
|
177
|
-
this.#huffman.set(`${info >>> 4}:${info & 0x0f}`, table);
|
|
178
|
-
}
|
|
179
|
-
this.#offset = end;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Reads the JPEG restart interval declared by a DRI segment for the JPEG
|
|
184
|
-
* decoder.
|
|
185
|
-
*/
|
|
186
|
-
readRestartInterval() {
|
|
187
|
-
const length = this.readU16();
|
|
188
|
-
if (length !== 4) throw new Error("jpeg: invalid restart interval segment");
|
|
189
|
-
this.#restartInterval = this.readU16();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Reads JPEG scan component and spectral-selection metadata for the JPEG
|
|
194
|
-
* decoder.
|
|
195
|
-
*/
|
|
196
|
-
readScanHeader() {
|
|
197
|
-
const length = this.readU16();
|
|
198
|
-
const count = this.readU8();
|
|
199
|
-
if (!this.#frame || count !== this.#frame.components.length) throw new Error("jpeg: unsupported scan component count");
|
|
200
|
-
const byId = new Map(this.#frame.components.map(component => [component.id, component]));
|
|
201
|
-
for (let i = 0; i < count; i++) {
|
|
202
|
-
const id = this.readU8();
|
|
203
|
-
const tables = this.readU8();
|
|
204
|
-
const component = byId.get(id);
|
|
205
|
-
if (!component) throw new Error(`jpeg: scan references unknown component ${id}`);
|
|
206
|
-
component.dc = tables >>> 4;
|
|
207
|
-
component.ac = tables & 0x0f;
|
|
208
|
-
}
|
|
209
|
-
const spectralStart = this.readU8();
|
|
210
|
-
const spectralEnd = this.readU8();
|
|
211
|
-
const successive = this.readU8();
|
|
212
|
-
if (spectralStart !== 0 || spectralEnd !== 63 || successive !== 0) {
|
|
213
|
-
throw new Error("jpeg: progressive or non-sequential scan is not supported");
|
|
214
|
-
}
|
|
215
|
-
const consumed = 6 + count * 2;
|
|
216
|
-
if (length !== consumed) this.#offset += Math.max(0, length - consumed);
|
|
217
|
-
this.#scan = {
|
|
218
|
-
byId
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Decodes the current JPEG entropy scan into component planes and RGBA
|
|
224
|
-
* pixels for the JPEG decoder.
|
|
225
|
-
*/
|
|
226
|
-
decodeScan() {
|
|
227
|
-
const frame = this.#frame;
|
|
228
|
-
const mcuWidth = 8 * frame.maxH;
|
|
229
|
-
const mcuHeight = 8 * frame.maxV;
|
|
230
|
-
const mcuColumns = Math.ceil(frame.width / mcuWidth);
|
|
231
|
-
const mcuRows = Math.ceil(frame.height / mcuHeight);
|
|
232
|
-
for (const component of frame.components) {
|
|
233
|
-
component.planeWidth = mcuColumns * component.h * 8;
|
|
234
|
-
component.planeHeight = mcuRows * component.v * 8;
|
|
235
|
-
component.plane = new Uint8Array(component.planeWidth * component.planeHeight);
|
|
236
|
-
}
|
|
237
|
-
const reader = new EntropyReader(this.#bytes, this.#offset);
|
|
238
|
-
let mcuIndex = 0;
|
|
239
|
-
for (let row = 0; row < mcuRows; row++) {
|
|
240
|
-
for (let column = 0; column < mcuColumns; column++) {
|
|
241
|
-
for (const component of frame.components) {
|
|
242
|
-
for (let y = 0; y < component.v; y++) {
|
|
243
|
-
for (let x = 0; x < component.h; x++) {
|
|
244
|
-
const block = this.decodeBlock(reader, component);
|
|
245
|
-
const originX = (column * component.h + x) * 8;
|
|
246
|
-
const originY = (row * component.v + y) * 8;
|
|
247
|
-
writeBlock(component.plane, component.planeWidth, originX, originY, block);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
mcuIndex++;
|
|
252
|
-
if (this.#restartInterval && mcuIndex % this.#restartInterval === 0 && mcuIndex < mcuColumns * mcuRows) {
|
|
253
|
-
reader.align();
|
|
254
|
-
reader.consumeRestart();
|
|
255
|
-
for (const component of frame.components) component.previousDc = 0;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const data = new Uint8Array(frame.width * frame.height * 4);
|
|
260
|
-
for (let y = 0; y < frame.height; y++) {
|
|
261
|
-
for (let x = 0; x < frame.width; x++) {
|
|
262
|
-
const offset = (y * frame.width + x) * 4;
|
|
263
|
-
if (frame.components.length === 1) {
|
|
264
|
-
const value = frame.components[0].plane[y * frame.components[0].planeWidth + x];
|
|
265
|
-
data[offset] = value;
|
|
266
|
-
data[offset + 1] = value;
|
|
267
|
-
data[offset + 2] = value;
|
|
268
|
-
} else {
|
|
269
|
-
const yValue = sampleComponent(frame.components[0], x, y, frame.width, frame.height);
|
|
270
|
-
const cb = sampleComponent(frame.components[1], x, y, frame.width, frame.height) - 128;
|
|
271
|
-
const cr = sampleComponent(frame.components[2], x, y, frame.width, frame.height) - 128;
|
|
272
|
-
data[offset] = clampByte(yValue + 1.402 * cr);
|
|
273
|
-
data[offset + 1] = clampByte(yValue - 0.344136 * cb - 0.714136 * cr);
|
|
274
|
-
data[offset + 2] = clampByte(yValue + 1.772 * cb);
|
|
275
|
-
}
|
|
276
|
-
data[offset + 3] = 255;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return {
|
|
280
|
-
width: frame.width,
|
|
281
|
-
height: frame.height,
|
|
282
|
-
data
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Decodes one JPEG coefficient block through inverse quantization and IDCT
|
|
288
|
-
* for the JPEG decoder.
|
|
289
|
-
*/
|
|
290
|
-
decodeBlock(reader, component) {
|
|
291
|
-
const quantization = this.#quantization.get(component.quantizationId);
|
|
292
|
-
const dcTable = this.#huffman.get(`0:${component.dc}`);
|
|
293
|
-
const acTable = this.#huffman.get(`1:${component.ac}`);
|
|
294
|
-
if (!quantization || !dcTable || !acTable) throw new Error("jpeg: missing quantization or Huffman table");
|
|
295
|
-
const coefficients = new Int32Array(64);
|
|
296
|
-
const category = decodeHuffman(reader, dcTable);
|
|
297
|
-
const delta = receiveExtend(reader, category);
|
|
298
|
-
component.previousDc += delta;
|
|
299
|
-
coefficients[0] = component.previousDc;
|
|
300
|
-
let index = 1;
|
|
301
|
-
while (index < 64) {
|
|
302
|
-
const value = decodeHuffman(reader, acTable);
|
|
303
|
-
if (value === 0) break;
|
|
304
|
-
if (value === 0xf0) {
|
|
305
|
-
index += 16;
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
index += value >>> 4;
|
|
309
|
-
if (index >= 64) throw new Error("jpeg: invalid AC coefficient run");
|
|
310
|
-
coefficients[ZIGZAG[index]] = receiveExtend(reader, value & 0x0f);
|
|
311
|
-
index++;
|
|
312
|
-
}
|
|
313
|
-
for (let i = 0; i < 64; i++) coefficients[i] *= quantization[i];
|
|
314
|
-
return inverseDct(coefficients);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Reads an unsigned 8-bit value from the JPEG byte cursor for the JPEG
|
|
319
|
-
* decoder.
|
|
320
|
-
*/
|
|
321
|
-
readU8() {
|
|
322
|
-
if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end of input");
|
|
323
|
-
return this.#bytes[this.#offset++];
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Reads an unsigned 16-bit big-endian value from the JPEG byte cursor for
|
|
328
|
-
* the JPEG decoder.
|
|
329
|
-
*/
|
|
330
|
-
readU16() {
|
|
331
|
-
return this.readU8() << 8 | this.readU8();
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** Consumes and validates an expected JPEG marker for the JPEG decoder. */
|
|
335
|
-
readMarker(expected = null) {
|
|
336
|
-
const marker = this.nextMarker();
|
|
337
|
-
if (expected !== null && marker !== expected) throw new Error("jpeg: missing SOI marker");
|
|
338
|
-
return marker;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/** Scans forward to the next valid JPEG marker byte for the JPEG decoder. */
|
|
342
|
-
nextMarker() {
|
|
343
|
-
while (this.#offset < this.#bytes.length && this.#bytes[this.#offset++] !== 0xff) {
|
|
344
|
-
// Scan forward to the next marker prefix.
|
|
345
|
-
}
|
|
346
|
-
while (this.#offset < this.#bytes.length && this.#bytes[this.#offset] === 0xff) this.#offset++;
|
|
347
|
-
if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end while reading marker");
|
|
348
|
-
return this.#bytes[this.#offset++];
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Advances past the payload of an unhandled JPEG segment for the JPEG
|
|
353
|
-
* decoder.
|
|
354
|
-
*/
|
|
355
|
-
skipSegment() {
|
|
356
|
-
const length = this.readU16();
|
|
357
|
-
if (length < 2 || this.#offset + length - 2 > this.#bytes.length) throw new Error("jpeg: invalid segment length");
|
|
358
|
-
this.#offset += length - 2;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Bit-level reader over JPEG entropy-coded data that handles byte stuffing
|
|
364
|
-
* and restart markers for the baseline decoder.
|
|
365
|
-
*/
|
|
366
|
-
class EntropyReader {
|
|
367
|
-
#bytes;
|
|
368
|
-
#offset;
|
|
369
|
-
#buffer = 0;
|
|
370
|
-
#bits = 0;
|
|
371
|
-
#marker = null;
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Creates a EntropyReader over caller-provided JPEG bytes and reader
|
|
375
|
-
* options.
|
|
376
|
-
*/
|
|
377
|
-
constructor(bytes, offset) {
|
|
378
|
-
this.#bytes = bytes;
|
|
379
|
-
this.#offset = offset;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/** Reads one entropy-coded bit for the JPEG binary reader. */
|
|
383
|
-
readBit() {
|
|
384
|
-
if (!this.#bits) {
|
|
385
|
-
let value = this.#bytes[this.#offset++];
|
|
386
|
-
if (value === 0xff) {
|
|
387
|
-
while (this.#bytes[this.#offset] === 0xff) this.#offset++;
|
|
388
|
-
const marker = this.#bytes[this.#offset++];
|
|
389
|
-
if (marker !== 0x00) {
|
|
390
|
-
this.#marker = marker;
|
|
391
|
-
throw new Error("jpeg: unexpected marker in entropy data");
|
|
392
|
-
}
|
|
393
|
-
value = 0xff;
|
|
394
|
-
}
|
|
395
|
-
if (value === undefined) throw new Error("jpeg: unexpected end in entropy data");
|
|
396
|
-
this.#buffer = value;
|
|
397
|
-
this.#bits = 8;
|
|
398
|
-
}
|
|
399
|
-
return this.#buffer >>> --this.#bits & 1;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Reads the requested number of entropy-coded bits for the JPEG binary
|
|
404
|
-
* reader.
|
|
405
|
-
*/
|
|
406
|
-
readBits(count) {
|
|
407
|
-
let value = 0;
|
|
408
|
-
for (let i = 0; i < count; i++) value = value << 1 | this.readBit();
|
|
409
|
-
return value;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Aligns the entropy cursor to the next byte boundary for the JPEG binary
|
|
414
|
-
* reader.
|
|
415
|
-
*/
|
|
416
|
-
align() {
|
|
417
|
-
this.#bits = 0;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Consumes and validates the next JPEG restart marker for the JPEG binary
|
|
422
|
-
* reader.
|
|
423
|
-
*/
|
|
424
|
-
consumeRestart() {
|
|
425
|
-
while (this.#bytes[this.#offset] === 0xff) this.#offset++;
|
|
426
|
-
const marker = this.#bytes[this.#offset++];
|
|
427
|
-
if (marker < 0xd0 || marker > 0xd7) throw new Error("jpeg: missing restart marker");
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
function decodeHuffman(reader, table) {
|
|
431
|
-
let code = 0;
|
|
432
|
-
for (let length = 1; length <= 16; length++) {
|
|
433
|
-
code = code << 1 | reader.readBit();
|
|
434
|
-
const entry = table[length].find(item => item.code === code);
|
|
435
|
-
if (entry) return entry.value;
|
|
436
|
-
}
|
|
437
|
-
throw new Error("jpeg: invalid Huffman code");
|
|
438
|
-
}
|
|
439
|
-
function receiveExtend(reader, size) {
|
|
440
|
-
if (!size) return 0;
|
|
441
|
-
const value = reader.readBits(size);
|
|
442
|
-
const threshold = 1 << size - 1;
|
|
443
|
-
return value < threshold ? value - ((1 << size) - 1) : value;
|
|
444
|
-
}
|
|
445
|
-
function inverseDct(coefficients) {
|
|
446
|
-
const output = new Uint8Array(64);
|
|
447
|
-
for (let y = 0; y < 8; y++) {
|
|
448
|
-
for (let x = 0; x < 8; x++) {
|
|
449
|
-
let sum = 0;
|
|
450
|
-
for (let v = 0; v < 8; v++) {
|
|
451
|
-
for (let u = 0; u < 8; u++) {
|
|
452
|
-
sum += SCALE[u] * SCALE[v] * coefficients[v * 8 + u] * COSINE[x][u] * COSINE[y][v];
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
output[y * 8 + x] = clampByte(128 + sum / 4);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return output;
|
|
459
|
-
}
|
|
460
|
-
function writeBlock(plane, planeWidth, originX, originY, block) {
|
|
461
|
-
for (let y = 0; y < 8; y++) {
|
|
462
|
-
const targetY = originY + y;
|
|
463
|
-
if (targetY >= plane.length / planeWidth) continue;
|
|
464
|
-
for (let x = 0; x < 8; x++) {
|
|
465
|
-
const targetX = originX + x;
|
|
466
|
-
if (targetX < planeWidth) plane[targetY * planeWidth + targetX] = block[y * 8 + x];
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
function sampleComponent(component, x, y, width, height) {
|
|
471
|
-
const sampleX = Math.min(component.planeWidth - 1, Math.floor(x * component.planeWidth / width));
|
|
472
|
-
const sampleY = Math.min(component.planeHeight - 1, Math.floor(y * component.planeHeight / height));
|
|
473
|
-
return component.plane[sampleY * component.planeWidth + sampleX];
|
|
474
|
-
}
|
|
475
|
-
function clampByte(value) {
|
|
476
|
-
return Math.max(0, Math.min(255, Math.round(value)));
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
export { canDecodeJpeg, decodeJpegToRgba };
|
|
480
|
-
//# sourceMappingURL=jpeg.js.map
|
|
1
|
+
const ZIGZAG = [0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63];
|
|
2
|
+
const COSINE = Array.from({
|
|
3
|
+
length: 8
|
|
4
|
+
}, (_, x) => Array.from({
|
|
5
|
+
length: 8
|
|
6
|
+
}, (_, u) => Math.cos((2 * x + 1) * u * Math.PI / 16)));
|
|
7
|
+
const SCALE = Array.from({
|
|
8
|
+
length: 8
|
|
9
|
+
}, (_, value) => value === 0 ? 1 / Math.sqrt(2) : 1);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Decodes baseline JPEG bytes into a normalized RGBA payload for the JPEG format
|
|
13
|
+
* reader.
|
|
14
|
+
*/
|
|
15
|
+
function decodeJpegToRgba(bytes, metadata = {}) {
|
|
16
|
+
const decoder = new BaselineJpegDecoder(bytes);
|
|
17
|
+
const image = decoder.decode();
|
|
18
|
+
return {
|
|
19
|
+
payloadType: "rgba",
|
|
20
|
+
sourceFormat: "jpeg",
|
|
21
|
+
mimeType: "image/jpeg",
|
|
22
|
+
containerOnly: false,
|
|
23
|
+
isDecoded: true,
|
|
24
|
+
rgbaDecodeSupported: true,
|
|
25
|
+
width: image.width,
|
|
26
|
+
height: image.height,
|
|
27
|
+
pixelFormat: "rgba8unorm",
|
|
28
|
+
data: image.data,
|
|
29
|
+
strideBytes: image.width * 4,
|
|
30
|
+
origin: "top-left",
|
|
31
|
+
colorSpace: "srgb",
|
|
32
|
+
alphaMode: "opaque",
|
|
33
|
+
metadata: {
|
|
34
|
+
...metadata,
|
|
35
|
+
decoder: "software-baseline"
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Reports whether JPEG metadata is supported by the software decoder for the
|
|
42
|
+
* JPEG format reader.
|
|
43
|
+
*/
|
|
44
|
+
function canDecodeJpeg(metadata = {}) {
|
|
45
|
+
return metadata.sourceFormat === "jpeg" && metadata.precision === 8 && metadata.components >= 1 && metadata.components <= 3 && (metadata.marker === 0xc0 || metadata.marker === 0xc1) && metadata.progressive !== true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Pure-JS baseline sequential JPEG decoder that parses markers, quantization
|
|
50
|
+
* and Huffman tables, and entropy-coded scans into RGBA pixels.
|
|
51
|
+
*/
|
|
52
|
+
class BaselineJpegDecoder {
|
|
53
|
+
#bytes;
|
|
54
|
+
#offset = 0;
|
|
55
|
+
#quantization = new Map();
|
|
56
|
+
#huffman = new Map();
|
|
57
|
+
#frame = null;
|
|
58
|
+
#scan = null;
|
|
59
|
+
#restartInterval = 0;
|
|
60
|
+
|
|
61
|
+
/** Creates a BaselineJpegDecoder with caller-provided initial state. */
|
|
62
|
+
constructor(bytes) {
|
|
63
|
+
this.#bytes = bytes;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Decodes the current baseline JPEG stream into RGBA pixels for the JPEG
|
|
68
|
+
* decoder.
|
|
69
|
+
*/
|
|
70
|
+
decode() {
|
|
71
|
+
this.readMarker(0xd8);
|
|
72
|
+
while (this.#offset < this.#bytes.length) {
|
|
73
|
+
const marker = this.nextMarker();
|
|
74
|
+
if (marker === 0xd9) break;
|
|
75
|
+
if (marker === 0xda) {
|
|
76
|
+
this.readScanHeader();
|
|
77
|
+
return this.decodeScan();
|
|
78
|
+
}
|
|
79
|
+
if (marker === 0xdb) this.readQuantizationTables();else if (marker === 0xc0 || marker === 0xc1 || marker === 0xc2) this.readFrame(marker);else if (marker === 0xc4) this.readHuffmanTables();else if (marker === 0xdd) this.readRestartInterval();else if (marker >= 0xe0 && marker <= 0xef || marker === 0xfe) this.skipSegment();else if (marker === 0xd8 || marker === 0x01 || marker >= 0xd0 && marker <= 0xd7) continue;else this.skipSegment();
|
|
80
|
+
}
|
|
81
|
+
throw new Error("jpeg: no baseline scan found");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Reads JPEG frame dimensions, sampling, and component metadata for the JPEG
|
|
86
|
+
* decoder.
|
|
87
|
+
*/
|
|
88
|
+
readFrame(marker) {
|
|
89
|
+
const length = this.readU16();
|
|
90
|
+
const precision = this.readU8();
|
|
91
|
+
const height = this.readU16();
|
|
92
|
+
const width = this.readU16();
|
|
93
|
+
const components = this.readU8();
|
|
94
|
+
if (precision !== 8) throw new Error(`jpeg: unsupported sample precision ${precision}`);
|
|
95
|
+
if (!width || !height || !components || components > 3) throw new Error("jpeg: unsupported frame layout");
|
|
96
|
+
const list = [];
|
|
97
|
+
let maxH = 0,
|
|
98
|
+
maxV = 0;
|
|
99
|
+
for (let i = 0; i < components; i++) {
|
|
100
|
+
const id = this.readU8();
|
|
101
|
+
const sampling = this.readU8();
|
|
102
|
+
const component = {
|
|
103
|
+
id,
|
|
104
|
+
h: sampling >>> 4,
|
|
105
|
+
v: sampling & 0x0f,
|
|
106
|
+
quantizationId: this.readU8(),
|
|
107
|
+
dc: 0,
|
|
108
|
+
ac: 0,
|
|
109
|
+
previousDc: 0,
|
|
110
|
+
plane: null,
|
|
111
|
+
planeWidth: 0,
|
|
112
|
+
planeHeight: 0
|
|
113
|
+
};
|
|
114
|
+
if (!component.h || !component.v || component.h > 4 || component.v > 4) {
|
|
115
|
+
throw new Error("jpeg: unsupported component sampling");
|
|
116
|
+
}
|
|
117
|
+
maxH = Math.max(maxH, component.h);
|
|
118
|
+
maxV = Math.max(maxV, component.v);
|
|
119
|
+
list.push(component);
|
|
120
|
+
}
|
|
121
|
+
const consumed = 8 + components * 3;
|
|
122
|
+
if (length !== consumed) this.#offset += Math.max(0, length - consumed);
|
|
123
|
+
if (marker === 0xc2) throw new Error("jpeg: progressive scans are not supported by the software decoder");
|
|
124
|
+
this.#frame = {
|
|
125
|
+
width,
|
|
126
|
+
height,
|
|
127
|
+
precision,
|
|
128
|
+
components: list,
|
|
129
|
+
maxH,
|
|
130
|
+
maxV
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Reads JPEG quantization tables into natural coefficient order for the JPEG
|
|
136
|
+
* decoder.
|
|
137
|
+
*/
|
|
138
|
+
readQuantizationTables() {
|
|
139
|
+
const end = this.#offset + this.readU16() - 2;
|
|
140
|
+
while (this.#offset < end) {
|
|
141
|
+
const info = this.readU8();
|
|
142
|
+
const precision = info >>> 4;
|
|
143
|
+
const id = info & 0x0f;
|
|
144
|
+
if (precision > 1) throw new Error("jpeg: unsupported 16-bit quantization table");
|
|
145
|
+
const table = new Uint16Array(64);
|
|
146
|
+
for (let i = 0; i < 64; i++) table[ZIGZAG[i]] = precision ? this.readU16() : this.readU8();
|
|
147
|
+
this.#quantization.set(id, table);
|
|
148
|
+
}
|
|
149
|
+
this.#offset = end;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Builds JPEG Huffman lookup tables from their canonical definitions for the
|
|
154
|
+
* JPEG decoder.
|
|
155
|
+
*/
|
|
156
|
+
readHuffmanTables() {
|
|
157
|
+
const end = this.#offset + this.readU16() - 2;
|
|
158
|
+
while (this.#offset < end) {
|
|
159
|
+
const info = this.readU8();
|
|
160
|
+
const table = new Array(17).fill(null).map(() => []);
|
|
161
|
+
const counts = [];
|
|
162
|
+
for (let length = 1; length <= 16; length++) counts.push(this.readU8());
|
|
163
|
+
let code = 0;
|
|
164
|
+
let valueIndex = 0;
|
|
165
|
+
for (let length = 1; length <= 16; length++) {
|
|
166
|
+
for (let i = 0; i < counts[length - 1]; i++) {
|
|
167
|
+
table[length].push({
|
|
168
|
+
code,
|
|
169
|
+
value: this.#bytes[this.#offset + valueIndex]
|
|
170
|
+
});
|
|
171
|
+
valueIndex++;
|
|
172
|
+
code++;
|
|
173
|
+
}
|
|
174
|
+
code <<= 1;
|
|
175
|
+
}
|
|
176
|
+
this.#offset += valueIndex;
|
|
177
|
+
this.#huffman.set(`${info >>> 4}:${info & 0x0f}`, table);
|
|
178
|
+
}
|
|
179
|
+
this.#offset = end;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Reads the JPEG restart interval declared by a DRI segment for the JPEG
|
|
184
|
+
* decoder.
|
|
185
|
+
*/
|
|
186
|
+
readRestartInterval() {
|
|
187
|
+
const length = this.readU16();
|
|
188
|
+
if (length !== 4) throw new Error("jpeg: invalid restart interval segment");
|
|
189
|
+
this.#restartInterval = this.readU16();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Reads JPEG scan component and spectral-selection metadata for the JPEG
|
|
194
|
+
* decoder.
|
|
195
|
+
*/
|
|
196
|
+
readScanHeader() {
|
|
197
|
+
const length = this.readU16();
|
|
198
|
+
const count = this.readU8();
|
|
199
|
+
if (!this.#frame || count !== this.#frame.components.length) throw new Error("jpeg: unsupported scan component count");
|
|
200
|
+
const byId = new Map(this.#frame.components.map(component => [component.id, component]));
|
|
201
|
+
for (let i = 0; i < count; i++) {
|
|
202
|
+
const id = this.readU8();
|
|
203
|
+
const tables = this.readU8();
|
|
204
|
+
const component = byId.get(id);
|
|
205
|
+
if (!component) throw new Error(`jpeg: scan references unknown component ${id}`);
|
|
206
|
+
component.dc = tables >>> 4;
|
|
207
|
+
component.ac = tables & 0x0f;
|
|
208
|
+
}
|
|
209
|
+
const spectralStart = this.readU8();
|
|
210
|
+
const spectralEnd = this.readU8();
|
|
211
|
+
const successive = this.readU8();
|
|
212
|
+
if (spectralStart !== 0 || spectralEnd !== 63 || successive !== 0) {
|
|
213
|
+
throw new Error("jpeg: progressive or non-sequential scan is not supported");
|
|
214
|
+
}
|
|
215
|
+
const consumed = 6 + count * 2;
|
|
216
|
+
if (length !== consumed) this.#offset += Math.max(0, length - consumed);
|
|
217
|
+
this.#scan = {
|
|
218
|
+
byId
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Decodes the current JPEG entropy scan into component planes and RGBA
|
|
224
|
+
* pixels for the JPEG decoder.
|
|
225
|
+
*/
|
|
226
|
+
decodeScan() {
|
|
227
|
+
const frame = this.#frame;
|
|
228
|
+
const mcuWidth = 8 * frame.maxH;
|
|
229
|
+
const mcuHeight = 8 * frame.maxV;
|
|
230
|
+
const mcuColumns = Math.ceil(frame.width / mcuWidth);
|
|
231
|
+
const mcuRows = Math.ceil(frame.height / mcuHeight);
|
|
232
|
+
for (const component of frame.components) {
|
|
233
|
+
component.planeWidth = mcuColumns * component.h * 8;
|
|
234
|
+
component.planeHeight = mcuRows * component.v * 8;
|
|
235
|
+
component.plane = new Uint8Array(component.planeWidth * component.planeHeight);
|
|
236
|
+
}
|
|
237
|
+
const reader = new EntropyReader(this.#bytes, this.#offset);
|
|
238
|
+
let mcuIndex = 0;
|
|
239
|
+
for (let row = 0; row < mcuRows; row++) {
|
|
240
|
+
for (let column = 0; column < mcuColumns; column++) {
|
|
241
|
+
for (const component of frame.components) {
|
|
242
|
+
for (let y = 0; y < component.v; y++) {
|
|
243
|
+
for (let x = 0; x < component.h; x++) {
|
|
244
|
+
const block = this.decodeBlock(reader, component);
|
|
245
|
+
const originX = (column * component.h + x) * 8;
|
|
246
|
+
const originY = (row * component.v + y) * 8;
|
|
247
|
+
writeBlock(component.plane, component.planeWidth, originX, originY, block);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
mcuIndex++;
|
|
252
|
+
if (this.#restartInterval && mcuIndex % this.#restartInterval === 0 && mcuIndex < mcuColumns * mcuRows) {
|
|
253
|
+
reader.align();
|
|
254
|
+
reader.consumeRestart();
|
|
255
|
+
for (const component of frame.components) component.previousDc = 0;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const data = new Uint8Array(frame.width * frame.height * 4);
|
|
260
|
+
for (let y = 0; y < frame.height; y++) {
|
|
261
|
+
for (let x = 0; x < frame.width; x++) {
|
|
262
|
+
const offset = (y * frame.width + x) * 4;
|
|
263
|
+
if (frame.components.length === 1) {
|
|
264
|
+
const value = frame.components[0].plane[y * frame.components[0].planeWidth + x];
|
|
265
|
+
data[offset] = value;
|
|
266
|
+
data[offset + 1] = value;
|
|
267
|
+
data[offset + 2] = value;
|
|
268
|
+
} else {
|
|
269
|
+
const yValue = sampleComponent(frame.components[0], x, y, frame.width, frame.height);
|
|
270
|
+
const cb = sampleComponent(frame.components[1], x, y, frame.width, frame.height) - 128;
|
|
271
|
+
const cr = sampleComponent(frame.components[2], x, y, frame.width, frame.height) - 128;
|
|
272
|
+
data[offset] = clampByte(yValue + 1.402 * cr);
|
|
273
|
+
data[offset + 1] = clampByte(yValue - 0.344136 * cb - 0.714136 * cr);
|
|
274
|
+
data[offset + 2] = clampByte(yValue + 1.772 * cb);
|
|
275
|
+
}
|
|
276
|
+
data[offset + 3] = 255;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
width: frame.width,
|
|
281
|
+
height: frame.height,
|
|
282
|
+
data
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Decodes one JPEG coefficient block through inverse quantization and IDCT
|
|
288
|
+
* for the JPEG decoder.
|
|
289
|
+
*/
|
|
290
|
+
decodeBlock(reader, component) {
|
|
291
|
+
const quantization = this.#quantization.get(component.quantizationId);
|
|
292
|
+
const dcTable = this.#huffman.get(`0:${component.dc}`);
|
|
293
|
+
const acTable = this.#huffman.get(`1:${component.ac}`);
|
|
294
|
+
if (!quantization || !dcTable || !acTable) throw new Error("jpeg: missing quantization or Huffman table");
|
|
295
|
+
const coefficients = new Int32Array(64);
|
|
296
|
+
const category = decodeHuffman(reader, dcTable);
|
|
297
|
+
const delta = receiveExtend(reader, category);
|
|
298
|
+
component.previousDc += delta;
|
|
299
|
+
coefficients[0] = component.previousDc;
|
|
300
|
+
let index = 1;
|
|
301
|
+
while (index < 64) {
|
|
302
|
+
const value = decodeHuffman(reader, acTable);
|
|
303
|
+
if (value === 0) break;
|
|
304
|
+
if (value === 0xf0) {
|
|
305
|
+
index += 16;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
index += value >>> 4;
|
|
309
|
+
if (index >= 64) throw new Error("jpeg: invalid AC coefficient run");
|
|
310
|
+
coefficients[ZIGZAG[index]] = receiveExtend(reader, value & 0x0f);
|
|
311
|
+
index++;
|
|
312
|
+
}
|
|
313
|
+
for (let i = 0; i < 64; i++) coefficients[i] *= quantization[i];
|
|
314
|
+
return inverseDct(coefficients);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Reads an unsigned 8-bit value from the JPEG byte cursor for the JPEG
|
|
319
|
+
* decoder.
|
|
320
|
+
*/
|
|
321
|
+
readU8() {
|
|
322
|
+
if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end of input");
|
|
323
|
+
return this.#bytes[this.#offset++];
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Reads an unsigned 16-bit big-endian value from the JPEG byte cursor for
|
|
328
|
+
* the JPEG decoder.
|
|
329
|
+
*/
|
|
330
|
+
readU16() {
|
|
331
|
+
return this.readU8() << 8 | this.readU8();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** Consumes and validates an expected JPEG marker for the JPEG decoder. */
|
|
335
|
+
readMarker(expected = null) {
|
|
336
|
+
const marker = this.nextMarker();
|
|
337
|
+
if (expected !== null && marker !== expected) throw new Error("jpeg: missing SOI marker");
|
|
338
|
+
return marker;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Scans forward to the next valid JPEG marker byte for the JPEG decoder. */
|
|
342
|
+
nextMarker() {
|
|
343
|
+
while (this.#offset < this.#bytes.length && this.#bytes[this.#offset++] !== 0xff) {
|
|
344
|
+
// Scan forward to the next marker prefix.
|
|
345
|
+
}
|
|
346
|
+
while (this.#offset < this.#bytes.length && this.#bytes[this.#offset] === 0xff) this.#offset++;
|
|
347
|
+
if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end while reading marker");
|
|
348
|
+
return this.#bytes[this.#offset++];
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Advances past the payload of an unhandled JPEG segment for the JPEG
|
|
353
|
+
* decoder.
|
|
354
|
+
*/
|
|
355
|
+
skipSegment() {
|
|
356
|
+
const length = this.readU16();
|
|
357
|
+
if (length < 2 || this.#offset + length - 2 > this.#bytes.length) throw new Error("jpeg: invalid segment length");
|
|
358
|
+
this.#offset += length - 2;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Bit-level reader over JPEG entropy-coded data that handles byte stuffing
|
|
364
|
+
* and restart markers for the baseline decoder.
|
|
365
|
+
*/
|
|
366
|
+
class EntropyReader {
|
|
367
|
+
#bytes;
|
|
368
|
+
#offset;
|
|
369
|
+
#buffer = 0;
|
|
370
|
+
#bits = 0;
|
|
371
|
+
#marker = null;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Creates a EntropyReader over caller-provided JPEG bytes and reader
|
|
375
|
+
* options.
|
|
376
|
+
*/
|
|
377
|
+
constructor(bytes, offset) {
|
|
378
|
+
this.#bytes = bytes;
|
|
379
|
+
this.#offset = offset;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** Reads one entropy-coded bit for the JPEG binary reader. */
|
|
383
|
+
readBit() {
|
|
384
|
+
if (!this.#bits) {
|
|
385
|
+
let value = this.#bytes[this.#offset++];
|
|
386
|
+
if (value === 0xff) {
|
|
387
|
+
while (this.#bytes[this.#offset] === 0xff) this.#offset++;
|
|
388
|
+
const marker = this.#bytes[this.#offset++];
|
|
389
|
+
if (marker !== 0x00) {
|
|
390
|
+
this.#marker = marker;
|
|
391
|
+
throw new Error("jpeg: unexpected marker in entropy data");
|
|
392
|
+
}
|
|
393
|
+
value = 0xff;
|
|
394
|
+
}
|
|
395
|
+
if (value === undefined) throw new Error("jpeg: unexpected end in entropy data");
|
|
396
|
+
this.#buffer = value;
|
|
397
|
+
this.#bits = 8;
|
|
398
|
+
}
|
|
399
|
+
return this.#buffer >>> --this.#bits & 1;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Reads the requested number of entropy-coded bits for the JPEG binary
|
|
404
|
+
* reader.
|
|
405
|
+
*/
|
|
406
|
+
readBits(count) {
|
|
407
|
+
let value = 0;
|
|
408
|
+
for (let i = 0; i < count; i++) value = value << 1 | this.readBit();
|
|
409
|
+
return value;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Aligns the entropy cursor to the next byte boundary for the JPEG binary
|
|
414
|
+
* reader.
|
|
415
|
+
*/
|
|
416
|
+
align() {
|
|
417
|
+
this.#bits = 0;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Consumes and validates the next JPEG restart marker for the JPEG binary
|
|
422
|
+
* reader.
|
|
423
|
+
*/
|
|
424
|
+
consumeRestart() {
|
|
425
|
+
while (this.#bytes[this.#offset] === 0xff) this.#offset++;
|
|
426
|
+
const marker = this.#bytes[this.#offset++];
|
|
427
|
+
if (marker < 0xd0 || marker > 0xd7) throw new Error("jpeg: missing restart marker");
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function decodeHuffman(reader, table) {
|
|
431
|
+
let code = 0;
|
|
432
|
+
for (let length = 1; length <= 16; length++) {
|
|
433
|
+
code = code << 1 | reader.readBit();
|
|
434
|
+
const entry = table[length].find(item => item.code === code);
|
|
435
|
+
if (entry) return entry.value;
|
|
436
|
+
}
|
|
437
|
+
throw new Error("jpeg: invalid Huffman code");
|
|
438
|
+
}
|
|
439
|
+
function receiveExtend(reader, size) {
|
|
440
|
+
if (!size) return 0;
|
|
441
|
+
const value = reader.readBits(size);
|
|
442
|
+
const threshold = 1 << size - 1;
|
|
443
|
+
return value < threshold ? value - ((1 << size) - 1) : value;
|
|
444
|
+
}
|
|
445
|
+
function inverseDct(coefficients) {
|
|
446
|
+
const output = new Uint8Array(64);
|
|
447
|
+
for (let y = 0; y < 8; y++) {
|
|
448
|
+
for (let x = 0; x < 8; x++) {
|
|
449
|
+
let sum = 0;
|
|
450
|
+
for (let v = 0; v < 8; v++) {
|
|
451
|
+
for (let u = 0; u < 8; u++) {
|
|
452
|
+
sum += SCALE[u] * SCALE[v] * coefficients[v * 8 + u] * COSINE[x][u] * COSINE[y][v];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
output[y * 8 + x] = clampByte(128 + sum / 4);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return output;
|
|
459
|
+
}
|
|
460
|
+
function writeBlock(plane, planeWidth, originX, originY, block) {
|
|
461
|
+
for (let y = 0; y < 8; y++) {
|
|
462
|
+
const targetY = originY + y;
|
|
463
|
+
if (targetY >= plane.length / planeWidth) continue;
|
|
464
|
+
for (let x = 0; x < 8; x++) {
|
|
465
|
+
const targetX = originX + x;
|
|
466
|
+
if (targetX < planeWidth) plane[targetY * planeWidth + targetX] = block[y * 8 + x];
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function sampleComponent(component, x, y, width, height) {
|
|
471
|
+
const sampleX = Math.min(component.planeWidth - 1, Math.floor(x * component.planeWidth / width));
|
|
472
|
+
const sampleY = Math.min(component.planeHeight - 1, Math.floor(y * component.planeHeight / height));
|
|
473
|
+
return component.plane[sampleY * component.planeWidth + sampleX];
|
|
474
|
+
}
|
|
475
|
+
function clampByte(value) {
|
|
476
|
+
return Math.max(0, Math.min(255, Math.round(value)));
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export { canDecodeJpeg, decodeJpegToRgba };
|
|
480
|
+
//# sourceMappingURL=jpeg.js.map
|