@carbonenginejs/runtime-resource 0.8.0 → 0.9.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 (259) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +29 -29
  3. package/README.md +67 -548
  4. package/dist/CjsMotherLode.js +1271 -1271
  5. package/dist/CjsResMan.js +3005 -3005
  6. package/dist/CjsResManQueue.js +214 -214
  7. package/dist/CjsResource.js +566 -566
  8. package/dist/CjsResourceSource.js +59 -59
  9. package/dist/_virtual/_rollupPluginBabelHelpers.js +153 -153
  10. package/dist/format/CjsBlueReader.js +269 -269
  11. package/dist/format/CjsFormat.js +192 -192
  12. package/dist/format/CjsReader.js +18 -18
  13. package/dist/format/CjsResourceProbe.js +277 -277
  14. package/dist/format/payloadContract.js +173 -173
  15. package/dist/formats/black/CjsBlackFormat.js +278 -278
  16. package/dist/formats/black/core/CjsBlackBinaryReader.js +153 -153
  17. package/dist/formats/black/core/CjsBlackPropertyReaders.js +382 -382
  18. package/dist/formats/black/core/CjsBlackReader.js +639 -639
  19. package/dist/formats/black/core/CjsBlackSchemaRegistry.js +433 -433
  20. package/dist/formats/black/core/black-schema-v1-2026-07-11.json.js +4 -4
  21. package/dist/formats/black/core/blackConstants.js +7 -7
  22. package/dist/formats/black/core/blackDefinitions.js +10 -10
  23. package/dist/formats/black/core/blackEnums.js +6 -6
  24. package/dist/formats/black/core/blackSchema.js +3 -3
  25. package/dist/formats/black/core/blackVersion.js +22 -22
  26. package/dist/formats/black/core/helpers.js +182 -182
  27. package/dist/formats/black/core/schema.js +4 -4
  28. package/dist/formats/black/index.js +2 -2
  29. package/dist/formats/bnk/CjsBnkFormat.js +125 -125
  30. package/dist/formats/bnk/core/graph.js +140 -140
  31. package/dist/formats/bnk/core/helpers.js +409 -409
  32. package/dist/formats/bnk/core/musicNodes.js +489 -489
  33. package/dist/formats/bnk/core/soundbanksInfo.js +246 -246
  34. package/dist/formats/bnk/index.js +2 -2
  35. package/dist/formats/cmf/CjsCmfFormat.js +497 -497
  36. package/dist/formats/cmf/core/binary.js +118 -118
  37. package/dist/formats/cmf/core/buffers.js +233 -233
  38. package/dist/formats/cmf/core/constants.js +47 -47
  39. package/dist/formats/cmf/core/gr2Anim.js +453 -453
  40. package/dist/formats/cmf/core/helpers.js +287 -287
  41. package/dist/formats/cmf/core/pack.js +276 -276
  42. package/dist/formats/cmf/core/schema.js +364 -364
  43. package/dist/formats/cmf/core/shared.js +268 -268
  44. package/dist/formats/cmf/core/writer.js +517 -517
  45. package/dist/formats/cmf/index.js +2 -2
  46. package/dist/formats/dds/CjsDdsFormat.js +193 -193
  47. package/dist/formats/dds/core/bc6h.js +288 -288
  48. package/dist/formats/dds/core/bc7.js +251 -251
  49. package/dist/formats/dds/core/helpers.js +815 -815
  50. package/dist/formats/dds/index.js +2 -2
  51. package/dist/formats/fbx/CjsFbxFormat.js +266 -266
  52. package/dist/formats/fbx/core/helpers.js +3901 -3901
  53. package/dist/formats/fbx/index.js +2 -2
  54. package/dist/formats/flac/CjsFlacFormat.js +87 -87
  55. package/dist/formats/flac/core/helpers.js +295 -295
  56. package/dist/formats/flac/index.js +2 -2
  57. package/dist/formats/gif/CjsGifFormat.js +87 -87
  58. package/dist/formats/gif/core/helpers.js +360 -360
  59. package/dist/formats/gif/index.js +2 -2
  60. package/dist/formats/gltf/CjsGltfFormat.js +290 -290
  61. package/dist/formats/gltf/core/helpers.js +292 -292
  62. package/dist/formats/gltf/core/json.js +79 -79
  63. package/dist/formats/gltf/core/parser.js +666 -666
  64. package/dist/formats/gltf/core/targets.js +163 -163
  65. package/dist/formats/gltf/index.js +2 -2
  66. package/dist/formats/gr2/CjsGr2Format.js +46 -0
  67. package/dist/formats/gr2/CjsGr2Format.js.map +1 -0
  68. package/dist/formats/gr2/core/CjsFormatGr2.js +273 -0
  69. package/dist/formats/gr2/core/CjsFormatGr2.js.map +1 -0
  70. package/dist/formats/gr2/core/bitknit2.js +280 -0
  71. package/dist/formats/gr2/core/bitknit2.js.map +1 -0
  72. package/dist/formats/gr2/core/curves.js +1047 -0
  73. package/dist/formats/gr2/core/curves.js.map +1 -0
  74. package/dist/formats/gr2/core/gsf.js +72 -0
  75. package/dist/formats/gr2/core/gsf.js.map +1 -0
  76. package/dist/formats/gr2/core/helpers.js +332 -0
  77. package/dist/formats/gr2/core/helpers.js.map +1 -0
  78. package/dist/formats/gr2/core/json.js +622 -0
  79. package/dist/formats/gr2/core/json.js.map +1 -0
  80. package/dist/formats/gr2/core/oodle1.js +388 -0
  81. package/dist/formats/gr2/core/oodle1.js.map +1 -0
  82. package/dist/formats/gr2/core/reader.js +617 -0
  83. package/dist/formats/gr2/core/reader.js.map +1 -0
  84. package/dist/formats/gr2/core/tangents.js +48 -0
  85. package/dist/formats/gr2/core/tangents.js.map +1 -0
  86. package/dist/formats/gr2/core/targets.js +351 -0
  87. package/dist/formats/gr2/core/targets.js.map +1 -0
  88. package/dist/formats/gr2/index.js +3 -0
  89. package/dist/formats/gr2/index.js.map +1 -0
  90. package/dist/formats/index.js +30 -23
  91. package/dist/formats/index.js.map +1 -1
  92. package/dist/formats/jpeg/CjsJpegFormat.js +206 -206
  93. package/dist/formats/jpeg/core/helpers.js +350 -350
  94. package/dist/formats/jpeg/core/jpeg.js +377 -377
  95. package/dist/formats/jpeg/index.js +2 -2
  96. package/dist/formats/mp3/CjsMp3Format.js +192 -192
  97. package/dist/formats/mp3/core/helpers.js +338 -338
  98. package/dist/formats/mp3/index.js +2 -2
  99. package/dist/formats/mp4/CjsMp4Format.js +191 -191
  100. package/dist/formats/mp4/core/helpers.js +449 -449
  101. package/dist/formats/mp4/index.js +2 -2
  102. package/dist/formats/obj/CjsObjFormat.js +253 -253
  103. package/dist/formats/obj/core/helpers.js +573 -573
  104. package/dist/formats/obj/core/json.js +64 -64
  105. package/dist/formats/obj/core/parser.js +321 -321
  106. package/dist/formats/obj/index.js +2 -2
  107. package/dist/formats/ogg/CjsOggFormat.js +88 -88
  108. package/dist/formats/ogg/core/helpers.js +387 -387
  109. package/dist/formats/ogg/core/imdct.js +178 -178
  110. package/dist/formats/ogg/core/vorbis.js +999 -999
  111. package/dist/formats/ogg/index.js +2 -2
  112. package/dist/formats/png/CjsPngFormat.js +195 -195
  113. package/dist/formats/png/core/helpers.js +583 -583
  114. package/dist/formats/png/index.js +2 -2
  115. package/dist/formats/red/CjsRedFormat.js +261 -261
  116. package/dist/formats/red/core/CjsRedReader.js +194 -194
  117. package/dist/formats/red/core/blackDefinitions.js +3 -3
  118. package/dist/formats/red/core/helpers.js +139 -139
  119. package/dist/formats/red/core/redGraph.js +68 -68
  120. package/dist/formats/red/core/schema.js +4 -4
  121. package/dist/formats/red/index.js +2 -2
  122. package/dist/formats/stl/CjsStlFormat.js +365 -365
  123. package/dist/formats/stl/core/helpers.js +261 -261
  124. package/dist/formats/stl/core/json.js +51 -51
  125. package/dist/formats/stl/core/stl.js +629 -629
  126. package/dist/formats/stl/core/targets.js +163 -163
  127. package/dist/formats/stl/index.js +2 -2
  128. package/dist/formats/tga/CjsTgaFormat.js +192 -192
  129. package/dist/formats/tga/core/helpers.js +446 -446
  130. package/dist/formats/tga/index.js +2 -2
  131. package/dist/formats/wav/CjsWavFormat.js +192 -192
  132. package/dist/formats/wav/core/helpers.js +328 -328
  133. package/dist/formats/wav/index.js +2 -2
  134. package/dist/formats/webm/CjsWebmFormat.js +191 -191
  135. package/dist/formats/webm/core/helpers.js +537 -537
  136. package/dist/formats/webm/index.js +2 -2
  137. package/dist/formats/webp/CjsWebpFormat.js +86 -86
  138. package/dist/formats/webp/core/helpers.js +214 -214
  139. package/dist/formats/webp/index.js +2 -2
  140. package/dist/formats/wem/CjsWemFormat.js +241 -241
  141. package/dist/formats/wem/core/bitStream.js +259 -259
  142. package/dist/formats/wem/core/codebookLibrary.js +164 -164
  143. package/dist/formats/wem/core/helpers.js +417 -417
  144. package/dist/formats/wem/core/packedCodebooksAotuv603.js +30 -30
  145. package/dist/formats/wem/core/ptadpcm.js +77 -77
  146. package/dist/formats/wem/core/resolve.js +121 -121
  147. package/dist/formats/wem/core/wemToOgg.js +485 -485
  148. package/dist/formats/wem/index.js +2 -2
  149. package/dist/formats/yaml/CjsYamlFormat.js +83 -83
  150. package/dist/formats/yaml/core/CjsYamlReader.js +305 -305
  151. package/dist/formats/yaml/core/helpers.js +160 -160
  152. package/dist/formats/yaml/index.js +2 -2
  153. package/dist/index.js +49 -48
  154. package/dist/index.js.map +1 -1
  155. package/dist/resourcePath.js +18 -18
  156. package/dist/resourceStates.js +9 -9
  157. package/dist/resources/AudioGeometryResData.js +47 -47
  158. package/dist/resources/GStateBindingCallbackData.js +31 -31
  159. package/dist/resources/MeshDecalData.js +37 -37
  160. package/dist/resources/MeshDecalLodData.js +34 -34
  161. package/dist/resources/Tr2EffectRes.js +71 -71
  162. package/dist/resources/Tr2GrannyIntersectionResult.js +60 -60
  163. package/dist/resources/Tr2GrannyStateRes.js +44 -44
  164. package/dist/resources/Tr2ImageRes.js +114 -114
  165. package/dist/resources/Tr2LightProfileRes.js +40 -40
  166. package/dist/resources/Tr2MaterialArea.js +34 -34
  167. package/dist/resources/Tr2MaterialMesh.js +31 -31
  168. package/dist/resources/Tr2MaterialRes.js +34 -34
  169. package/dist/resources/Tr2ShaderPermutation.js +43 -43
  170. package/dist/resources/Tr2TextureLodManager.js +80 -80
  171. package/dist/resources/Tr2TextureLodUpdateRequest.js +37 -37
  172. package/dist/resources/Tr2TexturePackChannel.js +37 -37
  173. package/dist/resources/Tr2TexturePipeline.js +52 -52
  174. package/dist/resources/Tr2TexturePipelineParams.js +34 -34
  175. package/dist/resources/Tr2TexturePipelineStepCompress.js +40 -40
  176. package/dist/resources/Tr2TexturePipelineStepGenerateMips.js +22 -0
  177. package/dist/resources/Tr2TexturePipelineStepGenerateMips.js.map +1 -0
  178. package/dist/resources/Tr2TexturePipelineStepLimitSize.js +34 -34
  179. package/dist/resources/Tr2TexturePipelineStepLoad.js +31 -31
  180. package/dist/resources/Tr2TexturePipelineStepPack.js +43 -43
  181. package/dist/resources/TriGeometryRes.js +239 -239
  182. package/dist/resources/TriGeometryResAreaData.js +59 -59
  183. package/dist/resources/TriGeometryResJointData.js +38 -38
  184. package/dist/resources/TriGeometryResLodData.js +88 -88
  185. package/dist/resources/TriGeometryResMeshData.js +63 -63
  186. package/dist/resources/TriGeometryResSkeletonData.js +34 -34
  187. package/dist/resources/TriGrannyRes.js +43 -43
  188. package/dist/resources/TriJointBinding.js +38 -38
  189. package/dist/resources/TriMorphTargetGeometryConstants.js +46 -46
  190. package/dist/resources/TriRtGeometryConstants.js +88 -88
  191. package/dist/resources/TriTextureRes.js +304 -304
  192. package/dist/resources/enums.js +18 -18
  193. package/dist/resources/resourceBoundary.js +47 -47
  194. package/dist/resources/texturePipelineBehavior.js +308 -308
  195. package/dist/texture/CjsTextureArrayRes.js +406 -406
  196. package/dist/texture/CjsTextureParameterProxy.js +133 -133
  197. package/docs/README.md +69 -0
  198. package/docs/architecture.md +86 -0
  199. package/docs/concepts/resource-lifecycle.md +217 -0
  200. package/docs/formats/README.md +104 -0
  201. package/{FORMAT-PROVENANCE.md → docs/formats/provenance.md} +173 -155
  202. package/docs/formats/stl.md +37 -0
  203. package/docs/formats/wwise.md +44 -0
  204. package/docs/reference/events.md +92 -0
  205. package/docs/reference/motherlode-cache.md +244 -0
  206. package/docs/reference/queues.md +102 -0
  207. package/docs/reference/reload.md +107 -0
  208. package/docs/reference/texture-arrays.md +113 -0
  209. package/docs/reference/texture-pipeline.md +53 -0
  210. package/docs/roadmap.md +104 -0
  211. package/format-notices/black/LICENSE +21 -21
  212. package/format-notices/black/NOTICE +47 -47
  213. package/format-notices/bnk/LICENSE +21 -21
  214. package/format-notices/bnk/NOTICE +20 -20
  215. package/format-notices/cmf/LICENSE +21 -21
  216. package/format-notices/cmf/NOTICE +36 -36
  217. package/format-notices/dds/LICENSE +21 -21
  218. package/format-notices/dds/NOTICE +14 -14
  219. package/format-notices/fbx/LICENSE +21 -21
  220. package/format-notices/fbx/NOTICE +14 -14
  221. package/format-notices/flac/LICENSE +21 -21
  222. package/format-notices/flac/NOTICE +14 -14
  223. package/format-notices/gif/LICENSE +21 -21
  224. package/format-notices/gif/NOTICE +14 -14
  225. package/format-notices/gltf/LICENSE +21 -21
  226. package/format-notices/gltf/NOTICE +27 -27
  227. package/format-notices/gr2/LICENSE +21 -0
  228. package/format-notices/gr2/NOTICE +60 -0
  229. package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -0
  230. package/format-notices/jpeg/LICENSE +21 -21
  231. package/format-notices/jpeg/NOTICE +14 -14
  232. package/format-notices/mp3/LICENSE +21 -21
  233. package/format-notices/mp3/NOTICE +14 -14
  234. package/format-notices/mp4/LICENSE +21 -21
  235. package/format-notices/mp4/NOTICE +14 -14
  236. package/format-notices/obj/LICENSE +21 -21
  237. package/format-notices/obj/NOTICE +26 -26
  238. package/format-notices/ogg/LICENSE +21 -21
  239. package/format-notices/ogg/NOTICE +28 -28
  240. package/format-notices/png/LICENSE +21 -21
  241. package/format-notices/png/NOTICE +14 -14
  242. package/format-notices/red/LICENSE +21 -21
  243. package/format-notices/red/NOTICE +31 -31
  244. package/format-notices/stl/LICENSE +21 -21
  245. package/format-notices/stl/NOTICE +21 -21
  246. package/format-notices/tga/LICENSE +21 -21
  247. package/format-notices/tga/NOTICE +14 -14
  248. package/format-notices/wav/LICENSE +21 -21
  249. package/format-notices/wav/NOTICE +14 -14
  250. package/format-notices/webm/LICENSE +21 -21
  251. package/format-notices/webm/NOTICE +14 -14
  252. package/format-notices/webp/LICENSE +21 -21
  253. package/format-notices/webp/NOTICE +14 -14
  254. package/format-notices/wem/LICENSE +57 -57
  255. package/format-notices/wem/NOTICE +33 -33
  256. package/format-notices/yaml/LICENSE +21 -21
  257. package/format-notices/yaml/NOTICE +44 -44
  258. package/package.json +52 -51
  259. package/resource-lifecycle.md +0 -679
@@ -1,377 +1,377 @@
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
- function decodeJpegToRgba(bytes, metadata = {}) {
11
- const decoder = new BaselineJpegDecoder(bytes);
12
- const image = decoder.decode();
13
- return {
14
- payloadType: "rgba",
15
- sourceFormat: "jpeg",
16
- mimeType: "image/jpeg",
17
- containerOnly: false,
18
- isDecoded: true,
19
- rgbaDecodeSupported: true,
20
- width: image.width,
21
- height: image.height,
22
- pixelFormat: "rgba8unorm",
23
- data: image.data,
24
- strideBytes: image.width * 4,
25
- origin: "top-left",
26
- colorSpace: "srgb",
27
- alphaMode: "opaque",
28
- metadata: {
29
- ...metadata,
30
- decoder: "software-baseline"
31
- }
32
- };
33
- }
34
- function canDecodeJpeg(metadata = {}) {
35
- return metadata.sourceFormat === "jpeg" && metadata.precision === 8 && metadata.components >= 1 && metadata.components <= 3 && (metadata.marker === 0xc0 || metadata.marker === 0xc1) && metadata.progressive !== true;
36
- }
37
- class BaselineJpegDecoder {
38
- #bytes;
39
- #offset = 0;
40
- #quantization = new Map();
41
- #huffman = new Map();
42
- #frame = null;
43
- #scan = null;
44
- #restartInterval = 0;
45
- constructor(bytes) {
46
- this.#bytes = bytes;
47
- }
48
- decode() {
49
- this.readMarker(0xd8);
50
- while (this.#offset < this.#bytes.length) {
51
- const marker = this.nextMarker();
52
- if (marker === 0xd9) break;
53
- if (marker === 0xda) {
54
- this.readScanHeader();
55
- return this.decodeScan();
56
- }
57
- 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();
58
- }
59
- throw new Error("jpeg: no baseline scan found");
60
- }
61
- readFrame(marker) {
62
- const length = this.readU16();
63
- const precision = this.readU8();
64
- const height = this.readU16();
65
- const width = this.readU16();
66
- const components = this.readU8();
67
- if (precision !== 8) throw new Error(`jpeg: unsupported sample precision ${precision}`);
68
- if (!width || !height || !components || components > 3) throw new Error("jpeg: unsupported frame layout");
69
- const list = [];
70
- let maxH = 0,
71
- maxV = 0;
72
- for (let i = 0; i < components; i++) {
73
- const id = this.readU8();
74
- const sampling = this.readU8();
75
- const component = {
76
- id,
77
- h: sampling >>> 4,
78
- v: sampling & 0x0f,
79
- quantizationId: this.readU8(),
80
- dc: 0,
81
- ac: 0,
82
- previousDc: 0,
83
- plane: null,
84
- planeWidth: 0,
85
- planeHeight: 0
86
- };
87
- if (!component.h || !component.v || component.h > 4 || component.v > 4) {
88
- throw new Error("jpeg: unsupported component sampling");
89
- }
90
- maxH = Math.max(maxH, component.h);
91
- maxV = Math.max(maxV, component.v);
92
- list.push(component);
93
- }
94
- const consumed = 8 + components * 3;
95
- if (length !== consumed) this.#offset += Math.max(0, length - consumed);
96
- if (marker === 0xc2) throw new Error("jpeg: progressive scans are not supported by the software decoder");
97
- this.#frame = {
98
- width,
99
- height,
100
- precision,
101
- components: list,
102
- maxH,
103
- maxV
104
- };
105
- }
106
- readQuantizationTables() {
107
- const end = this.#offset + this.readU16() - 2;
108
- while (this.#offset < end) {
109
- const info = this.readU8();
110
- const precision = info >>> 4;
111
- const id = info & 0x0f;
112
- if (precision > 1) throw new Error("jpeg: unsupported 16-bit quantization table");
113
- const table = new Uint16Array(64);
114
- for (let i = 0; i < 64; i++) table[ZIGZAG[i]] = precision ? this.readU16() : this.readU8();
115
- this.#quantization.set(id, table);
116
- }
117
- this.#offset = end;
118
- }
119
- readHuffmanTables() {
120
- const end = this.#offset + this.readU16() - 2;
121
- while (this.#offset < end) {
122
- const info = this.readU8();
123
- const table = new Array(17).fill(null).map(() => []);
124
- const counts = [];
125
- for (let length = 1; length <= 16; length++) counts.push(this.readU8());
126
- let code = 0;
127
- let valueIndex = 0;
128
- for (let length = 1; length <= 16; length++) {
129
- for (let i = 0; i < counts[length - 1]; i++) {
130
- table[length].push({
131
- code,
132
- value: this.#bytes[this.#offset + valueIndex]
133
- });
134
- valueIndex++;
135
- code++;
136
- }
137
- code <<= 1;
138
- }
139
- this.#offset += valueIndex;
140
- this.#huffman.set(`${info >>> 4}:${info & 0x0f}`, table);
141
- }
142
- this.#offset = end;
143
- }
144
- readRestartInterval() {
145
- const length = this.readU16();
146
- if (length !== 4) throw new Error("jpeg: invalid restart interval segment");
147
- this.#restartInterval = this.readU16();
148
- }
149
- readScanHeader() {
150
- const length = this.readU16();
151
- const count = this.readU8();
152
- if (!this.#frame || count !== this.#frame.components.length) throw new Error("jpeg: unsupported scan component count");
153
- const byId = new Map(this.#frame.components.map(component => [component.id, component]));
154
- for (let i = 0; i < count; i++) {
155
- const id = this.readU8();
156
- const tables = this.readU8();
157
- const component = byId.get(id);
158
- if (!component) throw new Error(`jpeg: scan references unknown component ${id}`);
159
- component.dc = tables >>> 4;
160
- component.ac = tables & 0x0f;
161
- }
162
- const spectralStart = this.readU8();
163
- const spectralEnd = this.readU8();
164
- const successive = this.readU8();
165
- if (spectralStart !== 0 || spectralEnd !== 63 || successive !== 0) {
166
- throw new Error("jpeg: progressive or non-sequential scan is not supported");
167
- }
168
- const consumed = 6 + count * 2;
169
- if (length !== consumed) this.#offset += Math.max(0, length - consumed);
170
- this.#scan = {
171
- byId
172
- };
173
- }
174
- decodeScan() {
175
- const frame = this.#frame;
176
- const mcuWidth = 8 * frame.maxH;
177
- const mcuHeight = 8 * frame.maxV;
178
- const mcuColumns = Math.ceil(frame.width / mcuWidth);
179
- const mcuRows = Math.ceil(frame.height / mcuHeight);
180
- for (const component of frame.components) {
181
- component.planeWidth = mcuColumns * component.h * 8;
182
- component.planeHeight = mcuRows * component.v * 8;
183
- component.plane = new Uint8Array(component.planeWidth * component.planeHeight);
184
- }
185
- const reader = new EntropyReader(this.#bytes, this.#offset);
186
- let mcuIndex = 0;
187
- for (let row = 0; row < mcuRows; row++) {
188
- for (let column = 0; column < mcuColumns; column++) {
189
- for (const component of frame.components) {
190
- for (let y = 0; y < component.v; y++) {
191
- for (let x = 0; x < component.h; x++) {
192
- const block = this.decodeBlock(reader, component);
193
- const originX = (column * component.h + x) * 8;
194
- const originY = (row * component.v + y) * 8;
195
- writeBlock(component.plane, component.planeWidth, originX, originY, block);
196
- }
197
- }
198
- }
199
- mcuIndex++;
200
- if (this.#restartInterval && mcuIndex % this.#restartInterval === 0 && mcuIndex < mcuColumns * mcuRows) {
201
- reader.align();
202
- reader.consumeRestart();
203
- for (const component of frame.components) component.previousDc = 0;
204
- }
205
- }
206
- }
207
- const data = new Uint8Array(frame.width * frame.height * 4);
208
- for (let y = 0; y < frame.height; y++) {
209
- for (let x = 0; x < frame.width; x++) {
210
- const offset = (y * frame.width + x) * 4;
211
- if (frame.components.length === 1) {
212
- const value = frame.components[0].plane[y * frame.components[0].planeWidth + x];
213
- data[offset] = value;
214
- data[offset + 1] = value;
215
- data[offset + 2] = value;
216
- } else {
217
- const yValue = sampleComponent(frame.components[0], x, y, frame.width, frame.height);
218
- const cb = sampleComponent(frame.components[1], x, y, frame.width, frame.height) - 128;
219
- const cr = sampleComponent(frame.components[2], x, y, frame.width, frame.height) - 128;
220
- data[offset] = clampByte(yValue + 1.402 * cr);
221
- data[offset + 1] = clampByte(yValue - 0.344136 * cb - 0.714136 * cr);
222
- data[offset + 2] = clampByte(yValue + 1.772 * cb);
223
- }
224
- data[offset + 3] = 255;
225
- }
226
- }
227
- return {
228
- width: frame.width,
229
- height: frame.height,
230
- data
231
- };
232
- }
233
- decodeBlock(reader, component) {
234
- const quantization = this.#quantization.get(component.quantizationId);
235
- const dcTable = this.#huffman.get(`0:${component.dc}`);
236
- const acTable = this.#huffman.get(`1:${component.ac}`);
237
- if (!quantization || !dcTable || !acTable) throw new Error("jpeg: missing quantization or Huffman table");
238
- const coefficients = new Int32Array(64);
239
- const category = decodeHuffman(reader, dcTable);
240
- const delta = receiveExtend(reader, category);
241
- component.previousDc += delta;
242
- coefficients[0] = component.previousDc;
243
- let index = 1;
244
- while (index < 64) {
245
- const value = decodeHuffman(reader, acTable);
246
- if (value === 0) break;
247
- if (value === 0xf0) {
248
- index += 16;
249
- continue;
250
- }
251
- index += value >>> 4;
252
- if (index >= 64) throw new Error("jpeg: invalid AC coefficient run");
253
- coefficients[ZIGZAG[index]] = receiveExtend(reader, value & 0x0f);
254
- index++;
255
- }
256
- for (let i = 0; i < 64; i++) coefficients[i] *= quantization[i];
257
- return inverseDct(coefficients);
258
- }
259
- readU8() {
260
- if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end of input");
261
- return this.#bytes[this.#offset++];
262
- }
263
- readU16() {
264
- return this.readU8() << 8 | this.readU8();
265
- }
266
- readMarker(expected = null) {
267
- const marker = this.nextMarker();
268
- if (expected !== null && marker !== expected) throw new Error("jpeg: missing SOI marker");
269
- return marker;
270
- }
271
- nextMarker() {
272
- while (this.#offset < this.#bytes.length && this.#bytes[this.#offset++] !== 0xff) {
273
- // Scan forward to the next marker prefix.
274
- }
275
- while (this.#offset < this.#bytes.length && this.#bytes[this.#offset] === 0xff) this.#offset++;
276
- if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end while reading marker");
277
- return this.#bytes[this.#offset++];
278
- }
279
- skipSegment() {
280
- const length = this.readU16();
281
- if (length < 2 || this.#offset + length - 2 > this.#bytes.length) throw new Error("jpeg: invalid segment length");
282
- this.#offset += length - 2;
283
- }
284
- }
285
- class EntropyReader {
286
- #bytes;
287
- #offset;
288
- #buffer = 0;
289
- #bits = 0;
290
- #marker = null;
291
- constructor(bytes, offset) {
292
- this.#bytes = bytes;
293
- this.#offset = offset;
294
- }
295
- readBit() {
296
- if (!this.#bits) {
297
- let value = this.#bytes[this.#offset++];
298
- if (value === 0xff) {
299
- while (this.#bytes[this.#offset] === 0xff) this.#offset++;
300
- const marker = this.#bytes[this.#offset++];
301
- if (marker !== 0x00) {
302
- this.#marker = marker;
303
- throw new Error("jpeg: unexpected marker in entropy data");
304
- }
305
- value = 0xff;
306
- }
307
- if (value === undefined) throw new Error("jpeg: unexpected end in entropy data");
308
- this.#buffer = value;
309
- this.#bits = 8;
310
- }
311
- return this.#buffer >>> --this.#bits & 1;
312
- }
313
- readBits(count) {
314
- let value = 0;
315
- for (let i = 0; i < count; i++) value = value << 1 | this.readBit();
316
- return value;
317
- }
318
- align() {
319
- this.#bits = 0;
320
- }
321
- consumeRestart() {
322
- while (this.#bytes[this.#offset] === 0xff) this.#offset++;
323
- const marker = this.#bytes[this.#offset++];
324
- if (marker < 0xd0 || marker > 0xd7) throw new Error("jpeg: missing restart marker");
325
- }
326
- }
327
- function decodeHuffman(reader, table) {
328
- let code = 0;
329
- for (let length = 1; length <= 16; length++) {
330
- code = code << 1 | reader.readBit();
331
- const entry = table[length].find(item => item.code === code);
332
- if (entry) return entry.value;
333
- }
334
- throw new Error("jpeg: invalid Huffman code");
335
- }
336
- function receiveExtend(reader, size) {
337
- if (!size) return 0;
338
- const value = reader.readBits(size);
339
- const threshold = 1 << size - 1;
340
- return value < threshold ? value - ((1 << size) - 1) : value;
341
- }
342
- function inverseDct(coefficients) {
343
- const output = new Uint8Array(64);
344
- for (let y = 0; y < 8; y++) {
345
- for (let x = 0; x < 8; x++) {
346
- let sum = 0;
347
- for (let v = 0; v < 8; v++) {
348
- for (let u = 0; u < 8; u++) {
349
- sum += SCALE[u] * SCALE[v] * coefficients[v * 8 + u] * COSINE[x][u] * COSINE[y][v];
350
- }
351
- }
352
- output[y * 8 + x] = clampByte(128 + sum / 4);
353
- }
354
- }
355
- return output;
356
- }
357
- function writeBlock(plane, planeWidth, originX, originY, block) {
358
- for (let y = 0; y < 8; y++) {
359
- const targetY = originY + y;
360
- if (targetY >= plane.length / planeWidth) continue;
361
- for (let x = 0; x < 8; x++) {
362
- const targetX = originX + x;
363
- if (targetX < planeWidth) plane[targetY * planeWidth + targetX] = block[y * 8 + x];
364
- }
365
- }
366
- }
367
- function sampleComponent(component, x, y, width, height) {
368
- const sampleX = Math.min(component.planeWidth - 1, Math.floor(x * component.planeWidth / width));
369
- const sampleY = Math.min(component.planeHeight - 1, Math.floor(y * component.planeHeight / height));
370
- return component.plane[sampleY * component.planeWidth + sampleX];
371
- }
372
- function clampByte(value) {
373
- return Math.max(0, Math.min(255, Math.round(value)));
374
- }
375
-
376
- export { canDecodeJpeg, decodeJpegToRgba };
377
- //# 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
+ function decodeJpegToRgba(bytes, metadata = {}) {
11
+ const decoder = new BaselineJpegDecoder(bytes);
12
+ const image = decoder.decode();
13
+ return {
14
+ payloadType: "rgba",
15
+ sourceFormat: "jpeg",
16
+ mimeType: "image/jpeg",
17
+ containerOnly: false,
18
+ isDecoded: true,
19
+ rgbaDecodeSupported: true,
20
+ width: image.width,
21
+ height: image.height,
22
+ pixelFormat: "rgba8unorm",
23
+ data: image.data,
24
+ strideBytes: image.width * 4,
25
+ origin: "top-left",
26
+ colorSpace: "srgb",
27
+ alphaMode: "opaque",
28
+ metadata: {
29
+ ...metadata,
30
+ decoder: "software-baseline"
31
+ }
32
+ };
33
+ }
34
+ function canDecodeJpeg(metadata = {}) {
35
+ return metadata.sourceFormat === "jpeg" && metadata.precision === 8 && metadata.components >= 1 && metadata.components <= 3 && (metadata.marker === 0xc0 || metadata.marker === 0xc1) && metadata.progressive !== true;
36
+ }
37
+ class BaselineJpegDecoder {
38
+ #bytes;
39
+ #offset = 0;
40
+ #quantization = new Map();
41
+ #huffman = new Map();
42
+ #frame = null;
43
+ #scan = null;
44
+ #restartInterval = 0;
45
+ constructor(bytes) {
46
+ this.#bytes = bytes;
47
+ }
48
+ decode() {
49
+ this.readMarker(0xd8);
50
+ while (this.#offset < this.#bytes.length) {
51
+ const marker = this.nextMarker();
52
+ if (marker === 0xd9) break;
53
+ if (marker === 0xda) {
54
+ this.readScanHeader();
55
+ return this.decodeScan();
56
+ }
57
+ 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();
58
+ }
59
+ throw new Error("jpeg: no baseline scan found");
60
+ }
61
+ readFrame(marker) {
62
+ const length = this.readU16();
63
+ const precision = this.readU8();
64
+ const height = this.readU16();
65
+ const width = this.readU16();
66
+ const components = this.readU8();
67
+ if (precision !== 8) throw new Error(`jpeg: unsupported sample precision ${precision}`);
68
+ if (!width || !height || !components || components > 3) throw new Error("jpeg: unsupported frame layout");
69
+ const list = [];
70
+ let maxH = 0,
71
+ maxV = 0;
72
+ for (let i = 0; i < components; i++) {
73
+ const id = this.readU8();
74
+ const sampling = this.readU8();
75
+ const component = {
76
+ id,
77
+ h: sampling >>> 4,
78
+ v: sampling & 0x0f,
79
+ quantizationId: this.readU8(),
80
+ dc: 0,
81
+ ac: 0,
82
+ previousDc: 0,
83
+ plane: null,
84
+ planeWidth: 0,
85
+ planeHeight: 0
86
+ };
87
+ if (!component.h || !component.v || component.h > 4 || component.v > 4) {
88
+ throw new Error("jpeg: unsupported component sampling");
89
+ }
90
+ maxH = Math.max(maxH, component.h);
91
+ maxV = Math.max(maxV, component.v);
92
+ list.push(component);
93
+ }
94
+ const consumed = 8 + components * 3;
95
+ if (length !== consumed) this.#offset += Math.max(0, length - consumed);
96
+ if (marker === 0xc2) throw new Error("jpeg: progressive scans are not supported by the software decoder");
97
+ this.#frame = {
98
+ width,
99
+ height,
100
+ precision,
101
+ components: list,
102
+ maxH,
103
+ maxV
104
+ };
105
+ }
106
+ readQuantizationTables() {
107
+ const end = this.#offset + this.readU16() - 2;
108
+ while (this.#offset < end) {
109
+ const info = this.readU8();
110
+ const precision = info >>> 4;
111
+ const id = info & 0x0f;
112
+ if (precision > 1) throw new Error("jpeg: unsupported 16-bit quantization table");
113
+ const table = new Uint16Array(64);
114
+ for (let i = 0; i < 64; i++) table[ZIGZAG[i]] = precision ? this.readU16() : this.readU8();
115
+ this.#quantization.set(id, table);
116
+ }
117
+ this.#offset = end;
118
+ }
119
+ readHuffmanTables() {
120
+ const end = this.#offset + this.readU16() - 2;
121
+ while (this.#offset < end) {
122
+ const info = this.readU8();
123
+ const table = new Array(17).fill(null).map(() => []);
124
+ const counts = [];
125
+ for (let length = 1; length <= 16; length++) counts.push(this.readU8());
126
+ let code = 0;
127
+ let valueIndex = 0;
128
+ for (let length = 1; length <= 16; length++) {
129
+ for (let i = 0; i < counts[length - 1]; i++) {
130
+ table[length].push({
131
+ code,
132
+ value: this.#bytes[this.#offset + valueIndex]
133
+ });
134
+ valueIndex++;
135
+ code++;
136
+ }
137
+ code <<= 1;
138
+ }
139
+ this.#offset += valueIndex;
140
+ this.#huffman.set(`${info >>> 4}:${info & 0x0f}`, table);
141
+ }
142
+ this.#offset = end;
143
+ }
144
+ readRestartInterval() {
145
+ const length = this.readU16();
146
+ if (length !== 4) throw new Error("jpeg: invalid restart interval segment");
147
+ this.#restartInterval = this.readU16();
148
+ }
149
+ readScanHeader() {
150
+ const length = this.readU16();
151
+ const count = this.readU8();
152
+ if (!this.#frame || count !== this.#frame.components.length) throw new Error("jpeg: unsupported scan component count");
153
+ const byId = new Map(this.#frame.components.map(component => [component.id, component]));
154
+ for (let i = 0; i < count; i++) {
155
+ const id = this.readU8();
156
+ const tables = this.readU8();
157
+ const component = byId.get(id);
158
+ if (!component) throw new Error(`jpeg: scan references unknown component ${id}`);
159
+ component.dc = tables >>> 4;
160
+ component.ac = tables & 0x0f;
161
+ }
162
+ const spectralStart = this.readU8();
163
+ const spectralEnd = this.readU8();
164
+ const successive = this.readU8();
165
+ if (spectralStart !== 0 || spectralEnd !== 63 || successive !== 0) {
166
+ throw new Error("jpeg: progressive or non-sequential scan is not supported");
167
+ }
168
+ const consumed = 6 + count * 2;
169
+ if (length !== consumed) this.#offset += Math.max(0, length - consumed);
170
+ this.#scan = {
171
+ byId
172
+ };
173
+ }
174
+ decodeScan() {
175
+ const frame = this.#frame;
176
+ const mcuWidth = 8 * frame.maxH;
177
+ const mcuHeight = 8 * frame.maxV;
178
+ const mcuColumns = Math.ceil(frame.width / mcuWidth);
179
+ const mcuRows = Math.ceil(frame.height / mcuHeight);
180
+ for (const component of frame.components) {
181
+ component.planeWidth = mcuColumns * component.h * 8;
182
+ component.planeHeight = mcuRows * component.v * 8;
183
+ component.plane = new Uint8Array(component.planeWidth * component.planeHeight);
184
+ }
185
+ const reader = new EntropyReader(this.#bytes, this.#offset);
186
+ let mcuIndex = 0;
187
+ for (let row = 0; row < mcuRows; row++) {
188
+ for (let column = 0; column < mcuColumns; column++) {
189
+ for (const component of frame.components) {
190
+ for (let y = 0; y < component.v; y++) {
191
+ for (let x = 0; x < component.h; x++) {
192
+ const block = this.decodeBlock(reader, component);
193
+ const originX = (column * component.h + x) * 8;
194
+ const originY = (row * component.v + y) * 8;
195
+ writeBlock(component.plane, component.planeWidth, originX, originY, block);
196
+ }
197
+ }
198
+ }
199
+ mcuIndex++;
200
+ if (this.#restartInterval && mcuIndex % this.#restartInterval === 0 && mcuIndex < mcuColumns * mcuRows) {
201
+ reader.align();
202
+ reader.consumeRestart();
203
+ for (const component of frame.components) component.previousDc = 0;
204
+ }
205
+ }
206
+ }
207
+ const data = new Uint8Array(frame.width * frame.height * 4);
208
+ for (let y = 0; y < frame.height; y++) {
209
+ for (let x = 0; x < frame.width; x++) {
210
+ const offset = (y * frame.width + x) * 4;
211
+ if (frame.components.length === 1) {
212
+ const value = frame.components[0].plane[y * frame.components[0].planeWidth + x];
213
+ data[offset] = value;
214
+ data[offset + 1] = value;
215
+ data[offset + 2] = value;
216
+ } else {
217
+ const yValue = sampleComponent(frame.components[0], x, y, frame.width, frame.height);
218
+ const cb = sampleComponent(frame.components[1], x, y, frame.width, frame.height) - 128;
219
+ const cr = sampleComponent(frame.components[2], x, y, frame.width, frame.height) - 128;
220
+ data[offset] = clampByte(yValue + 1.402 * cr);
221
+ data[offset + 1] = clampByte(yValue - 0.344136 * cb - 0.714136 * cr);
222
+ data[offset + 2] = clampByte(yValue + 1.772 * cb);
223
+ }
224
+ data[offset + 3] = 255;
225
+ }
226
+ }
227
+ return {
228
+ width: frame.width,
229
+ height: frame.height,
230
+ data
231
+ };
232
+ }
233
+ decodeBlock(reader, component) {
234
+ const quantization = this.#quantization.get(component.quantizationId);
235
+ const dcTable = this.#huffman.get(`0:${component.dc}`);
236
+ const acTable = this.#huffman.get(`1:${component.ac}`);
237
+ if (!quantization || !dcTable || !acTable) throw new Error("jpeg: missing quantization or Huffman table");
238
+ const coefficients = new Int32Array(64);
239
+ const category = decodeHuffman(reader, dcTable);
240
+ const delta = receiveExtend(reader, category);
241
+ component.previousDc += delta;
242
+ coefficients[0] = component.previousDc;
243
+ let index = 1;
244
+ while (index < 64) {
245
+ const value = decodeHuffman(reader, acTable);
246
+ if (value === 0) break;
247
+ if (value === 0xf0) {
248
+ index += 16;
249
+ continue;
250
+ }
251
+ index += value >>> 4;
252
+ if (index >= 64) throw new Error("jpeg: invalid AC coefficient run");
253
+ coefficients[ZIGZAG[index]] = receiveExtend(reader, value & 0x0f);
254
+ index++;
255
+ }
256
+ for (let i = 0; i < 64; i++) coefficients[i] *= quantization[i];
257
+ return inverseDct(coefficients);
258
+ }
259
+ readU8() {
260
+ if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end of input");
261
+ return this.#bytes[this.#offset++];
262
+ }
263
+ readU16() {
264
+ return this.readU8() << 8 | this.readU8();
265
+ }
266
+ readMarker(expected = null) {
267
+ const marker = this.nextMarker();
268
+ if (expected !== null && marker !== expected) throw new Error("jpeg: missing SOI marker");
269
+ return marker;
270
+ }
271
+ nextMarker() {
272
+ while (this.#offset < this.#bytes.length && this.#bytes[this.#offset++] !== 0xff) {
273
+ // Scan forward to the next marker prefix.
274
+ }
275
+ while (this.#offset < this.#bytes.length && this.#bytes[this.#offset] === 0xff) this.#offset++;
276
+ if (this.#offset >= this.#bytes.length) throw new Error("jpeg: unexpected end while reading marker");
277
+ return this.#bytes[this.#offset++];
278
+ }
279
+ skipSegment() {
280
+ const length = this.readU16();
281
+ if (length < 2 || this.#offset + length - 2 > this.#bytes.length) throw new Error("jpeg: invalid segment length");
282
+ this.#offset += length - 2;
283
+ }
284
+ }
285
+ class EntropyReader {
286
+ #bytes;
287
+ #offset;
288
+ #buffer = 0;
289
+ #bits = 0;
290
+ #marker = null;
291
+ constructor(bytes, offset) {
292
+ this.#bytes = bytes;
293
+ this.#offset = offset;
294
+ }
295
+ readBit() {
296
+ if (!this.#bits) {
297
+ let value = this.#bytes[this.#offset++];
298
+ if (value === 0xff) {
299
+ while (this.#bytes[this.#offset] === 0xff) this.#offset++;
300
+ const marker = this.#bytes[this.#offset++];
301
+ if (marker !== 0x00) {
302
+ this.#marker = marker;
303
+ throw new Error("jpeg: unexpected marker in entropy data");
304
+ }
305
+ value = 0xff;
306
+ }
307
+ if (value === undefined) throw new Error("jpeg: unexpected end in entropy data");
308
+ this.#buffer = value;
309
+ this.#bits = 8;
310
+ }
311
+ return this.#buffer >>> --this.#bits & 1;
312
+ }
313
+ readBits(count) {
314
+ let value = 0;
315
+ for (let i = 0; i < count; i++) value = value << 1 | this.readBit();
316
+ return value;
317
+ }
318
+ align() {
319
+ this.#bits = 0;
320
+ }
321
+ consumeRestart() {
322
+ while (this.#bytes[this.#offset] === 0xff) this.#offset++;
323
+ const marker = this.#bytes[this.#offset++];
324
+ if (marker < 0xd0 || marker > 0xd7) throw new Error("jpeg: missing restart marker");
325
+ }
326
+ }
327
+ function decodeHuffman(reader, table) {
328
+ let code = 0;
329
+ for (let length = 1; length <= 16; length++) {
330
+ code = code << 1 | reader.readBit();
331
+ const entry = table[length].find(item => item.code === code);
332
+ if (entry) return entry.value;
333
+ }
334
+ throw new Error("jpeg: invalid Huffman code");
335
+ }
336
+ function receiveExtend(reader, size) {
337
+ if (!size) return 0;
338
+ const value = reader.readBits(size);
339
+ const threshold = 1 << size - 1;
340
+ return value < threshold ? value - ((1 << size) - 1) : value;
341
+ }
342
+ function inverseDct(coefficients) {
343
+ const output = new Uint8Array(64);
344
+ for (let y = 0; y < 8; y++) {
345
+ for (let x = 0; x < 8; x++) {
346
+ let sum = 0;
347
+ for (let v = 0; v < 8; v++) {
348
+ for (let u = 0; u < 8; u++) {
349
+ sum += SCALE[u] * SCALE[v] * coefficients[v * 8 + u] * COSINE[x][u] * COSINE[y][v];
350
+ }
351
+ }
352
+ output[y * 8 + x] = clampByte(128 + sum / 4);
353
+ }
354
+ }
355
+ return output;
356
+ }
357
+ function writeBlock(plane, planeWidth, originX, originY, block) {
358
+ for (let y = 0; y < 8; y++) {
359
+ const targetY = originY + y;
360
+ if (targetY >= plane.length / planeWidth) continue;
361
+ for (let x = 0; x < 8; x++) {
362
+ const targetX = originX + x;
363
+ if (targetX < planeWidth) plane[targetY * planeWidth + targetX] = block[y * 8 + x];
364
+ }
365
+ }
366
+ }
367
+ function sampleComponent(component, x, y, width, height) {
368
+ const sampleX = Math.min(component.planeWidth - 1, Math.floor(x * component.planeWidth / width));
369
+ const sampleY = Math.min(component.planeHeight - 1, Math.floor(y * component.planeHeight / height));
370
+ return component.plane[sampleY * component.planeWidth + sampleX];
371
+ }
372
+ function clampByte(value) {
373
+ return Math.max(0, Math.min(255, Math.round(value)));
374
+ }
375
+
376
+ export { canDecodeJpeg, decodeJpegToRgba };
377
+ //# sourceMappingURL=jpeg.js.map