ranger-compiler 3.5.0 → 3.5.2

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 (338) hide show
  1. package/CHANGELOG.md +1160 -19
  2. package/LICENSE +3 -1
  3. package/README.md +124 -29
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79924 -56922
  7. package/dist/lib/JSON.rgr +102 -91
  8. package/dist/lib/Shell.rgr +4 -4
  9. package/dist/lib/apple/AppleToolchain.rgr +4 -4
  10. package/dist/lib/apple/README.md +5 -4
  11. package/dist/lib/apple/apple_test.rgr +1 -1
  12. package/dist/lib/core/README.md +1 -1
  13. package/dist/lib/evg/EVG.rgr +12 -0
  14. package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
  15. package/dist/lib/evg/EVGA11yTree.rgr +894 -0
  16. package/dist/lib/evg/EVGBox.rgr +267 -0
  17. package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
  18. package/dist/lib/evg/EVGCodepoint.rgr +316 -0
  19. package/dist/lib/evg/EVGColor.rgr +700 -0
  20. package/dist/lib/evg/EVGCommands.rgr +177 -0
  21. package/dist/lib/evg/EVGComponent.rgr +331 -0
  22. package/dist/lib/evg/EVGComponentTest.rgr +387 -0
  23. package/dist/lib/evg/EVGConnector.rgr +541 -0
  24. package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
  25. package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
  26. package/dist/lib/evg/EVGEasing.rgr +370 -0
  27. package/dist/lib/evg/EVGEffectTest.rgr +253 -0
  28. package/dist/lib/evg/EVGElement.rgr +4914 -0
  29. package/dist/lib/evg/EVGFixedTest.rgr +289 -0
  30. package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
  31. package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
  32. package/dist/lib/evg/EVGFling.rgr +244 -0
  33. package/dist/lib/evg/EVGFocus.rgr +400 -0
  34. package/dist/lib/evg/EVGFocusTest.rgr +399 -0
  35. package/dist/lib/evg/EVGGradient.rgr +322 -0
  36. package/dist/lib/evg/EVGGrapheme.rgr +190 -0
  37. package/dist/lib/evg/EVGGrid.rgr +975 -0
  38. package/dist/lib/evg/EVGHitTest.rgr +208 -0
  39. package/dist/lib/evg/EVGHoles.rgr +294 -0
  40. package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
  41. package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
  42. package/dist/lib/evg/EVGHostTree.rgr +834 -0
  43. package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
  44. package/dist/lib/evg/EVGImageDecode.rgr +117 -0
  45. package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
  46. package/dist/lib/evg/EVGInspect.rgr +883 -0
  47. package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
  48. package/dist/lib/evg/EVGJsonTest.rgr +535 -0
  49. package/dist/lib/evg/EVGLayout.rgr +4220 -0
  50. package/dist/lib/evg/EVGMeasure.rgr +1267 -0
  51. package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
  52. package/dist/lib/evg/EVGPatch.rgr +1721 -0
  53. package/dist/lib/evg/EVGPatchTest.rgr +692 -0
  54. package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
  55. package/dist/lib/evg/EVGReconcile.rgr +226 -0
  56. package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
  57. package/dist/lib/evg/EVGReject.rgr +126 -0
  58. package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
  59. package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
  60. package/dist/lib/evg/EVGRuler.rgr +232 -0
  61. package/dist/lib/evg/EVGRulerTest.rgr +172 -0
  62. package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
  63. package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
  64. package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
  65. package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
  66. package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
  67. package/dist/lib/evg/EVGText.rgr +105 -0
  68. package/dist/lib/evg/EVGTextEngine.rgr +536 -0
  69. package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
  70. package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
  71. package/dist/lib/evg/EVGToolbar.rgr +1369 -0
  72. package/dist/lib/evg/EVGTransition.rgr +728 -0
  73. package/dist/lib/evg/EVGTreeJson.rgr +721 -0
  74. package/dist/lib/evg/EVGUnit.rgr +554 -0
  75. package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
  76. package/dist/lib/evg/EvgApp.rgr +189 -0
  77. package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
  78. package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
  79. package/dist/lib/evg/EvgHost.rgr +451 -0
  80. package/dist/lib/evg/EvgTest.rgr +91 -0
  81. package/dist/lib/evg/EvgTraceColor.rgr +236 -0
  82. package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
  83. package/dist/lib/evg/EvgTraceFit.rgr +767 -0
  84. package/dist/lib/evg/EvgTracePath.rgr +435 -0
  85. package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
  86. package/dist/lib/evg/EvgViewport.rgr +313 -0
  87. package/dist/lib/evg/FxDemoDoc.rgr +185 -0
  88. package/dist/lib/evg/HOSTS.md +227 -0
  89. package/dist/lib/evg/ISSUES.md +835 -0
  90. package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
  91. package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
  92. package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
  93. package/dist/lib/evg/PLAN_EVG.md +518 -0
  94. package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
  95. package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
  96. package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
  97. package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
  98. package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
  99. package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
  100. package/dist/lib/evg/PathBuilder.rgr +333 -0
  101. package/dist/lib/evg/README.md +1236 -0
  102. package/dist/lib/evg/SPEC.md +1252 -0
  103. package/dist/lib/evg/SVGPathParser.rgr +1199 -0
  104. package/dist/lib/evg/SvgParser.rgr +1736 -0
  105. package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
  106. package/dist/lib/evg/VectorShapes.rgr +331 -0
  107. package/dist/lib/evg/VectorStroke.rgr +107 -0
  108. package/dist/lib/evg/VectorViewBox.rgr +380 -0
  109. package/dist/lib/evg/agent/README.md +290 -0
  110. package/dist/lib/evg/agent/evg_agent.rgr +899 -0
  111. package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
  112. package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
  113. package/dist/lib/evg/agent/fixtures/connector.css +63 -0
  114. package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
  115. package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
  116. package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
  117. package/dist/lib/evg/agent/fixtures/popover.css +99 -0
  118. package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
  119. package/dist/lib/evg/agent/roundtrip.sh +74 -0
  120. package/dist/lib/evg/agent/smoke.sh +230 -0
  121. package/dist/lib/evg/android/README.md +97 -0
  122. package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
  123. package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
  124. package/dist/lib/evg/android/androidstubs/App.kt +30 -0
  125. package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
  126. package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
  127. package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
  128. package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
  129. package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
  130. package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
  131. package/dist/lib/evg/android/androidstubs/View.kt +113 -0
  132. package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
  133. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
  134. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
  135. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
  136. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
  137. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
  138. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
  139. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
  140. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
  141. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
  142. package/dist/lib/evg/apple/README.md +128 -0
  143. package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
  144. package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
  145. package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
  146. package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
  147. package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
  148. package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
  149. package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
  150. package/dist/lib/evg/bench/README.md +64 -0
  151. package/dist/lib/evg/bench/layout-bench.mjs +316 -0
  152. package/dist/lib/evg/bench/layout-cases.mjs +510 -0
  153. package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
  154. package/dist/lib/evg/bin/.gitignore +17 -0
  155. package/dist/lib/evg/evg_test.rgr +313 -0
  156. package/dist/lib/evg/gl/README.md +198 -0
  157. package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
  158. package/dist/lib/evg/gl/blur-check.mjs +399 -0
  159. package/dist/lib/evg/gl/boxmodel.json +1 -0
  160. package/dist/lib/evg/gl/demo.html +46 -0
  161. package/dist/lib/evg/gl/effect-presets.css +285 -0
  162. package/dist/lib/evg/gl/effect-presets.js +63 -0
  163. package/dist/lib/evg/gl/effect-shots.mjs +135 -0
  164. package/dist/lib/evg/gl/evg-a11y.js +566 -0
  165. package/dist/lib/evg/gl/evg-binary.js +160 -0
  166. package/dist/lib/evg/gl/evg-engine.js +296 -0
  167. package/dist/lib/evg/gl/evg-fx.js +237 -0
  168. package/dist/lib/evg/gl/evg-gestures.js +209 -0
  169. package/dist/lib/evg/gl/evg-list.js +167 -0
  170. package/dist/lib/evg/gl/evg-measure.js +186 -0
  171. package/dist/lib/evg/gl/evg-textinput.js +303 -0
  172. package/dist/lib/evg/gl/evg-view.js +144 -0
  173. package/dist/lib/evg/gl/evg-webgl.js +3942 -0
  174. package/dist/lib/evg/gl/fx-check.mjs +998 -0
  175. package/dist/lib/evg/gl/fx-demo.html +166 -0
  176. package/dist/lib/evg/gl/fx-demo.js +2 -0
  177. package/dist/lib/evg/gl/fx-serve.mjs +47 -0
  178. package/dist/lib/evg/gl/gestures-check.mjs +189 -0
  179. package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
  180. package/dist/lib/evg/gl/measure-check.mjs +135 -0
  181. package/dist/lib/evg/gl/rotation-check.mjs +207 -0
  182. package/dist/lib/evg/gl/shift-check.mjs +113 -0
  183. package/dist/lib/evg/gl/stroke-check.mjs +168 -0
  184. package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
  185. package/dist/lib/evg/gl/view-check.mjs +343 -0
  186. package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
  187. package/dist/lib/evg/html/evg-dom.js +318 -0
  188. package/dist/lib/evg/html/evg-html.js +600 -0
  189. package/dist/lib/evg/inspect/README.md +415 -0
  190. package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
  191. package/dist/lib/evg/inspect/evg-inspect.js +947 -0
  192. package/dist/lib/evg/inspect/shots/css.png +0 -0
  193. package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
  194. package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
  195. package/dist/lib/evg/inspect/shots/state.png +0 -0
  196. package/dist/lib/evg/inspect/shots.mjs +226 -0
  197. package/dist/lib/evg/oracle/css-blur.json +576 -0
  198. package/dist/lib/evg/oracle/css-box.json +157 -0
  199. package/dist/lib/evg/oracle/css-timing.json +709 -0
  200. package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
  201. package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
  202. package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
  203. package/dist/lib/evg/original/EVGColor.clj +310 -0
  204. package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
  205. package/dist/lib/evg/original/SVGPath.rgr +627 -0
  206. package/dist/lib/evg/original/Vec2.crgr +103 -0
  207. package/dist/lib/evg/ranger.json +9 -0
  208. package/dist/lib/evg/showcase/README.md +246 -0
  209. package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
  210. package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
  211. package/dist/lib/evg/showcase/build.mjs +651 -0
  212. package/dist/lib/evg/showcase/pages/album.tsx +30 -0
  213. package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
  214. package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
  215. package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
  216. package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
  217. package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
  218. package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
  219. package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
  220. package/dist/lib/evg/showcase/pages/more.tsx +332 -0
  221. package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
  222. package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
  223. package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
  224. package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
  225. package/dist/lib/evg/showcase/pages/units.tsx +35 -0
  226. package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
  227. package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
  228. package/dist/lib/evg/showcase/pages/views.tsx +223 -0
  229. package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
  230. package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
  231. package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
  232. package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
  233. package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
  234. package/dist/lib/evg/showcase/themes/more-default.css +128 -0
  235. package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
  236. package/dist/lib/evg/showcase/themes/showcase.css +508 -0
  237. package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
  238. package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
  239. package/dist/lib/evg/showcase/themes/views-default.css +15 -0
  240. package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
  241. package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
  242. package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
  243. package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
  244. package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
  245. package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
  246. package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
  247. package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
  248. package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
  249. package/dist/lib/evg/web/responsive/README.md +97 -0
  250. package/dist/lib/evg/web/responsive/build.mjs +90 -0
  251. package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
  252. package/dist/lib/evg/web/responsive/index.html +177 -0
  253. package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
  254. package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
  255. package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
  256. package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
  257. package/dist/lib/evg/web/tools/minify.mjs +60 -0
  258. package/dist/lib/evg/web/tracer/build.mjs +87 -0
  259. package/dist/lib/evg/web/tracer/index.html +2805 -0
  260. package/dist/lib/evg/web/tracer/sample.png +0 -0
  261. package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
  262. package/dist/lib/evgr/Cargo.lock +21 -0
  263. package/dist/lib/evgr/Cargo.toml +19 -0
  264. package/dist/lib/evgr/README.md +140 -0
  265. package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
  266. package/dist/lib/evgr/bench/compare.mjs +252 -0
  267. package/dist/lib/evgr/bench/speed.mjs +277 -0
  268. package/dist/lib/evgr/bin/.gitignore +3 -0
  269. package/dist/lib/evgr/src/bin/bench.rs +106 -0
  270. package/dist/lib/evgr/src/bin/smoke.rs +13 -0
  271. package/dist/lib/evgr/src/grid.rs +730 -0
  272. package/dist/lib/evgr/src/lib.rs +1003 -0
  273. package/dist/lib/evgr/src/style.rs +468 -0
  274. package/dist/lib/evgr/src/text.rs +83 -0
  275. package/dist/lib/image/BitReader.rgr +171 -0
  276. package/dist/lib/image/Buffer.rgr +173 -0
  277. package/dist/lib/image/DCT.rgr +283 -0
  278. package/dist/lib/image/Deflate.rgr +339 -0
  279. package/dist/lib/image/HuffmanDecoder.rgr +181 -0
  280. package/dist/lib/image/ImageBuffer.rgr +706 -0
  281. package/dist/lib/image/JPEGDecoder.rgr +808 -0
  282. package/dist/lib/image/PNGDecoder.rgr +544 -0
  283. package/dist/lib/image/PNGEncoder.rgr +388 -0
  284. package/dist/lib/image/PPMImage.rgr +224 -0
  285. package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
  286. package/dist/lib/image/README.md +33 -0
  287. package/dist/lib/image/RasterBuffer.rgr +294 -0
  288. package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
  289. package/dist/lib/image/WebPDecoder.rgr +433 -0
  290. package/dist/lib/image/WebPLossless.rgr +1035 -0
  291. package/dist/lib/image/WebPLossy.rgr +1929 -0
  292. package/dist/lib/image/ranger.json +9 -0
  293. package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
  294. package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
  295. package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
  296. package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
  297. package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
  298. package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
  299. package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
  300. package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
  301. package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
  302. package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
  303. package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
  304. package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
  305. package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
  306. package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
  307. package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
  308. package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
  309. package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
  310. package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
  311. package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
  312. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
  313. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
  314. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
  315. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
  316. package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
  317. package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
  318. package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
  319. package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
  320. package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
  321. package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
  322. package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
  323. package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
  324. package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
  325. package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
  326. package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
  327. package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
  328. package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
  329. package/dist/lib/image/tests/run_webp_tests.sh +39 -0
  330. package/dist/lib/rust/RsJson.rgr +468 -0
  331. package/dist/lib/rust/RsPrelude.rgr +1663 -0
  332. package/dist/lib/shell_test.rgr +7 -7
  333. package/dist/lib/stdlib.rgr +21 -5
  334. package/dist/lib/zip/ranger.json +6 -0
  335. package/dist/rgrc.js +87318 -67610
  336. package/package.json +1010 -1040
  337. package/dist/README.md +0 -117
  338. package/dist/package.json +0 -47
@@ -0,0 +1,808 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; JPEGDecoder.rgr - Full JPEG decoder (baseline DCT)
4
+ ; Decodes JPEG to raw RGB pixels
5
+
6
+ Import "Buffer.rgr"
7
+ Import "BitReader.rgr"
8
+ Import "HuffmanDecoder.rgr"
9
+ Import "DCT.rgr"
10
+ Import "ImageBuffer.rgr"
11
+ Import "PPMImage.rgr"
12
+
13
+ class JPEGComponent {
14
+ def id:int 0
15
+ def hSamp:int 1 ; Horizontal sampling factor
16
+ def vSamp:int 1 ; Vertical sampling factor
17
+ def quantTableId:int 0
18
+ def dcTableId:int 0
19
+ def acTableId:int 0
20
+ def prevDC:int 0 ; Previous DC value for differential coding
21
+
22
+ Constructor () {
23
+ }
24
+ }
25
+
26
+ class QuantizationTable {
27
+ def values:[int]
28
+ def id:int 0
29
+
30
+ Constructor () {
31
+ def i 0
32
+ while (i < 64) {
33
+ push values 1
34
+ i = i + 1
35
+ }
36
+ }
37
+ }
38
+
39
+ class JPEGDecoder {
40
+ ; Say nothing while decoding.
41
+ ;
42
+ ; This decoder narrates - twenty-five lines per photograph, every
43
+ ; marker and every tenth row - which is useful when you are debugging a
44
+ ; JPEG and is noise everywhere else. In a browser it goes to a console
45
+ ; nobody has open; in a native window it goes to the terminal, so a book
46
+ ; of forty pictures opens behind a thousand lines of scrolling.
47
+ ;
48
+ ; Off by default, so every existing caller is unchanged. A caller that
49
+ ; decodes pictures as a side effect of doing something else turns it on.
50
+ def quiet:boolean false
51
+
52
+ fn say:void (msg:string) {
53
+ if quiet {
54
+ return
55
+ }
56
+ print msg
57
+ }
58
+ def data:buffer (buffer_alloc 0)
59
+ def dataLen:int 0
60
+
61
+ ; Image properties
62
+ def width:int 0
63
+ def height:int 0
64
+ def numComponents:int 0
65
+ def precision:int 8
66
+
67
+ ; Components
68
+ def components:[JPEGComponent]
69
+
70
+ ; Quantization tables (up to 4)
71
+ def quantTables:[QuantizationTable]
72
+
73
+ ; Huffman decoder
74
+ def huffman:HuffmanDecoder
75
+
76
+ ; DCT transformer
77
+ def idct:IDCT
78
+
79
+ ; Scan data position
80
+ def scanDataStart:int 0
81
+ def scanDataLen:int 0
82
+
83
+ ; MCU dimensions
84
+ def mcuWidth:int 8
85
+ def mcuHeight:int 8
86
+ def mcusPerRow:int 0
87
+ def mcusPerCol:int 0
88
+ def maxHSamp:int 1
89
+ def maxVSamp:int 1
90
+
91
+ ; Restart interval (0 = no restart markers)
92
+ def restartInterval:int 0
93
+
94
+ Constructor () {
95
+ huffman = (new HuffmanDecoder())
96
+ idct = (new IDCT())
97
+
98
+ def i 0
99
+ while (i < 4) {
100
+ push quantTables (new QuantizationTable())
101
+ i = i + 1
102
+ }
103
+ }
104
+
105
+ fn reset:void () {
106
+ ; Reset all state for decoding a new image
107
+ ; This is important when reusing the same decoder instance!
108
+ width = 0
109
+ height = 0
110
+ numComponents = 0
111
+ precision = 8
112
+ scanDataStart = 0
113
+ scanDataLen = 0
114
+ mcuWidth = 8
115
+ mcuHeight = 8
116
+ mcusPerRow = 0
117
+ mcusPerCol = 0
118
+ maxHSamp = 1
119
+ maxVSamp = 1
120
+ restartInterval = 0
121
+
122
+ ; Clear components
123
+ clear components
124
+
125
+ ; Reset Huffman tables
126
+ huffman.dcTable0.resetArrays()
127
+ huffman.dcTable1.resetArrays()
128
+ huffman.acTable0.resetArrays()
129
+ huffman.acTable1.resetArrays()
130
+
131
+ ; Reset quantization tables
132
+ def i 0
133
+ while (i < 4) {
134
+ def qt:QuantizationTable (at quantTables i)
135
+ clear qt.values
136
+ def j 0
137
+ while (j < 64) {
138
+ push qt.values 1
139
+ j = j + 1
140
+ }
141
+ i = i + 1
142
+ }
143
+ }
144
+
145
+ fn readUint16BE:int (pos:int) {
146
+ def high:int (buffer_get data pos)
147
+ def low:int (buffer_get data (pos + 1))
148
+ return ((high * 256) + low)
149
+ }
150
+
151
+ fn parseSOF:void (pos:int length:int) {
152
+ ; Start of Frame - image dimensions and components
153
+ precision = (buffer_get data pos)
154
+ height = (this.readUint16BE(pos + 1))
155
+ width = (this.readUint16BE(pos + 3))
156
+ numComponents = (buffer_get data (pos + 5))
157
+
158
+ this.say((" Image: " + (to_string width) + "x" + (to_string height) + ", " + (to_string numComponents) + " components"))
159
+
160
+ clear components
161
+ maxHSamp = 1
162
+ maxVSamp = 1
163
+
164
+ def i 0
165
+ def offset:int (pos + 6)
166
+ while (i < numComponents) {
167
+ def comp (new JPEGComponent())
168
+ comp.id = (buffer_get data offset)
169
+ def sampling:int (buffer_get data (offset + 1))
170
+ comp.hSamp = (bit_shr sampling 4)
171
+ comp.vSamp = (bit_and sampling 15)
172
+ comp.quantTableId = (buffer_get data (offset + 2))
173
+
174
+ if (comp.hSamp > maxHSamp) { maxHSamp = comp.hSamp }
175
+ if (comp.vSamp > maxVSamp) { maxVSamp = comp.vSamp }
176
+
177
+ push components comp
178
+ this.say((" Component " + (to_string comp.id) + ": " + (to_string comp.hSamp) + "x" + (to_string comp.vSamp) + " sampling, quant table " + (to_string comp.quantTableId)))
179
+
180
+ offset = offset + 3
181
+ i = i + 1
182
+ }
183
+
184
+ ; Calculate MCU dimensions
185
+ mcuWidth = maxHSamp * 8
186
+ mcuHeight = maxVSamp * 8
187
+
188
+ ; Calculate MCUs needed (ceiling division)
189
+ ; mcusPerRow = ceil(width / mcuWidth)
190
+ mcusPerRow = (to_int ((width + mcuWidth - 1) / mcuWidth))
191
+ mcusPerCol = (to_int ((height + mcuHeight - 1) / mcuHeight))
192
+
193
+ this.say((" MCU size: " + (to_string mcuWidth) + "x" + (to_string mcuHeight) + ", grid: " + (to_string mcusPerRow) + "x" + (to_string mcusPerCol)))
194
+ }
195
+
196
+ fn parseDQT:void (pos:int length:int) {
197
+ ; Define Quantization Table
198
+ def endPos:int (pos + length)
199
+
200
+ while (pos < endPos) {
201
+ def info:int (buffer_get data pos)
202
+ pos = pos + 1
203
+
204
+ def precision:int (bit_shr info 4) ; 0 = 8-bit, 1 = 16-bit
205
+ def tableId:int (bit_and info 15)
206
+
207
+ def table:QuantizationTable (at quantTables tableId)
208
+ table.id = tableId
209
+ clear table.values
210
+
211
+ def i 0
212
+ while (i < 64) {
213
+ if (precision == 0) {
214
+ push table.values (buffer_get data pos)
215
+ pos = pos + 1
216
+ } {
217
+ push table.values (this.readUint16BE(pos))
218
+ pos = pos + 2
219
+ }
220
+ i = i + 1
221
+ }
222
+
223
+ this.say((" Quantization table " + (to_string tableId) + " (" + (to_string (precision + 1)) + "-byte values)"))
224
+ }
225
+ }
226
+
227
+ fn parseSOS:void (pos:int length:int) {
228
+ ; Start of Scan
229
+ def numScanComponents:int (buffer_get data pos)
230
+ pos = pos + 1
231
+
232
+ def i 0
233
+ while (i < numScanComponents) {
234
+ def compId:int (buffer_get data pos)
235
+ def tableSelect:int (buffer_get data (pos + 1))
236
+ pos = pos + 2
237
+
238
+ ; Find matching component and set table IDs
239
+ def j 0
240
+ while (j < numComponents) {
241
+ def comp:JPEGComponent (at components j)
242
+ if (comp.id == compId) {
243
+ comp.dcTableId = (bit_shr tableSelect 4)
244
+ comp.acTableId = (bit_and tableSelect 15)
245
+ this.say((" Component " + (to_string compId) + ": DC table " + (to_string comp.dcTableId) + ", AC table " + (to_string comp.acTableId)))
246
+ }
247
+ j = j + 1
248
+ }
249
+
250
+ i = i + 1
251
+ }
252
+
253
+ ; Skip spectral selection and successive approximation (baseline ignores these)
254
+ pos = pos + 3
255
+
256
+ ; Scan data starts here
257
+ scanDataStart = pos
258
+
259
+ ; Find end of scan data (next marker or EOI)
260
+ ; Note: RST markers (FFD0-FFD7) are part of scan data and should not stop the search
261
+ def searchPos:int pos
262
+ while (searchPos < (dataLen - 1)) {
263
+ def b:int (buffer_get data searchPos)
264
+ if (b == 255) {
265
+ def nextB:int (buffer_get data (searchPos + 1))
266
+ if ((nextB != 0) && (nextB != 255)) {
267
+ ; Check if it's a RST marker (D0-D7 = 208-215)
268
+ if ((nextB >= 208) && (nextB <= 215)) {
269
+ ; RST marker - skip it and continue searching
270
+ searchPos = searchPos + 2
271
+ continue
272
+ }
273
+ ; Found a non-RST marker - end of scan data
274
+ scanDataLen = searchPos - scanDataStart
275
+ return
276
+ }
277
+ }
278
+ searchPos = searchPos + 1
279
+ }
280
+ scanDataLen = dataLen - scanDataStart
281
+ }
282
+
283
+ fn parseMarkers:boolean () {
284
+ ; Parse all JPEG markers
285
+ def pos 0
286
+
287
+ ; Check SOI
288
+ if (dataLen < 2) {
289
+ this.say("Error: File too small")
290
+ return false
291
+ }
292
+
293
+ def m1:int (buffer_get data 0)
294
+ def m2:int (buffer_get data 1)
295
+ if ((m1 != 255) || (m2 != 216)) {
296
+ this.say("Error: Not a JPEG file (missing SOI)")
297
+ return false
298
+ }
299
+
300
+ pos = 2
301
+ this.say("Parsing JPEG markers...")
302
+
303
+ while (pos < (dataLen - 1)) {
304
+ def marker1:int (buffer_get data pos)
305
+ if (marker1 != 255) {
306
+ pos = pos + 1
307
+ continue
308
+ }
309
+
310
+ def marker2:int (buffer_get data (pos + 1))
311
+
312
+ ; Skip padding FF bytes
313
+ if (marker2 == 255) {
314
+ pos = pos + 1
315
+ continue
316
+ }
317
+
318
+ if (marker2 == 0) {
319
+ ; FF00 = escaped FF in data
320
+ pos = pos + 2
321
+ continue
322
+ }
323
+
324
+ ; Check for markers without length
325
+ if (marker2 == 216) {
326
+ ; SOI
327
+ pos = pos + 2
328
+ continue
329
+ }
330
+ if (marker2 == 217) {
331
+ ; EOI
332
+ this.say(" End of Image")
333
+ return true
334
+ }
335
+ if ((marker2 >= 208) && (marker2 <= 215)) {
336
+ ; RST markers
337
+ pos = pos + 2
338
+ continue
339
+ }
340
+
341
+ ; Read marker length
342
+ if ((pos + 4) > dataLen) {
343
+ return true
344
+ }
345
+ def markerLen:int (this.readUint16BE(pos + 2))
346
+ def dataStart:int (pos + 4)
347
+ def markerDataLen:int (markerLen - 2)
348
+
349
+ ; Process marker
350
+ if (marker2 == 192) {
351
+ this.say(" SOF0 (Baseline DCT)")
352
+ this.parseSOF(dataStart markerDataLen)
353
+ }
354
+ if (marker2 == 193) {
355
+ this.say(" SOF1 (Extended Sequential DCT)")
356
+ this.parseSOF(dataStart markerDataLen)
357
+ }
358
+ if (marker2 == 194) {
359
+ this.say(" SOF2 (Progressive DCT) - NOT SUPPORTED")
360
+ return false
361
+ }
362
+ if (marker2 == 196) {
363
+ this.say(" DHT (Huffman Tables)")
364
+ huffman.parseDHT(data dataStart markerDataLen)
365
+ }
366
+ if (marker2 == 219) {
367
+ this.say(" DQT (Quantization Tables)")
368
+ this.parseDQT(dataStart markerDataLen)
369
+ }
370
+ if (marker2 == 221) {
371
+ ; DRI - Define Restart Interval
372
+ restartInterval = (this.readUint16BE(dataStart))
373
+ this.say((" DRI (Restart Interval: " + (to_string restartInterval) + ")"))
374
+ }
375
+ if (marker2 == 218) {
376
+ this.say(" SOS (Start of Scan)")
377
+ this.parseSOS(dataStart markerDataLen)
378
+ ; After SOS, entropy-coded data follows
379
+ ; Skip to end of scan data
380
+ pos = scanDataStart + scanDataLen
381
+ continue
382
+ }
383
+ if (marker2 == 224) {
384
+ this.say(" APP0 (JFIF)")
385
+ }
386
+ if (marker2 == 225) {
387
+ this.say(" APP1 (EXIF)")
388
+ }
389
+ if (marker2 == 254) {
390
+ this.say(" COM (Comment)")
391
+ }
392
+
393
+ pos = pos + 2 + markerLen
394
+ }
395
+
396
+ return true
397
+ }
398
+
399
+ fn decodeBlock:int_buffer (reader:BitReader comp:JPEGComponent quantTable:QuantizationTable) {
400
+ ; Decode one 8x8 block
401
+ ; Returns 64 dequantized DCT coefficients in zigzag order
402
+
403
+ def coeffs:int_buffer (int_buffer_alloc 64)
404
+ int_buffer_fill coeffs 0 0 64
405
+
406
+ ; Decode DC coefficient
407
+ def dcTable:HuffmanTable (huffman.getDCTable(comp.dcTableId))
408
+ def dcCategory:int (dcTable.decode(reader))
409
+ def dcDiff:int (reader.receiveExtend(dcCategory))
410
+ def dcValue:int (comp.prevDC + dcDiff)
411
+ comp.prevDC = dcValue
412
+
413
+ ; Dequantize DC
414
+ def dcQuant:int (at quantTable.values 0)
415
+ int_buffer_set coeffs 0 (dcValue * dcQuant)
416
+
417
+ ; Decode AC coefficients
418
+ def acTable:HuffmanTable (huffman.getACTable(comp.acTableId))
419
+ def k:int 1
420
+
421
+ while (k < 64) {
422
+ def acSymbol:int (acTable.decode(reader))
423
+
424
+ if (acSymbol == 0) {
425
+ ; EOB - all remaining coefficients are zero
426
+ k = 64
427
+ } {
428
+ def runLength:int (bit_shr acSymbol 4)
429
+ def acCategory:int (bit_and acSymbol 15)
430
+
431
+ if (acSymbol == 240) {
432
+ ; ZRL - skip 16 zeros
433
+ k = k + 16
434
+ } {
435
+ ; Skip run of zeros
436
+ k = k + runLength
437
+
438
+ if (k < 64) {
439
+ ; Decode AC value
440
+ def acValue:int (reader.receiveExtend(acCategory))
441
+
442
+ ; Dequantize
443
+ def acQuant:int (at quantTable.values k)
444
+ int_buffer_set coeffs k (acValue * acQuant)
445
+
446
+ k = k + 1
447
+ }
448
+ }
449
+ }
450
+ }
451
+ return coeffs
452
+ }
453
+
454
+ fn decode:ImageBuffer (dirPath:string fileName:string) {
455
+ def bytes:buffer (buffer_read_file dirPath fileName)
456
+ return (this.decodeBytes(bytes))
457
+ }
458
+
459
+ ; decode a JPEG already held in memory (e.g. a glTF embedded image slice).
460
+ fn decodeBytes:ImageBuffer (bytes:buffer) {
461
+ ; Main decode function
462
+ ; Reset all state before decoding new image
463
+ this.reset()
464
+ ; The table builder narrates too. Passed here rather than in the
465
+ ; constructor, because a caller sets `quiet` on the decoder AFTER
466
+ ; constructing it - which is the only moment it could.
467
+ huffman.quiet = quiet
468
+
469
+ data = bytes
470
+ dataLen = (buffer_length data)
471
+
472
+ this.say(("Decoding JPEG in-memory (" + (to_string dataLen) + " bytes)"))
473
+
474
+ ; Parse markers
475
+ def ok:boolean (this.parseMarkers())
476
+ if (ok == false) {
477
+ this.say("Error parsing JPEG markers")
478
+ def errImg (new ImageBuffer())
479
+ errImg.init(1 1)
480
+ return errImg
481
+ }
482
+
483
+ if ((width == 0) || (height == 0)) {
484
+ this.say("Error: Invalid image dimensions")
485
+ def errImg (new ImageBuffer())
486
+ errImg.init(1 1)
487
+ return errImg
488
+ }
489
+
490
+ this.say(("Decoding " + (to_string scanDataLen) + " bytes of scan data..."))
491
+
492
+ ; Create output image
493
+ def img (new ImageBuffer())
494
+ img.init(width height)
495
+
496
+ ; Create bit reader for scan data
497
+ def reader (new BitReader())
498
+ reader.init(data scanDataStart scanDataLen)
499
+
500
+ ; Reset DC predictors
501
+ def c 0
502
+ while (c < numComponents) {
503
+ def comp:JPEGComponent (at components c)
504
+ comp.prevDC = 0
505
+ c = c + 1
506
+ }
507
+
508
+ ; Component block buffers - use flat arrays, 64 values per block
509
+ ; For 2x2 subsampling max, we need 4 Y blocks = 256 values
510
+ def yBlocksData:[int] ; Up to 4 Y blocks * 64 = 256 values
511
+ def yBlockCount:int 0
512
+ def cbBlock:[int]
513
+ def crBlock:[int]
514
+
515
+ ; MCU counter for restart interval
516
+ def mcuCount:int 0
517
+
518
+ ; Decode MCU by MCU
519
+ def mcuY 0
520
+ while (mcuY < mcusPerCol) {
521
+ def mcuX 0
522
+ while (mcuX < mcusPerRow) {
523
+ ; Check for restart interval - reset DC predictions
524
+ if ((restartInterval > 0) && (mcuCount > 0) && ((mcuCount % restartInterval) == 0)) {
525
+ ; Reset DC predictions after restart marker
526
+ c = 0
527
+ while (c < numComponents) {
528
+ def compRst:JPEGComponent (at components c)
529
+ compRst.prevDC = 0
530
+ c = c + 1
531
+ }
532
+ ; Align bit reader to byte boundary and skip RST marker
533
+ reader.alignToByte()
534
+ reader.skipRestartMarker()
535
+ }
536
+
537
+ ; Decode all blocks in this MCU
538
+ clear yBlocksData
539
+ yBlockCount = 0
540
+
541
+ ; For each component
542
+ def compIdx 0
543
+ while (compIdx < numComponents) {
544
+ def comp:JPEGComponent (at components compIdx)
545
+ def quantTable:QuantizationTable (at quantTables comp.quantTableId)
546
+
547
+ ; Decode blocks for this component
548
+ def blockV 0
549
+ while (blockV < comp.vSamp) {
550
+ def blockH 0
551
+ while (blockH < comp.hSamp) {
552
+ ; Decode block
553
+ def coeffs:int_buffer (this.decodeBlock(reader comp quantTable))
554
+
555
+ ; IDCT to get pixels
556
+ def blockPixels:int_buffer (int_buffer_alloc 64)
557
+ int_buffer_fill blockPixels 0 0 64
558
+
559
+ ; Dezigzag and transform
560
+ def tempBlock:int_buffer (idct.dezigzag(coeffs))
561
+ idct.transform(tempBlock blockPixels)
562
+
563
+ ; Store block
564
+ if (compIdx == 0) {
565
+ ; Y component - append to flat array
566
+ def bi 0
567
+ while (bi < 64) {
568
+ push yBlocksData (int_buffer_get blockPixels bi)
569
+ bi = bi + 1
570
+ }
571
+ yBlockCount = yBlockCount + 1
572
+ }
573
+ if (compIdx == 1) {
574
+ ; Cb component
575
+ clear cbBlock
576
+ def bi 0
577
+ while (bi < 64) {
578
+ push cbBlock (int_buffer_get blockPixels bi)
579
+ bi = bi + 1
580
+ }
581
+ }
582
+ if (compIdx == 2) {
583
+ ; Cr component
584
+ clear crBlock
585
+ def bi 0
586
+ while (bi < 64) {
587
+ push crBlock (int_buffer_get blockPixels bi)
588
+ bi = bi + 1
589
+ }
590
+ }
591
+
592
+ blockH = blockH + 1
593
+ }
594
+ blockV = blockV + 1
595
+ }
596
+
597
+ compIdx = compIdx + 1
598
+ }
599
+
600
+ ; Convert MCU to RGB and write to image
601
+ this.writeMCU(img mcuX mcuY yBlocksData yBlockCount cbBlock crBlock)
602
+
603
+ mcuX = mcuX + 1
604
+ mcuCount = mcuCount + 1
605
+ }
606
+ mcuY = mcuY + 1
607
+
608
+ ; Progress indicator
609
+ if ((mcuY % 10) == 0) {
610
+ this.say((" Row " + (to_string mcuY) + "/" + (to_string mcusPerCol)))
611
+ }
612
+ }
613
+
614
+ this.say("Decode complete!")
615
+ return img
616
+ }
617
+
618
+ fn writeMCU:void (img:ImageBuffer mcuX:int mcuY:int yBlocksData:[int] yBlockCount:int cbBlock:[int] crBlock:[int]) {
619
+ ; Write decoded MCU to image, handling YCbCr to RGB conversion
620
+ ; yBlocksData is a flat array: block0[64], block1[64], ...
621
+
622
+ def baseX:int (mcuX * mcuWidth)
623
+ def baseY:int (mcuY * mcuHeight)
624
+
625
+ ; Get Y component from first component for dimensions
626
+ def comp0:JPEGComponent (at components 0)
627
+
628
+ ; Simple case: 1x1 sampling (no subsampling)
629
+ if ((maxHSamp == 1) && (maxVSamp == 1)) {
630
+ def py 0
631
+ while (py < 8) {
632
+ def px 0
633
+ while (px < 8) {
634
+ def imgX:int (baseX + px)
635
+ def imgY:int (baseY + py)
636
+
637
+ if ((imgX < width) && (imgY < height)) {
638
+ def idx:int ((py * 8) + px)
639
+ def y:int (at yBlocksData idx)
640
+
641
+ def cb:int 128
642
+ def cr:int 128
643
+ if (numComponents >= 3) {
644
+ cb = (at cbBlock idx)
645
+ cr = (at crBlock idx)
646
+ }
647
+
648
+ ; YCbCr to RGB
649
+ def r:int (y + (bit_shr (359 * (cr - 128)) 8))
650
+ def g:int (y - (bit_shr (88 * (cb - 128)) 8) - (bit_shr (183 * (cr - 128)) 8))
651
+ def b:int (y + (bit_shr (454 * (cb - 128)) 8))
652
+
653
+ if (r < 0) { r = 0 }
654
+ if (r > 255) { r = 255 }
655
+ if (g < 0) { g = 0 }
656
+ if (g > 255) { g = 255 }
657
+ if (b < 0) { b = 0 }
658
+ if (b > 255) { b = 255 }
659
+
660
+ img.setPixelRGB(imgX imgY r g b)
661
+ }
662
+ px = px + 1
663
+ }
664
+ py = py + 1
665
+ }
666
+ return
667
+ }
668
+
669
+ ; 2x2 subsampling (4:2:0) - most common
670
+ if ((maxHSamp == 2) && (maxVSamp == 2)) {
671
+ ; 4 Y blocks, 1 Cb, 1 Cr
672
+ ; Y blocks are stored sequentially: block0 at offset 0, block1 at 64, etc.
673
+ def blockIdx 0
674
+ def blockY 0
675
+ while (blockY < 2) {
676
+ def blockX 0
677
+ while (blockX < 2) {
678
+ def yBlockOffset:int (blockIdx * 64)
679
+
680
+ def py 0
681
+ while (py < 8) {
682
+ def px 0
683
+ while (px < 8) {
684
+ def imgX:int (baseX + (blockX * 8) + px)
685
+ def imgY:int (baseY + (blockY * 8) + py)
686
+
687
+ if ((imgX < width) && (imgY < height)) {
688
+ def yIdx:int (yBlockOffset + (py * 8) + px)
689
+ def y:int (at yBlocksData yIdx)
690
+
691
+ ; Cb/Cr are subsampled - calculate index
692
+ def chromaX:int ((blockX * 4) + (bit_shr px 1))
693
+ def chromaY:int ((blockY * 4) + (bit_shr py 1))
694
+ def chromaIdx:int ((chromaY * 8) + chromaX)
695
+
696
+ def cb:int 128
697
+ def cr:int 128
698
+ if (numComponents >= 3) {
699
+ cb = (at cbBlock chromaIdx)
700
+ cr = (at crBlock chromaIdx)
701
+ }
702
+
703
+ ; YCbCr to RGB
704
+ def r:int (y + (bit_shr (359 * (cr - 128)) 8))
705
+ def g:int (y - (bit_shr (88 * (cb - 128)) 8) - (bit_shr (183 * (cr - 128)) 8))
706
+ def b:int (y + (bit_shr (454 * (cb - 128)) 8))
707
+
708
+ if (r < 0) { r = 0 }
709
+ if (r > 255) { r = 255 }
710
+ if (g < 0) { g = 0 }
711
+ if (g > 255) { g = 255 }
712
+ if (b < 0) { b = 0 }
713
+ if (b > 255) { b = 255 }
714
+
715
+ img.setPixelRGB(imgX imgY r g b)
716
+ }
717
+ px = px + 1
718
+ }
719
+ py = py + 1
720
+ }
721
+
722
+ blockIdx = blockIdx + 1
723
+ blockX = blockX + 1
724
+ }
725
+ blockY = blockY + 1
726
+ }
727
+ return
728
+ }
729
+
730
+ ; 2x1 subsampling (4:2:2) - horizontal subsampling only
731
+ if ((maxHSamp == 2) && (maxVSamp == 1)) {
732
+ ; 2 Y blocks side by side, 1 Cb, 1 Cr
733
+ ; MCU is 16x8 pixels
734
+ ; Y block 0 covers pixels 0-7 horizontally
735
+ ; Y block 1 covers pixels 8-15 horizontally
736
+ ; Cb/Cr are subsampled 2:1 horizontally (each chroma sample covers 2 Y samples)
737
+
738
+ def blockX 0
739
+ while (blockX < 2) {
740
+ def yBlockOffset:int (blockX * 64)
741
+
742
+ def py 0
743
+ while (py < 8) {
744
+ def px 0
745
+ while (px < 8) {
746
+ def imgX:int (baseX + (blockX * 8) + px)
747
+ def imgY:int (baseY + py)
748
+
749
+ if ((imgX < width) && (imgY < height)) {
750
+ def yIdx:int (yBlockOffset + (py * 8) + px)
751
+ def y:int (at yBlocksData yIdx)
752
+
753
+ ; Cb/Cr are subsampled horizontally only
754
+ ; chromaX = (blockX * 4) + (px / 2), maps 16 px to 8
755
+ ; chromaY = py (no vertical subsampling)
756
+ def chromaX:int ((blockX * 4) + (bit_shr px 1))
757
+ def chromaY:int py
758
+ def chromaIdx:int ((chromaY * 8) + chromaX)
759
+
760
+ def cb:int 128
761
+ def cr:int 128
762
+ if (numComponents >= 3) {
763
+ cb = (at cbBlock chromaIdx)
764
+ cr = (at crBlock chromaIdx)
765
+ }
766
+
767
+ ; YCbCr to RGB
768
+ def r:int (y + (bit_shr (359 * (cr - 128)) 8))
769
+ def g:int (y - (bit_shr (88 * (cb - 128)) 8) - (bit_shr (183 * (cr - 128)) 8))
770
+ def b:int (y + (bit_shr (454 * (cb - 128)) 8))
771
+
772
+ if (r < 0) { r = 0 }
773
+ if (r > 255) { r = 255 }
774
+ if (g < 0) { g = 0 }
775
+ if (g > 255) { g = 255 }
776
+ if (b < 0) { b = 0 }
777
+ if (b > 255) { b = 255 }
778
+
779
+ img.setPixelRGB(imgX imgY r g b)
780
+ }
781
+ px = px + 1
782
+ }
783
+ py = py + 1
784
+ }
785
+ blockX = blockX + 1
786
+ }
787
+ return
788
+ }
789
+
790
+ ; Fallback: treat as grayscale
791
+ if (yBlockCount > 0) {
792
+ def py 0
793
+ while (py < 8) {
794
+ def px 0
795
+ while (px < 8) {
796
+ def imgX:int (baseX + px)
797
+ def imgY:int (baseY + py)
798
+ if ((imgX < width) && (imgY < height)) {
799
+ def y:int (at yBlocksData ((py * 8) + px))
800
+ img.setPixelRGB(imgX imgY y y y)
801
+ }
802
+ px = px + 1
803
+ }
804
+ py = py + 1
805
+ }
806
+ }
807
+ }
808
+ }