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.
- package/CHANGELOG.md +1160 -19
- package/LICENSE +3 -1
- package/README.md +124 -29
- package/dist/Lang.rgr +1188 -290
- package/dist/api.d.ts +2343 -879
- package/dist/api.js +79924 -56922
- package/dist/lib/JSON.rgr +102 -91
- package/dist/lib/Shell.rgr +4 -4
- package/dist/lib/apple/AppleToolchain.rgr +4 -4
- package/dist/lib/apple/README.md +5 -4
- package/dist/lib/apple/apple_test.rgr +1 -1
- package/dist/lib/core/README.md +1 -1
- package/dist/lib/evg/EVG.rgr +12 -0
- package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
- package/dist/lib/evg/EVGA11yTree.rgr +894 -0
- package/dist/lib/evg/EVGBox.rgr +267 -0
- package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
- package/dist/lib/evg/EVGCodepoint.rgr +316 -0
- package/dist/lib/evg/EVGColor.rgr +700 -0
- package/dist/lib/evg/EVGCommands.rgr +177 -0
- package/dist/lib/evg/EVGComponent.rgr +331 -0
- package/dist/lib/evg/EVGComponentTest.rgr +387 -0
- package/dist/lib/evg/EVGConnector.rgr +541 -0
- package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
- package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
- package/dist/lib/evg/EVGEasing.rgr +370 -0
- package/dist/lib/evg/EVGEffectTest.rgr +253 -0
- package/dist/lib/evg/EVGElement.rgr +4914 -0
- package/dist/lib/evg/EVGFixedTest.rgr +289 -0
- package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
- package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
- package/dist/lib/evg/EVGFling.rgr +244 -0
- package/dist/lib/evg/EVGFocus.rgr +400 -0
- package/dist/lib/evg/EVGFocusTest.rgr +399 -0
- package/dist/lib/evg/EVGGradient.rgr +322 -0
- package/dist/lib/evg/EVGGrapheme.rgr +190 -0
- package/dist/lib/evg/EVGGrid.rgr +975 -0
- package/dist/lib/evg/EVGHitTest.rgr +208 -0
- package/dist/lib/evg/EVGHoles.rgr +294 -0
- package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
- package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
- package/dist/lib/evg/EVGHostTree.rgr +834 -0
- package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
- package/dist/lib/evg/EVGImageDecode.rgr +117 -0
- package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
- package/dist/lib/evg/EVGInspect.rgr +883 -0
- package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
- package/dist/lib/evg/EVGJsonTest.rgr +535 -0
- package/dist/lib/evg/EVGLayout.rgr +4220 -0
- package/dist/lib/evg/EVGMeasure.rgr +1267 -0
- package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
- package/dist/lib/evg/EVGPatch.rgr +1721 -0
- package/dist/lib/evg/EVGPatchTest.rgr +692 -0
- package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
- package/dist/lib/evg/EVGReconcile.rgr +226 -0
- package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
- package/dist/lib/evg/EVGReject.rgr +126 -0
- package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
- package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
- package/dist/lib/evg/EVGRuler.rgr +232 -0
- package/dist/lib/evg/EVGRulerTest.rgr +172 -0
- package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
- package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
- package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
- package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
- package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
- package/dist/lib/evg/EVGText.rgr +105 -0
- package/dist/lib/evg/EVGTextEngine.rgr +536 -0
- package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
- package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
- package/dist/lib/evg/EVGToolbar.rgr +1369 -0
- package/dist/lib/evg/EVGTransition.rgr +728 -0
- package/dist/lib/evg/EVGTreeJson.rgr +721 -0
- package/dist/lib/evg/EVGUnit.rgr +554 -0
- package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
- package/dist/lib/evg/EvgApp.rgr +189 -0
- package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
- package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
- package/dist/lib/evg/EvgHost.rgr +451 -0
- package/dist/lib/evg/EvgTest.rgr +91 -0
- package/dist/lib/evg/EvgTraceColor.rgr +236 -0
- package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
- package/dist/lib/evg/EvgTraceFit.rgr +767 -0
- package/dist/lib/evg/EvgTracePath.rgr +435 -0
- package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
- package/dist/lib/evg/EvgViewport.rgr +313 -0
- package/dist/lib/evg/FxDemoDoc.rgr +185 -0
- package/dist/lib/evg/HOSTS.md +227 -0
- package/dist/lib/evg/ISSUES.md +835 -0
- package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
- package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
- package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
- package/dist/lib/evg/PLAN_EVG.md +518 -0
- package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
- package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
- package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
- package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
- package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
- package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
- package/dist/lib/evg/PathBuilder.rgr +333 -0
- package/dist/lib/evg/README.md +1236 -0
- package/dist/lib/evg/SPEC.md +1252 -0
- package/dist/lib/evg/SVGPathParser.rgr +1199 -0
- package/dist/lib/evg/SvgParser.rgr +1736 -0
- package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
- package/dist/lib/evg/VectorShapes.rgr +331 -0
- package/dist/lib/evg/VectorStroke.rgr +107 -0
- package/dist/lib/evg/VectorViewBox.rgr +380 -0
- package/dist/lib/evg/agent/README.md +290 -0
- package/dist/lib/evg/agent/evg_agent.rgr +899 -0
- package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
- package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
- package/dist/lib/evg/agent/fixtures/connector.css +63 -0
- package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
- package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
- package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
- package/dist/lib/evg/agent/fixtures/popover.css +99 -0
- package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
- package/dist/lib/evg/agent/roundtrip.sh +74 -0
- package/dist/lib/evg/agent/smoke.sh +230 -0
- package/dist/lib/evg/android/README.md +97 -0
- package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
- package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
- package/dist/lib/evg/android/androidstubs/App.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
- package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
- package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
- package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
- package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
- package/dist/lib/evg/android/androidstubs/View.kt +113 -0
- package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
- package/dist/lib/evg/apple/README.md +128 -0
- package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
- package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
- package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
- package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
- package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
- package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
- package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
- package/dist/lib/evg/bench/README.md +64 -0
- package/dist/lib/evg/bench/layout-bench.mjs +316 -0
- package/dist/lib/evg/bench/layout-cases.mjs +510 -0
- package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
- package/dist/lib/evg/bin/.gitignore +17 -0
- package/dist/lib/evg/evg_test.rgr +313 -0
- package/dist/lib/evg/gl/README.md +198 -0
- package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
- package/dist/lib/evg/gl/blur-check.mjs +399 -0
- package/dist/lib/evg/gl/boxmodel.json +1 -0
- package/dist/lib/evg/gl/demo.html +46 -0
- package/dist/lib/evg/gl/effect-presets.css +285 -0
- package/dist/lib/evg/gl/effect-presets.js +63 -0
- package/dist/lib/evg/gl/effect-shots.mjs +135 -0
- package/dist/lib/evg/gl/evg-a11y.js +566 -0
- package/dist/lib/evg/gl/evg-binary.js +160 -0
- package/dist/lib/evg/gl/evg-engine.js +296 -0
- package/dist/lib/evg/gl/evg-fx.js +237 -0
- package/dist/lib/evg/gl/evg-gestures.js +209 -0
- package/dist/lib/evg/gl/evg-list.js +167 -0
- package/dist/lib/evg/gl/evg-measure.js +186 -0
- package/dist/lib/evg/gl/evg-textinput.js +303 -0
- package/dist/lib/evg/gl/evg-view.js +144 -0
- package/dist/lib/evg/gl/evg-webgl.js +3942 -0
- package/dist/lib/evg/gl/fx-check.mjs +998 -0
- package/dist/lib/evg/gl/fx-demo.html +166 -0
- package/dist/lib/evg/gl/fx-demo.js +2 -0
- package/dist/lib/evg/gl/fx-serve.mjs +47 -0
- package/dist/lib/evg/gl/gestures-check.mjs +189 -0
- package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
- package/dist/lib/evg/gl/measure-check.mjs +135 -0
- package/dist/lib/evg/gl/rotation-check.mjs +207 -0
- package/dist/lib/evg/gl/shift-check.mjs +113 -0
- package/dist/lib/evg/gl/stroke-check.mjs +168 -0
- package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
- package/dist/lib/evg/gl/view-check.mjs +343 -0
- package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
- package/dist/lib/evg/html/evg-dom.js +318 -0
- package/dist/lib/evg/html/evg-html.js +600 -0
- package/dist/lib/evg/inspect/README.md +415 -0
- package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
- package/dist/lib/evg/inspect/evg-inspect.js +947 -0
- package/dist/lib/evg/inspect/shots/css.png +0 -0
- package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
- package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
- package/dist/lib/evg/inspect/shots/state.png +0 -0
- package/dist/lib/evg/inspect/shots.mjs +226 -0
- package/dist/lib/evg/oracle/css-blur.json +576 -0
- package/dist/lib/evg/oracle/css-box.json +157 -0
- package/dist/lib/evg/oracle/css-timing.json +709 -0
- package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
- package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
- package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
- package/dist/lib/evg/original/EVGColor.clj +310 -0
- package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
- package/dist/lib/evg/original/SVGPath.rgr +627 -0
- package/dist/lib/evg/original/Vec2.crgr +103 -0
- package/dist/lib/evg/ranger.json +9 -0
- package/dist/lib/evg/showcase/README.md +246 -0
- package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
- package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
- package/dist/lib/evg/showcase/build.mjs +651 -0
- package/dist/lib/evg/showcase/pages/album.tsx +30 -0
- package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
- package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
- package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
- package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
- package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
- package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
- package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
- package/dist/lib/evg/showcase/pages/more.tsx +332 -0
- package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
- package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
- package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
- package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
- package/dist/lib/evg/showcase/pages/units.tsx +35 -0
- package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
- package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
- package/dist/lib/evg/showcase/pages/views.tsx +223 -0
- package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
- package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
- package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
- package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
- package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
- package/dist/lib/evg/showcase/themes/more-default.css +128 -0
- package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
- package/dist/lib/evg/showcase/themes/showcase.css +508 -0
- package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
- package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
- package/dist/lib/evg/showcase/themes/views-default.css +15 -0
- package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
- package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
- package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
- package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
- package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
- package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
- package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
- package/dist/lib/evg/web/responsive/README.md +97 -0
- package/dist/lib/evg/web/responsive/build.mjs +90 -0
- package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
- package/dist/lib/evg/web/responsive/index.html +177 -0
- package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
- package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
- package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
- package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
- package/dist/lib/evg/web/tools/minify.mjs +60 -0
- package/dist/lib/evg/web/tracer/build.mjs +87 -0
- package/dist/lib/evg/web/tracer/index.html +2805 -0
- package/dist/lib/evg/web/tracer/sample.png +0 -0
- package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
- package/dist/lib/evgr/Cargo.lock +21 -0
- package/dist/lib/evgr/Cargo.toml +19 -0
- package/dist/lib/evgr/README.md +140 -0
- package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
- package/dist/lib/evgr/bench/compare.mjs +252 -0
- package/dist/lib/evgr/bench/speed.mjs +277 -0
- package/dist/lib/evgr/bin/.gitignore +3 -0
- package/dist/lib/evgr/src/bin/bench.rs +106 -0
- package/dist/lib/evgr/src/bin/smoke.rs +13 -0
- package/dist/lib/evgr/src/grid.rs +730 -0
- package/dist/lib/evgr/src/lib.rs +1003 -0
- package/dist/lib/evgr/src/style.rs +468 -0
- package/dist/lib/evgr/src/text.rs +83 -0
- package/dist/lib/image/BitReader.rgr +171 -0
- package/dist/lib/image/Buffer.rgr +173 -0
- package/dist/lib/image/DCT.rgr +283 -0
- package/dist/lib/image/Deflate.rgr +339 -0
- package/dist/lib/image/HuffmanDecoder.rgr +181 -0
- package/dist/lib/image/ImageBuffer.rgr +706 -0
- package/dist/lib/image/JPEGDecoder.rgr +808 -0
- package/dist/lib/image/PNGDecoder.rgr +544 -0
- package/dist/lib/image/PNGEncoder.rgr +388 -0
- package/dist/lib/image/PPMImage.rgr +224 -0
- package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
- package/dist/lib/image/README.md +33 -0
- package/dist/lib/image/RasterBuffer.rgr +294 -0
- package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
- package/dist/lib/image/WebPDecoder.rgr +433 -0
- package/dist/lib/image/WebPLossless.rgr +1035 -0
- package/dist/lib/image/WebPLossy.rgr +1929 -0
- package/dist/lib/image/ranger.json +9 -0
- package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
- package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
- package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
- package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
- package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
- package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
- package/dist/lib/image/tests/run_webp_tests.sh +39 -0
- package/dist/lib/rust/RsJson.rgr +468 -0
- package/dist/lib/rust/RsPrelude.rgr +1663 -0
- package/dist/lib/shell_test.rgr +7 -7
- package/dist/lib/stdlib.rgr +21 -5
- package/dist/lib/zip/ranger.json +6 -0
- package/dist/rgrc.js +87318 -67610
- package/package.json +1010 -1040
- package/dist/README.md +0 -117
- package/dist/package.json +0 -47
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
Import "RasterBuffer.rgr"
|
|
4
|
+
Import "Deflate.rgr"
|
|
5
|
+
Import "Buffer.rgr"
|
|
6
|
+
|
|
7
|
+
; PNG Encoder - Lossless image output
|
|
8
|
+
; Implements basic PNG format with uncompressed DEFLATE
|
|
9
|
+
|
|
10
|
+
class PNGEncoder {
|
|
11
|
+
def output:GrowableBuffer
|
|
12
|
+
def crcTable:[int]
|
|
13
|
+
def crcTableInit:boolean false
|
|
14
|
+
; Emit uncompressed deflate blocks instead of compressing. What this file
|
|
15
|
+
; used to do always.
|
|
16
|
+
def stored:boolean false
|
|
17
|
+
|
|
18
|
+
Constructor () {
|
|
19
|
+
output = (new GrowableBuffer())
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
; Initialize CRC32 lookup table
|
|
23
|
+
fn initCRCTable:void () {
|
|
24
|
+
if crcTableInit {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
def n:int 0
|
|
28
|
+
while (n < 256) {
|
|
29
|
+
def c:int n
|
|
30
|
+
def k:int 0
|
|
31
|
+
while (k < 8) {
|
|
32
|
+
if ((bit_and c 1) != 0) {
|
|
33
|
+
; EDB88320 in decimal = 3988292384
|
|
34
|
+
c = (bit_xor (bit_ushr c 1) 3988292384)
|
|
35
|
+
} {
|
|
36
|
+
c = (bit_ushr c 1)
|
|
37
|
+
}
|
|
38
|
+
k = k + 1
|
|
39
|
+
}
|
|
40
|
+
push crcTable c
|
|
41
|
+
n = n + 1
|
|
42
|
+
}
|
|
43
|
+
crcTableInit = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
; Calculate CRC32 of a GrowableBuffer section
|
|
47
|
+
fn crc32Buffer:int (data:GrowableBuffer) {
|
|
48
|
+
this.initCRCTable()
|
|
49
|
+
; FFFFFFFF in decimal = 4294967295
|
|
50
|
+
def crc:int 4294967295
|
|
51
|
+
def buf:buffer (data.toBuffer())
|
|
52
|
+
def len:int (data.size())
|
|
53
|
+
def i:int 0
|
|
54
|
+
while (i < len) {
|
|
55
|
+
def byte:int (buffer_get buf i)
|
|
56
|
+
def idx:int (bit_and (bit_xor crc byte) 255)
|
|
57
|
+
crc = (bit_xor (bit_ushr crc 8) (itemAt crcTable idx))
|
|
58
|
+
i = i + 1
|
|
59
|
+
}
|
|
60
|
+
return (bit_xor crc 4294967295)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
; Write PNG signature
|
|
64
|
+
fn writeSignature:void () {
|
|
65
|
+
output.writeByte(137) ; 0x89
|
|
66
|
+
output.writeByte(80) ; P
|
|
67
|
+
output.writeByte(78) ; N
|
|
68
|
+
output.writeByte(71) ; G
|
|
69
|
+
output.writeByte(13) ; 0x0D
|
|
70
|
+
output.writeByte(10) ; 0x0A
|
|
71
|
+
output.writeByte(26) ; 0x1A
|
|
72
|
+
output.writeByte(10) ; 0x0A
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
; Write 32-bit big-endian integer
|
|
76
|
+
fn writeUInt32:void (value:int) {
|
|
77
|
+
output.writeByte((bit_and (bit_shr value 24) 255))
|
|
78
|
+
output.writeByte((bit_and (bit_shr value 16) 255))
|
|
79
|
+
output.writeByte((bit_and (bit_shr value 8) 255))
|
|
80
|
+
output.writeByte((bit_and value 255))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
; Write 32-bit big-endian to a GrowableBuffer
|
|
84
|
+
fn writeUInt32To:void (buf:GrowableBuffer value:int) {
|
|
85
|
+
buf.writeByte((bit_and (bit_shr value 24) 255))
|
|
86
|
+
buf.writeByte((bit_and (bit_shr value 16) 255))
|
|
87
|
+
buf.writeByte((bit_and (bit_shr value 8) 255))
|
|
88
|
+
buf.writeByte((bit_and value 255))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
; Write a PNG chunk
|
|
92
|
+
fn writeChunk:void (chunkType:string data:GrowableBuffer) {
|
|
93
|
+
def dataLen:int (data.size())
|
|
94
|
+
|
|
95
|
+
; Length
|
|
96
|
+
this.writeUInt32(dataLen)
|
|
97
|
+
|
|
98
|
+
; Build chunk type + data for CRC
|
|
99
|
+
def crcData:GrowableBuffer (new GrowableBuffer())
|
|
100
|
+
def i:int 0
|
|
101
|
+
while (i < 4) {
|
|
102
|
+
def ch:int (charAt chunkType i)
|
|
103
|
+
crcData.writeByte(ch)
|
|
104
|
+
output.writeByte(ch)
|
|
105
|
+
i = i + 1
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
; Data
|
|
109
|
+
def dataBuf:buffer (data.toBuffer())
|
|
110
|
+
i = 0
|
|
111
|
+
while (i < dataLen) {
|
|
112
|
+
def b:int (buffer_get dataBuf i)
|
|
113
|
+
crcData.writeByte(b)
|
|
114
|
+
output.writeByte(b)
|
|
115
|
+
i = i + 1
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
; CRC
|
|
119
|
+
def crc:int (this.crc32Buffer(crcData))
|
|
120
|
+
this.writeUInt32(crc)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
; Write IHDR chunk (colorType 2 = RGB).
|
|
124
|
+
fn writeIHDR:void (width:int height:int) {
|
|
125
|
+
this.writeIHDRColor(width height 2)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn writeIHDRColor:void (width:int height:int colorType:int) {
|
|
129
|
+
def data:GrowableBuffer (new GrowableBuffer())
|
|
130
|
+
|
|
131
|
+
; Width (4 bytes)
|
|
132
|
+
this.writeUInt32To(data width)
|
|
133
|
+
|
|
134
|
+
; Height (4 bytes)
|
|
135
|
+
this.writeUInt32To(data height)
|
|
136
|
+
|
|
137
|
+
; Bit depth: 8
|
|
138
|
+
data.writeByte(8)
|
|
139
|
+
data.writeByte(colorType)
|
|
140
|
+
; Compression method: 0 = deflate
|
|
141
|
+
data.writeByte(0)
|
|
142
|
+
; Filter method: 0
|
|
143
|
+
data.writeByte(0)
|
|
144
|
+
; Interlace method: 0 = none
|
|
145
|
+
data.writeByte(0)
|
|
146
|
+
|
|
147
|
+
this.writeChunk("IHDR" data)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
; Adler32 checksum for zlib
|
|
151
|
+
fn adler32:int (data:GrowableBuffer) {
|
|
152
|
+
def a:int 1
|
|
153
|
+
def b:int 0
|
|
154
|
+
def buf:buffer (data.toBuffer())
|
|
155
|
+
def len:int (data.size())
|
|
156
|
+
def i:int 0
|
|
157
|
+
while (i < len) {
|
|
158
|
+
a = ((a + (buffer_get buf i)) % 65521)
|
|
159
|
+
b = ((b + a) % 65521)
|
|
160
|
+
i = i + 1
|
|
161
|
+
}
|
|
162
|
+
return (bit_or (bit_shl b 16) a)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
; Create uncompressed DEFLATE blocks (store mode)
|
|
166
|
+
; Compressed with fixed-Huffman deflate. Stored blocks are the fallback,
|
|
167
|
+
; kept because they are the one encoding that cannot be wrong — a bug here
|
|
168
|
+
; would be a file nothing opens, and `stored` is one flag away.
|
|
169
|
+
fn createDeflateData:void (rawData:GrowableBuffer compressed:GrowableBuffer) {
|
|
170
|
+
if (stored == false) {
|
|
171
|
+
def dz (new Deflate)
|
|
172
|
+
def w (new DeflateWriter)
|
|
173
|
+
dz.compress((rawData.toBuffer()) (rawData.size()) w)
|
|
174
|
+
def packed:buffer (w.out.toBuffer())
|
|
175
|
+
def pi:int 0
|
|
176
|
+
def pn:int (w.out.size())
|
|
177
|
+
while (pi < pn) {
|
|
178
|
+
compressed.writeByte((buffer_get packed pi))
|
|
179
|
+
pi = (pi + 1)
|
|
180
|
+
}
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
def rawBuf:buffer (rawData.toBuffer())
|
|
184
|
+
def dataLen:int (rawData.size())
|
|
185
|
+
def blockSize:int 65535 ; Max block size
|
|
186
|
+
def offset:int 0
|
|
187
|
+
|
|
188
|
+
while (offset < dataLen) {
|
|
189
|
+
def remaining:int (dataLen - offset)
|
|
190
|
+
def len:int blockSize
|
|
191
|
+
if (remaining < len) {
|
|
192
|
+
len = remaining
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
def isFinal:int 0
|
|
196
|
+
if ((offset + len) >= dataLen) {
|
|
197
|
+
isFinal = 1
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
; Block header: BFINAL=1/0, BTYPE=00 (stored)
|
|
201
|
+
compressed.writeByte(isFinal)
|
|
202
|
+
|
|
203
|
+
; LEN (2 bytes, little-endian)
|
|
204
|
+
compressed.writeByte((bit_and len 255))
|
|
205
|
+
compressed.writeByte((bit_and (bit_shr len 8) 255))
|
|
206
|
+
|
|
207
|
+
; NLEN (one's complement of LEN)
|
|
208
|
+
def nlen:int (bit_xor len 65535)
|
|
209
|
+
compressed.writeByte((bit_and nlen 255))
|
|
210
|
+
compressed.writeByte((bit_and (bit_shr nlen 8) 255))
|
|
211
|
+
|
|
212
|
+
; Data
|
|
213
|
+
def i:int 0
|
|
214
|
+
while (i < len) {
|
|
215
|
+
compressed.writeByte((buffer_get rawBuf (offset + i)))
|
|
216
|
+
i = i + 1
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
offset = offset + len
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
; Write IDAT chunk with image data
|
|
224
|
+
fn writeIDAT:void (buf:RasterBuffer) {
|
|
225
|
+
; Build raw scanline data with filter bytes
|
|
226
|
+
def rawData:GrowableBuffer (new GrowableBuffer())
|
|
227
|
+
|
|
228
|
+
def y:int 0
|
|
229
|
+
while (y < buf.height) {
|
|
230
|
+
; Filter type: 0 = None
|
|
231
|
+
rawData.writeByte(0)
|
|
232
|
+
|
|
233
|
+
def x:int 0
|
|
234
|
+
while (x < buf.width) {
|
|
235
|
+
def idx:int ((y * buf.width + x) * 4)
|
|
236
|
+
def r:int (buffer_get buf.pixels idx)
|
|
237
|
+
def g:int (buffer_get buf.pixels (idx + 1))
|
|
238
|
+
def b:int (buffer_get buf.pixels (idx + 2))
|
|
239
|
+
def a:int (buffer_get buf.pixels (idx + 3))
|
|
240
|
+
; A three-channel PNG cannot carry alpha, so a translucent
|
|
241
|
+
; pixel has to be composited against something. White: this is
|
|
242
|
+
; the format a picture is pasted into a document as, and a
|
|
243
|
+
; document's page is white. It used to premultiply against
|
|
244
|
+
; black with `>> 8`, which is a divide by 256 rather than 255 —
|
|
245
|
+
; so a pixel the text renderer left at alpha 254, which every
|
|
246
|
+
; antialiased glyph edge is, came out two levels darker than it
|
|
247
|
+
; was drawn, and a round trip through our own decoder could not
|
|
248
|
+
; get back what was painted.
|
|
249
|
+
if (a < 255) {
|
|
250
|
+
def inv:int (255 - a)
|
|
251
|
+
r = (idiv (((r * a) + (255 * inv)) + 127) 255)
|
|
252
|
+
g = (idiv (((g * a) + (255 * inv)) + 127) 255)
|
|
253
|
+
b = (idiv (((b * a) + (255 * inv)) + 127) 255)
|
|
254
|
+
}
|
|
255
|
+
rawData.writeByte(r)
|
|
256
|
+
rawData.writeByte(g)
|
|
257
|
+
rawData.writeByte(b)
|
|
258
|
+
x = x + 1
|
|
259
|
+
}
|
|
260
|
+
y = y + 1
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
; Wrap in zlib format
|
|
264
|
+
def zlibData:GrowableBuffer (new GrowableBuffer())
|
|
265
|
+
|
|
266
|
+
; Zlib header (CMF, FLG)
|
|
267
|
+
zlibData.writeByte(120) ; 0x78 CMF: CM=8 (deflate), CINFO=7 (32K window)
|
|
268
|
+
zlibData.writeByte(1) ; 0x01 FLG: no dict, level 0
|
|
269
|
+
|
|
270
|
+
; DEFLATE data
|
|
271
|
+
this.createDeflateData(rawData zlibData)
|
|
272
|
+
|
|
273
|
+
; Adler32 checksum (big-endian)
|
|
274
|
+
def adler:int (this.adler32(rawData))
|
|
275
|
+
zlibData.writeByte((bit_and (bit_shr adler 24) 255))
|
|
276
|
+
zlibData.writeByte((bit_and (bit_shr adler 16) 255))
|
|
277
|
+
zlibData.writeByte((bit_and (bit_shr adler 8) 255))
|
|
278
|
+
zlibData.writeByte((bit_and adler 255))
|
|
279
|
+
|
|
280
|
+
this.writeChunk("IDAT" zlibData)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
; Write IDAT chunk with RGBA scanlines (color type 6).
|
|
284
|
+
fn writeIDATRgba:void (buf:RasterBuffer) {
|
|
285
|
+
def rawData:GrowableBuffer (new GrowableBuffer())
|
|
286
|
+
|
|
287
|
+
def y:int 0
|
|
288
|
+
while (y < buf.height) {
|
|
289
|
+
rawData.writeByte(0)
|
|
290
|
+
def x:int 0
|
|
291
|
+
while (x < buf.width) {
|
|
292
|
+
def idx:int ((y * buf.width + x) * 4)
|
|
293
|
+
rawData.writeByte((buffer_get buf.pixels idx))
|
|
294
|
+
rawData.writeByte((buffer_get buf.pixels (idx + 1)))
|
|
295
|
+
rawData.writeByte((buffer_get buf.pixels (idx + 2)))
|
|
296
|
+
rawData.writeByte((buffer_get buf.pixels (idx + 3)))
|
|
297
|
+
x = (x + 1)
|
|
298
|
+
}
|
|
299
|
+
y = (y + 1)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
def zlibData:GrowableBuffer (new GrowableBuffer())
|
|
303
|
+
zlibData.writeByte(120)
|
|
304
|
+
zlibData.writeByte(1)
|
|
305
|
+
this.createDeflateData(rawData zlibData)
|
|
306
|
+
def adler:int (this.adler32(rawData))
|
|
307
|
+
zlibData.writeByte((bit_and (bit_shr adler 24) 255))
|
|
308
|
+
zlibData.writeByte((bit_and (bit_shr adler 16) 255))
|
|
309
|
+
zlibData.writeByte((bit_and (bit_shr adler 8) 255))
|
|
310
|
+
zlibData.writeByte((bit_and adler 255))
|
|
311
|
+
this.writeChunk("IDAT" zlibData)
|
|
312
|
+
}
|
|
313
|
+
fn writeIEND:void () {
|
|
314
|
+
def data:GrowableBuffer (new GrowableBuffer())
|
|
315
|
+
this.writeChunk("IEND" data)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
; The same, without the running commentary. A chart copied to the clipboard
|
|
319
|
+
; encodes a PNG on every Ctrl+C, and three lines of log per keystroke is
|
|
320
|
+
; noise in a server that is otherwise quiet.
|
|
321
|
+
fn encodeQuiet:buffer (buf:RasterBuffer) {
|
|
322
|
+
output = (new GrowableBuffer())
|
|
323
|
+
this.writeSignature()
|
|
324
|
+
this.writeIHDR(buf.width buf.height)
|
|
325
|
+
this.writeIDAT(buf)
|
|
326
|
+
this.writeIEND()
|
|
327
|
+
return (output.toBuffer())
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
; Encode buffer to PNG and return as buffer (for HTTP responses)
|
|
331
|
+
fn encodeToBuffer:buffer (buf:RasterBuffer) {
|
|
332
|
+
print ("Encoding PNG to buffer")
|
|
333
|
+
print (" Image size: " + (to_string buf.width) + "x" + (to_string buf.height))
|
|
334
|
+
|
|
335
|
+
; Reset output
|
|
336
|
+
output = (new GrowableBuffer())
|
|
337
|
+
|
|
338
|
+
this.writeSignature()
|
|
339
|
+
this.writeIHDR(buf.width buf.height)
|
|
340
|
+
this.writeIDAT(buf)
|
|
341
|
+
this.writeIEND()
|
|
342
|
+
|
|
343
|
+
def finalSize:int (output.size())
|
|
344
|
+
print (" Encoded size: " + (to_string finalSize) + " bytes")
|
|
345
|
+
|
|
346
|
+
return (output.toBuffer())
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
; Encode buffer to PNG and save to file
|
|
350
|
+
fn encode:void (buf:RasterBuffer dirPath:string fileName:string) {
|
|
351
|
+
print ("Encoding PNG: " + fileName)
|
|
352
|
+
print (" Image size: " + (to_string buf.width) + "x" + (to_string buf.height))
|
|
353
|
+
|
|
354
|
+
; Reset output
|
|
355
|
+
output = (new GrowableBuffer())
|
|
356
|
+
|
|
357
|
+
this.writeSignature()
|
|
358
|
+
this.writeIHDR(buf.width buf.height)
|
|
359
|
+
this.writeIDAT(buf)
|
|
360
|
+
this.writeIEND()
|
|
361
|
+
|
|
362
|
+
def finalSize:int (output.size())
|
|
363
|
+
print (" Encoded size: " + (to_string finalSize) + " bytes")
|
|
364
|
+
|
|
365
|
+
; Write to file
|
|
366
|
+
def outBuf:buffer (output.toBuffer())
|
|
367
|
+
buffer_write_file dirPath fileName outBuf
|
|
368
|
+
print (" Saved: " + dirPath + "/" + fileName)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
; Encode RGBA PNG (preserves alpha — use for LPC compose sheets).
|
|
372
|
+
fn encodeRgba:void (buf:RasterBuffer dirPath:string fileName:string) {
|
|
373
|
+
print ("Encoding RGBA PNG: " + fileName)
|
|
374
|
+
print (" Image size: " + (to_string buf.width) + "x" + (to_string buf.height))
|
|
375
|
+
|
|
376
|
+
output = (new GrowableBuffer())
|
|
377
|
+
this.writeSignature()
|
|
378
|
+
this.writeIHDRColor(buf.width buf.height 6)
|
|
379
|
+
this.writeIDATRgba(buf)
|
|
380
|
+
this.writeIEND()
|
|
381
|
+
|
|
382
|
+
def finalSize:int (output.size())
|
|
383
|
+
print (" Encoded size: " + (to_string finalSize) + " bytes")
|
|
384
|
+
def outBuf:buffer (output.toBuffer())
|
|
385
|
+
buffer_write_file dirPath fileName outBuf
|
|
386
|
+
print (" Saved: " + dirPath + "/" + fileName)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; PPMImage.rgr - PPM (Portable Pixmap) image reader/writer
|
|
4
|
+
; PPM is a simple uncompressed image format - easy to read/write
|
|
5
|
+
;
|
|
6
|
+
; Format: P6 (binary RGB) or P3 (ASCII RGB)
|
|
7
|
+
; Header: P6\n<width> <height>\n<maxval>\n<binary RGB data>
|
|
8
|
+
|
|
9
|
+
Import "Buffer.rgr"
|
|
10
|
+
Import "ImageBuffer.rgr"
|
|
11
|
+
|
|
12
|
+
class PPMImage {
|
|
13
|
+
|
|
14
|
+
Constructor () {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn parseNumber:int (data:buffer startPos:int endPos:[int]) {
|
|
18
|
+
; Parse ASCII number, skip whitespace, return value and update endPos
|
|
19
|
+
def len:int (buffer_length data)
|
|
20
|
+
def pos:int startPos
|
|
21
|
+
|
|
22
|
+
; Skip whitespace
|
|
23
|
+
def skipping:boolean true
|
|
24
|
+
while (skipping && (pos < len)) {
|
|
25
|
+
def ch:int (buffer_get data pos)
|
|
26
|
+
if ((ch == 32) || (ch == 10) || (ch == 13) || (ch == 9)) {
|
|
27
|
+
pos = pos + 1
|
|
28
|
+
} {
|
|
29
|
+
skipping = false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
; Parse digits
|
|
34
|
+
def value:int 0
|
|
35
|
+
def parsing:boolean true
|
|
36
|
+
while (parsing && (pos < len)) {
|
|
37
|
+
def ch:int (buffer_get data pos)
|
|
38
|
+
if ((ch >= 48) && (ch <= 57)) {
|
|
39
|
+
value = (value * 10) + (ch - 48)
|
|
40
|
+
pos = pos + 1
|
|
41
|
+
} {
|
|
42
|
+
parsing = false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
set endPos 0 pos
|
|
47
|
+
return value
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn skipToNextLine:int (data:buffer pos:int) {
|
|
51
|
+
def len:int (buffer_length data)
|
|
52
|
+
while (pos < len) {
|
|
53
|
+
def ch:int (buffer_get data pos)
|
|
54
|
+
pos = pos + 1
|
|
55
|
+
if (ch == 10) {
|
|
56
|
+
return pos
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return pos
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn load:ImageBuffer (dirPath:string fileName:string) {
|
|
63
|
+
def data:buffer (buffer_read_file dirPath fileName)
|
|
64
|
+
def len:int (buffer_length data)
|
|
65
|
+
|
|
66
|
+
if (len < 10) {
|
|
67
|
+
print ("Error: File too small: " + fileName)
|
|
68
|
+
def errImg (new ImageBuffer())
|
|
69
|
+
errImg.init(1 1)
|
|
70
|
+
return errImg
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
; Check magic number (P6 for binary PPM)
|
|
74
|
+
def m1:int (buffer_get data 0)
|
|
75
|
+
def m2:int (buffer_get data 1)
|
|
76
|
+
|
|
77
|
+
if ((m1 != 80) || ((m2 != 54) && (m2 != 51))) {
|
|
78
|
+
; Not P6 or P3
|
|
79
|
+
print ("Error: Not a PPM file (P3 or P6): " + fileName)
|
|
80
|
+
def errImg (new ImageBuffer())
|
|
81
|
+
errImg.init(1 1)
|
|
82
|
+
return errImg
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
def isBinary:boolean (m2 == 54)
|
|
86
|
+
def pos:int 2
|
|
87
|
+
|
|
88
|
+
; Skip comments and whitespace, parse width, height, maxval
|
|
89
|
+
def endPos:[int]
|
|
90
|
+
push endPos 0
|
|
91
|
+
|
|
92
|
+
; Skip any comments
|
|
93
|
+
def skippingComments:boolean true
|
|
94
|
+
while (skippingComments && (pos < len)) {
|
|
95
|
+
def ch:int (buffer_get data pos)
|
|
96
|
+
if ((ch == 32) || (ch == 10) || (ch == 13) || (ch == 9)) {
|
|
97
|
+
pos = pos + 1
|
|
98
|
+
} {
|
|
99
|
+
if (ch == 35) {
|
|
100
|
+
; Comment line starting with #
|
|
101
|
+
pos = (this.skipToNextLine(data pos))
|
|
102
|
+
} {
|
|
103
|
+
skippingComments = false
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
def width:int (this.parseNumber(data pos endPos))
|
|
109
|
+
pos = (at endPos 0)
|
|
110
|
+
|
|
111
|
+
def height:int (this.parseNumber(data pos endPos))
|
|
112
|
+
pos = (at endPos 0)
|
|
113
|
+
|
|
114
|
+
def maxVal:int (this.parseNumber(data pos endPos))
|
|
115
|
+
pos = (at endPos 0)
|
|
116
|
+
|
|
117
|
+
; Skip single whitespace after maxval
|
|
118
|
+
if (pos < len) {
|
|
119
|
+
pos = pos + 1
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
print ("Loading PPM: " + (to_string width) + "x" + (to_string height) + ", maxval=" + (to_string maxVal))
|
|
123
|
+
|
|
124
|
+
def img (new ImageBuffer())
|
|
125
|
+
img.init(width height)
|
|
126
|
+
|
|
127
|
+
if isBinary {
|
|
128
|
+
; P6: Binary RGB data
|
|
129
|
+
def y 0
|
|
130
|
+
while (y < height) {
|
|
131
|
+
def x 0
|
|
132
|
+
while (x < width) {
|
|
133
|
+
if ((pos + 2) < len) {
|
|
134
|
+
def r:int (buffer_get data pos)
|
|
135
|
+
def g:int (buffer_get data (pos + 1))
|
|
136
|
+
def b:int (buffer_get data (pos + 2))
|
|
137
|
+
img.setPixelRGB(x y r g b)
|
|
138
|
+
pos = pos + 3
|
|
139
|
+
}
|
|
140
|
+
x = x + 1
|
|
141
|
+
}
|
|
142
|
+
y = y + 1
|
|
143
|
+
}
|
|
144
|
+
} {
|
|
145
|
+
; P3: ASCII RGB data
|
|
146
|
+
def y 0
|
|
147
|
+
while (y < height) {
|
|
148
|
+
def x 0
|
|
149
|
+
while (x < width) {
|
|
150
|
+
def r:int (this.parseNumber(data pos endPos))
|
|
151
|
+
pos = (at endPos 0)
|
|
152
|
+
def g:int (this.parseNumber(data pos endPos))
|
|
153
|
+
pos = (at endPos 0)
|
|
154
|
+
def b:int (this.parseNumber(data pos endPos))
|
|
155
|
+
pos = (at endPos 0)
|
|
156
|
+
img.setPixelRGB(x y r g b)
|
|
157
|
+
x = x + 1
|
|
158
|
+
}
|
|
159
|
+
y = y + 1
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return img
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fn save:void (img:ImageBuffer dirPath:string fileName:string) {
|
|
167
|
+
; Save as P6 (binary PPM)
|
|
168
|
+
def buf (new GrowableBuffer())
|
|
169
|
+
|
|
170
|
+
; Header
|
|
171
|
+
buf.writeString("P6\n")
|
|
172
|
+
buf.writeString((to_string img.width) + " " + (to_string img.height) + "\n")
|
|
173
|
+
buf.writeString("255\n")
|
|
174
|
+
|
|
175
|
+
; Pixel data (RGB only, no alpha)
|
|
176
|
+
def y 0
|
|
177
|
+
while (y < img.height) {
|
|
178
|
+
def x 0
|
|
179
|
+
while (x < img.width) {
|
|
180
|
+
def c:Color (img.getPixel(x y))
|
|
181
|
+
buf.writeByte(c.r)
|
|
182
|
+
buf.writeByte(c.g)
|
|
183
|
+
buf.writeByte(c.b)
|
|
184
|
+
x = x + 1
|
|
185
|
+
}
|
|
186
|
+
y = y + 1
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
def data:buffer (buf.toBuffer())
|
|
190
|
+
buffer_write_file dirPath fileName data
|
|
191
|
+
print ("Saved PPM: " + dirPath + "/" + fileName)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
fn saveP3:void (img:ImageBuffer dirPath:string fileName:string) {
|
|
195
|
+
; Save as P3 (ASCII PPM) - larger but human-readable
|
|
196
|
+
def buf (new GrowableBuffer())
|
|
197
|
+
|
|
198
|
+
; Header
|
|
199
|
+
buf.writeString("P3\n")
|
|
200
|
+
buf.writeString("# Created by Ranger ImageEditor\n")
|
|
201
|
+
buf.writeString((to_string img.width) + " " + (to_string img.height) + "\n")
|
|
202
|
+
buf.writeString("255\n")
|
|
203
|
+
|
|
204
|
+
; Pixel data as ASCII
|
|
205
|
+
def y 0
|
|
206
|
+
while (y < img.height) {
|
|
207
|
+
def x 0
|
|
208
|
+
while (x < img.width) {
|
|
209
|
+
def c:Color (img.getPixel(x y))
|
|
210
|
+
buf.writeString((to_string c.r) + " " + (to_string c.g) + " " + (to_string c.b))
|
|
211
|
+
if (x < (img.width - 1)) {
|
|
212
|
+
buf.writeString(" ")
|
|
213
|
+
}
|
|
214
|
+
x = x + 1
|
|
215
|
+
}
|
|
216
|
+
buf.writeString("\n")
|
|
217
|
+
y = y + 1
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
def data:buffer (buf.toBuffer())
|
|
221
|
+
buffer_write_file dirPath fileName data
|
|
222
|
+
print ("Saved PPM (ASCII): " + dirPath + "/" + fileName)
|
|
223
|
+
}
|
|
224
|
+
}
|