@shopify/react-native-skia 2.0.7 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +20 -1
- package/cpp/api/JsiSkApi.h +3 -0
- package/cpp/api/JsiSkImageFilterFactory.h +478 -39
- package/cpp/api/JsiSkSkottie.h +590 -0
- package/cpp/api/JsiSkottieFactory.h +65 -0
- package/cpp/api/recorder/Command.h +1 -0
- package/cpp/api/recorder/Convertor.h +16 -0
- package/cpp/api/recorder/Drawings.h +23 -0
- package/cpp/api/recorder/JsiRecorder.h +6 -0
- package/cpp/api/recorder/RNRecorder.h +9 -0
- package/cpp/api/third_party/SkottieUtils.cpp +333 -0
- package/cpp/api/third_party/SkottieUtils.h +172 -0
- package/cpp/skia/modules/jsonreader/SkJSONReader.cpp +980 -0
- package/cpp/skia/modules/jsonreader/SkJSONReader.h +389 -0
- package/cpp/skia/modules/skottie/include/ExternalLayer.h +56 -0
- package/cpp/skia/modules/skottie/include/Skottie.h +313 -0
- package/cpp/skia/modules/skottie/include/SkottieProperty.h +190 -0
- package/cpp/skia/modules/skottie/include/SlotManager.h +113 -0
- package/cpp/skia/modules/skottie/include/TextShaper.h +200 -0
- package/cpp/skia/modules/skottie/src/SkottieValue.h +56 -0
- package/cpp/skia/modules/skottie/src/animator/Animator.h +89 -0
- package/cpp/skia/modules/skottie/src/text/Font.h +82 -0
- package/cpp/skia/modules/skottie/src/text/TextAdapter.h +155 -0
- package/cpp/skia/modules/skottie/src/text/TextAnimator.h +121 -0
- package/cpp/skia/modules/skottie/src/text/TextValue.h +28 -0
- package/cpp/skia/modules/sksg/include/SkSGClipEffect.h +61 -0
- package/cpp/skia/modules/sksg/include/SkSGColorFilter.h +135 -0
- package/cpp/skia/modules/sksg/include/SkSGDraw.h +57 -0
- package/cpp/skia/modules/sksg/include/SkSGEffectNode.h +50 -0
- package/cpp/skia/modules/sksg/include/SkSGGeometryEffect.h +181 -0
- package/cpp/skia/modules/sksg/include/SkSGGeometryNode.h +54 -0
- package/cpp/skia/modules/sksg/include/SkSGGradient.h +108 -0
- package/cpp/skia/modules/sksg/include/SkSGGroup.h +65 -0
- package/cpp/skia/modules/sksg/include/SkSGImage.h +59 -0
- package/cpp/skia/modules/sksg/include/SkSGInvalidationController.h +46 -0
- package/cpp/skia/modules/sksg/include/SkSGMaskEffect.h +65 -0
- package/cpp/skia/modules/sksg/include/SkSGMerge.h +74 -0
- package/cpp/skia/modules/sksg/include/SkSGNode.h +128 -0
- package/cpp/skia/modules/sksg/include/SkSGOpacityEffect.h +54 -0
- package/cpp/skia/modules/sksg/include/SkSGPaint.h +112 -0
- package/cpp/skia/modules/sksg/include/SkSGPath.h +68 -0
- package/cpp/skia/modules/sksg/include/SkSGPlane.h +47 -0
- package/cpp/skia/modules/sksg/include/SkSGRect.h +122 -0
- package/cpp/skia/modules/sksg/include/SkSGRenderEffect.h +283 -0
- package/cpp/skia/modules/sksg/include/SkSGRenderNode.h +157 -0
- package/cpp/skia/modules/sksg/include/SkSGScene.h +47 -0
- package/cpp/skia/modules/sksg/include/SkSGText.h +82 -0
- package/cpp/skia/modules/sksg/include/SkSGTransform.h +127 -0
- package/cpp/skia/src/base/SkArenaAlloc.h +371 -0
- package/lib/commonjs/dom/nodes/datatypes/Gradient.d.ts +15 -15
- package/lib/commonjs/dom/types/Drawings.d.ts +5 -1
- package/lib/commonjs/dom/types/Drawings.js.map +1 -1
- package/lib/commonjs/dom/types/NodeType.d.ts +2 -1
- package/lib/commonjs/dom/types/NodeType.js +2 -0
- package/lib/commonjs/dom/types/NodeType.js.map +1 -1
- package/lib/commonjs/renderer/__tests__/e2e/AdvancedImageFilters.spec.d.ts +1 -0
- package/lib/commonjs/renderer/__tests__/e2e/Camera.spec.d.ts +21 -0
- package/lib/commonjs/renderer/__tests__/e2e/LightingImageFilters.spec.d.ts +1 -0
- package/lib/commonjs/renderer/__tests__/e2e/Skottie.spec.d.ts +1 -0
- package/lib/commonjs/renderer/__tests__/setup.d.ts +5 -0
- package/lib/commonjs/renderer/components/Skottie.d.ts +4 -0
- package/lib/commonjs/renderer/components/Skottie.js +13 -0
- package/lib/commonjs/renderer/components/Skottie.js.map +1 -0
- package/lib/commonjs/renderer/components/index.d.ts +1 -0
- package/lib/commonjs/renderer/components/index.js +11 -0
- package/lib/commonjs/renderer/components/index.js.map +1 -1
- package/lib/commonjs/skia/types/ImageFilter/ImageFilterFactory.d.ts +252 -15
- package/lib/commonjs/skia/types/ImageFilter/ImageFilterFactory.js.map +1 -1
- package/lib/commonjs/skia/types/Matrix4.d.ts +11 -2
- package/lib/commonjs/skia/types/Matrix4.js +42 -1
- package/lib/commonjs/skia/types/Matrix4.js.map +1 -1
- package/lib/commonjs/skia/types/Recorder.d.ts +2 -1
- package/lib/commonjs/skia/types/Recorder.js.map +1 -1
- package/lib/commonjs/skia/types/Skia.d.ts +2 -0
- package/lib/commonjs/skia/types/Skia.js.map +1 -1
- package/lib/commonjs/skia/types/Skottie.d.ts +223 -0
- package/lib/commonjs/skia/types/Skottie.js +73 -0
- package/lib/commonjs/skia/types/Skottie.js.map +1 -0
- package/lib/commonjs/skia/types/index.d.ts +1 -0
- package/lib/commonjs/skia/types/index.js +11 -0
- package/lib/commonjs/skia/types/index.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkImageFilterFactory.d.ts +29 -12
- package/lib/commonjs/skia/web/JsiSkImageFilterFactory.js +88 -19
- package/lib/commonjs/skia/web/JsiSkImageFilterFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkia.js +2 -0
- package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkottieAnimation.d.ts +59 -0
- package/lib/commonjs/skia/web/JsiSkottieAnimation.js +243 -0
- package/lib/commonjs/skia/web/JsiSkottieAnimation.js.map +1 -0
- package/lib/commonjs/skia/web/JsiSkottieFactory.d.ts +9 -0
- package/lib/commonjs/skia/web/JsiSkottieFactory.js +26 -0
- package/lib/commonjs/skia/web/JsiSkottieFactory.js.map +1 -0
- package/lib/commonjs/sksg/Elements.d.ts +2 -1
- package/lib/commonjs/sksg/Elements.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Core.d.ts +4 -2
- package/lib/commonjs/sksg/Recorder/Core.js +1 -0
- package/lib/commonjs/sksg/Recorder/Core.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Player.js +2 -0
- package/lib/commonjs/sksg/Recorder/Player.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +2 -1
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js +4 -0
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Recorder.d.ts +2 -1
- package/lib/commonjs/sksg/Recorder/Recorder.js +6 -0
- package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Visitor.js +3 -0
- package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/commands/Drawing.d.ts +2 -2
- package/lib/commonjs/sksg/Recorder/commands/Drawing.js +11 -4
- package/lib/commonjs/sksg/Recorder/commands/Drawing.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/commands/ImageFilters.js +1 -1
- package/lib/commonjs/sksg/Recorder/commands/ImageFilters.js.map +1 -1
- package/lib/module/dom/nodes/datatypes/Gradient.d.ts +15 -15
- package/lib/module/dom/types/Drawings.d.ts +5 -1
- package/lib/module/dom/types/Drawings.js.map +1 -1
- package/lib/module/dom/types/NodeType.d.ts +2 -1
- package/lib/module/dom/types/NodeType.js +2 -0
- package/lib/module/dom/types/NodeType.js.map +1 -1
- package/lib/module/renderer/__tests__/e2e/AdvancedImageFilters.spec.d.ts +1 -0
- package/lib/module/renderer/__tests__/e2e/Camera.spec.d.ts +21 -0
- package/lib/module/renderer/__tests__/e2e/LightingImageFilters.spec.d.ts +1 -0
- package/lib/module/renderer/__tests__/e2e/Skottie.spec.d.ts +1 -0
- package/lib/module/renderer/__tests__/setup.d.ts +5 -0
- package/lib/module/renderer/components/Skottie.d.ts +4 -0
- package/lib/module/renderer/components/Skottie.js +5 -0
- package/lib/module/renderer/components/Skottie.js.map +1 -0
- package/lib/module/renderer/components/index.d.ts +1 -0
- package/lib/module/renderer/components/index.js +1 -0
- package/lib/module/renderer/components/index.js.map +1 -1
- package/lib/module/skia/types/ImageFilter/ImageFilterFactory.d.ts +252 -15
- package/lib/module/skia/types/ImageFilter/ImageFilterFactory.js.map +1 -1
- package/lib/module/skia/types/Matrix4.d.ts +11 -2
- package/lib/module/skia/types/Matrix4.js +40 -0
- package/lib/module/skia/types/Matrix4.js.map +1 -1
- package/lib/module/skia/types/Recorder.d.ts +2 -1
- package/lib/module/skia/types/Recorder.js.map +1 -1
- package/lib/module/skia/types/Skia.d.ts +2 -0
- package/lib/module/skia/types/Skia.js.map +1 -1
- package/lib/module/skia/types/Skottie.d.ts +223 -0
- package/lib/module/skia/types/Skottie.js +74 -0
- package/lib/module/skia/types/Skottie.js.map +1 -0
- package/lib/module/skia/types/index.d.ts +1 -0
- package/lib/module/skia/types/index.js +1 -0
- package/lib/module/skia/types/index.js.map +1 -1
- package/lib/module/skia/web/JsiSkImageFilterFactory.d.ts +29 -12
- package/lib/module/skia/web/JsiSkImageFilterFactory.js +88 -19
- package/lib/module/skia/web/JsiSkImageFilterFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkia.js +2 -0
- package/lib/module/skia/web/JsiSkia.js.map +1 -1
- package/lib/module/skia/web/JsiSkottieAnimation.d.ts +59 -0
- package/lib/module/skia/web/JsiSkottieAnimation.js +236 -0
- package/lib/module/skia/web/JsiSkottieAnimation.js.map +1 -0
- package/lib/module/skia/web/JsiSkottieFactory.d.ts +9 -0
- package/lib/module/skia/web/JsiSkottieFactory.js +19 -0
- package/lib/module/skia/web/JsiSkottieFactory.js.map +1 -0
- package/lib/module/sksg/Elements.d.ts +2 -1
- package/lib/module/sksg/Elements.js.map +1 -1
- package/lib/module/sksg/Recorder/Core.d.ts +4 -2
- package/lib/module/sksg/Recorder/Core.js +1 -0
- package/lib/module/sksg/Recorder/Core.js.map +1 -1
- package/lib/module/sksg/Recorder/Player.js +3 -1
- package/lib/module/sksg/Recorder/Player.js.map +1 -1
- package/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +2 -1
- package/lib/module/sksg/Recorder/ReanimatedRecorder.js +4 -0
- package/lib/module/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
- package/lib/module/sksg/Recorder/Recorder.d.ts +2 -1
- package/lib/module/sksg/Recorder/Recorder.js +6 -0
- package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/module/sksg/Recorder/Visitor.js +3 -0
- package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/module/sksg/Recorder/commands/Drawing.d.ts +2 -2
- package/lib/module/sksg/Recorder/commands/Drawing.js +9 -2
- package/lib/module/sksg/Recorder/commands/Drawing.js.map +1 -1
- package/lib/module/sksg/Recorder/commands/ImageFilters.js +1 -1
- package/lib/module/sksg/Recorder/commands/ImageFilters.js.map +1 -1
- package/lib/typescript/lib/commonjs/renderer/components/Skottie.d.ts +2 -0
- package/lib/typescript/lib/commonjs/skia/types/Matrix4.d.ts +1 -0
- package/lib/typescript/lib/commonjs/skia/types/Skottie.d.ts +6 -0
- package/lib/typescript/lib/commonjs/skia/web/JsiSkImageFilterFactory.d.ts +22 -5
- package/lib/typescript/lib/commonjs/skia/web/JsiSkia.d.ts +2 -0
- package/lib/typescript/lib/commonjs/skia/web/JsiSkottieAnimation.d.ts +48 -0
- package/lib/typescript/lib/commonjs/skia/web/JsiSkottieFactory.d.ts +6 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +1 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/Recorder.d.ts +1 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/commands/Drawing.d.ts +1 -1
- package/lib/typescript/lib/module/mock/index.d.ts +7 -0
- package/lib/typescript/lib/module/renderer/components/Skottie.d.ts +2 -0
- package/lib/typescript/lib/module/renderer/components/index.d.ts +1 -0
- package/lib/typescript/lib/module/skia/Skia.web.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/Matrix4.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/Skottie.d.ts +5 -0
- package/lib/typescript/lib/module/skia/types/index.d.ts +1 -0
- package/lib/typescript/lib/module/skia/web/JsiSkImageFilterFactory.d.ts +22 -5
- package/lib/typescript/lib/module/skia/web/JsiSkia.d.ts +2 -0
- package/lib/typescript/lib/module/skia/web/JsiSkottieAnimation.d.ts +47 -0
- package/lib/typescript/lib/module/skia/web/JsiSkottieFactory.d.ts +5 -0
- package/lib/typescript/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +1 -0
- package/lib/typescript/lib/module/sksg/Recorder/Recorder.d.ts +1 -0
- package/lib/typescript/lib/module/sksg/Recorder/commands/Drawing.d.ts +1 -1
- package/lib/typescript/src/dom/nodes/datatypes/Gradient.d.ts +15 -15
- package/lib/typescript/src/dom/types/Drawings.d.ts +5 -1
- package/lib/typescript/src/dom/types/NodeType.d.ts +2 -1
- package/lib/typescript/src/renderer/__tests__/e2e/AdvancedImageFilters.spec.d.ts +1 -0
- package/lib/typescript/src/renderer/__tests__/e2e/Camera.spec.d.ts +21 -0
- package/lib/typescript/src/renderer/__tests__/e2e/LightingImageFilters.spec.d.ts +1 -0
- package/lib/typescript/src/renderer/__tests__/e2e/Skottie.spec.d.ts +1 -0
- package/lib/typescript/src/renderer/__tests__/setup.d.ts +5 -0
- package/lib/typescript/src/renderer/components/Skottie.d.ts +4 -0
- package/lib/typescript/src/renderer/components/index.d.ts +1 -0
- package/lib/typescript/src/skia/types/ImageFilter/ImageFilterFactory.d.ts +252 -15
- package/lib/typescript/src/skia/types/Matrix4.d.ts +11 -2
- package/lib/typescript/src/skia/types/Recorder.d.ts +2 -1
- package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
- package/lib/typescript/src/skia/types/Skottie.d.ts +223 -0
- package/lib/typescript/src/skia/types/index.d.ts +1 -0
- package/lib/typescript/src/skia/web/JsiSkImageFilterFactory.d.ts +29 -12
- package/lib/typescript/src/skia/web/JsiSkottieAnimation.d.ts +59 -0
- package/lib/typescript/src/skia/web/JsiSkottieFactory.d.ts +9 -0
- package/lib/typescript/src/sksg/Elements.d.ts +2 -1
- package/lib/typescript/src/sksg/Recorder/Core.d.ts +4 -2
- package/lib/typescript/src/sksg/Recorder/ReanimatedRecorder.d.ts +2 -1
- package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +2 -1
- package/lib/typescript/src/sksg/Recorder/commands/Drawing.d.ts +2 -2
- package/libs/android/arm64-v8a/libjsonreader.a +0 -0
- package/libs/android/armeabi-v7a/libjsonreader.a +0 -0
- package/libs/android/x86/libjsonreader.a +0 -0
- package/libs/android/x86_64/libjsonreader.a +0 -0
- package/libs/apple/libpathops.xcframework/Info.plist +8 -8
- package/libs/apple/libskia.xcframework/Info.plist +14 -14
- package/libs/apple/libskottie.xcframework/Info.plist +14 -14
- package/libs/apple/libskparagraph.xcframework/Info.plist +16 -16
- package/libs/apple/libsksg.xcframework/Info.plist +5 -5
- package/libs/apple/libskshaper.xcframework/Info.plist +14 -14
- package/libs/apple/libskunicode_libgrapheme.xcframework/Info.plist +14 -14
- package/libs/apple/libsvg.xcframework/Info.plist +14 -14
- package/package.json +1 -1
- package/react-native-skia.podspec +4 -2
- package/src/__tests__/snapshots/matrix4/camera-corner.png +0 -0
- package/src/__tests__/snapshots/matrix4/camera-offset.png +0 -0
- package/src/__tests__/snapshots/matrix4/camera-top-left-center.png +0 -0
- package/src/__tests__/snapshots/matrix4/camera-zoom-out.png +0 -0
- package/src/__tests__/snapshots/matrix4/full-rect.png +0 -0
- package/src/__tests__/snapshots/matrix4/rect.png +0 -0
- package/src/__tests__/snapshots/matrix4/scaled-rect.png +0 -0
- package/src/__tests__/snapshots/matrix4/test-perspective.png +0 -0
- package/src/__tests__/snapshots/matrix4/test-perspective2.png +0 -0
- package/src/dom/types/Drawings.ts +6 -0
- package/src/dom/types/NodeType.ts +2 -0
- package/src/renderer/__tests__/e2e/AdvancedImageFilters.spec.tsx +492 -0
- package/src/renderer/__tests__/e2e/Camera.spec.tsx +475 -0
- package/src/renderer/__tests__/e2e/LightingImageFilters.spec.tsx +1478 -0
- package/src/renderer/__tests__/e2e/Skottie.spec.tsx +440 -0
- package/src/renderer/__tests__/e2e/setup/skottie/basic_slots.json +1118 -0
- package/src/renderer/__tests__/e2e/setup/skottie/color-props.json +1 -0
- package/src/renderer/__tests__/e2e/setup/skottie/confetti.json +5899 -0
- package/src/renderer/__tests__/e2e/setup/skottie/drinks.json +43857 -0
- package/src/renderer/__tests__/e2e/setup/skottie/fingerprint.json +1 -0
- package/src/renderer/__tests__/e2e/setup/skottie/lego_loader.json +29540 -0
- package/src/renderer/__tests__/e2e/setup/skottie/new-drop.json +1 -0
- package/src/renderer/__tests__/e2e/setup/skottie/onboarding.json +1 -0
- package/src/renderer/__tests__/e2e/setup/skottie/text-layer.json +1 -0
- package/src/renderer/__tests__/setup.tsx +23 -0
- package/src/renderer/components/Skottie.tsx +8 -0
- package/src/renderer/components/index.ts +1 -0
- package/src/skia/__tests__/assets/Avenir-Heavy.ttf +0 -0
- package/src/skia/types/ImageFilter/ImageFilterFactory.ts +391 -21
- package/src/skia/types/Matrix4.ts +108 -2
- package/src/skia/types/Recorder.ts +2 -0
- package/src/skia/types/Skia.ts +2 -0
- package/src/skia/types/Skottie.ts +266 -0
- package/src/skia/types/index.ts +1 -0
- package/src/skia/web/JsiSkImageFilterFactory.ts +266 -31
- package/src/skia/web/JsiSkia.ts +2 -0
- package/src/skia/web/JsiSkottieAnimation.ts +259 -0
- package/src/skia/web/JsiSkottieFactory.ts +25 -0
- package/src/sksg/Elements.tsx +2 -0
- package/src/sksg/Recorder/Core.ts +3 -0
- package/src/sksg/Recorder/Player.ts +3 -0
- package/src/sksg/Recorder/ReanimatedRecorder.ts +6 -0
- package/src/sksg/Recorder/Recorder.ts +5 -0
- package/src/sksg/Recorder/Visitor.ts +3 -0
- package/src/sksg/Recorder/commands/Drawing.ts +7 -3
- package/src/sksg/Recorder/commands/ImageFilters.ts +1 -1
@@ -0,0 +1,1478 @@
|
|
1
|
+
import { importSkia, surface, images } from "../setup";
|
2
|
+
import type { SkColor } from "../../../skia/types";
|
3
|
+
import { BlendMode, ClipOp, PaintStyle, TileMode } from "../../../skia/types";
|
4
|
+
import { checkImage, docPath, itRunsE2eOnly } from "../../../__tests__/setup";
|
5
|
+
|
6
|
+
const checkResult = (base64: string, path: string) => {
|
7
|
+
const { Skia } = importSkia();
|
8
|
+
const rData = Skia.Data.fromBase64(base64);
|
9
|
+
const image = Skia.Image.MakeImageFromEncoded(rData)!;
|
10
|
+
expect(rData).toBeDefined();
|
11
|
+
checkImage(image, docPath(path));
|
12
|
+
};
|
13
|
+
|
14
|
+
describe("Lighting Image Filters", () => {
|
15
|
+
itRunsE2eOnly("DistantLitDiffuse - Dramatic Relief", async () => {
|
16
|
+
const { skiaLogoPng } = images;
|
17
|
+
const base64 = await surface.eval(
|
18
|
+
(Skia, ctx) => {
|
19
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
20
|
+
const canvas = sur.getCanvas();
|
21
|
+
|
22
|
+
// Create a dark background to enhance contrast
|
23
|
+
const bgPaint = Skia.Paint();
|
24
|
+
bgPaint.setColor(Skia.Color("rgb(20, 20, 30)"));
|
25
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
26
|
+
|
27
|
+
// Create high-contrast emboss effect
|
28
|
+
const paint = Skia.Paint();
|
29
|
+
|
30
|
+
// Pre-process the image with a threshold filter to make shapes more defined
|
31
|
+
// This will help the lighting effect appear more dramatic
|
32
|
+
const inputFilter = Skia.ImageFilter.MakeColorFilter(
|
33
|
+
Skia.ColorFilter.MakeMatrix([
|
34
|
+
1.5,
|
35
|
+
0,
|
36
|
+
0,
|
37
|
+
0,
|
38
|
+
-20, // Increased contrast for red
|
39
|
+
0,
|
40
|
+
1.5,
|
41
|
+
0,
|
42
|
+
0,
|
43
|
+
-20, // Increased contrast for green
|
44
|
+
0,
|
45
|
+
0,
|
46
|
+
1.5,
|
47
|
+
0,
|
48
|
+
-20, // Increased contrast for blue
|
49
|
+
0,
|
50
|
+
0,
|
51
|
+
0,
|
52
|
+
1.2,
|
53
|
+
0, // Slightly boosted alpha
|
54
|
+
]),
|
55
|
+
null
|
56
|
+
);
|
57
|
+
|
58
|
+
// Direction vector for dramatic side lighting
|
59
|
+
const direction = { x: -3, y: -0.5, z: 0.5 };
|
60
|
+
|
61
|
+
// Light color (stark white for contrast)
|
62
|
+
const lightColor = Skia.Color("rgb(255, 255, 255)");
|
63
|
+
|
64
|
+
// Higher surface scale for more dramatic relief
|
65
|
+
const surfaceScale = 4.0;
|
66
|
+
const kd = 2.5; // Stronger diffuse coefficient
|
67
|
+
|
68
|
+
// Create the distant light diffuse filter
|
69
|
+
const distantLitFilter = Skia.ImageFilter.MakeDistantLitDiffuse(
|
70
|
+
direction,
|
71
|
+
lightColor,
|
72
|
+
surfaceScale,
|
73
|
+
kd,
|
74
|
+
inputFilter, // Use high-contrast image as input
|
75
|
+
null // No crop rect
|
76
|
+
);
|
77
|
+
|
78
|
+
// Set the filter to our paint
|
79
|
+
paint.setImageFilter(distantLitFilter);
|
80
|
+
|
81
|
+
// Add a subtle color tint
|
82
|
+
paint.setColorFilter(
|
83
|
+
Skia.ColorFilter.MakeMatrix([
|
84
|
+
1.2,
|
85
|
+
0,
|
86
|
+
0,
|
87
|
+
0,
|
88
|
+
10, // Boosted red
|
89
|
+
0,
|
90
|
+
1.0,
|
91
|
+
0,
|
92
|
+
0,
|
93
|
+
0, // Normal green
|
94
|
+
0,
|
95
|
+
0,
|
96
|
+
0.8,
|
97
|
+
0,
|
98
|
+
0, // Reduced blue for warmer tone
|
99
|
+
0,
|
100
|
+
0,
|
101
|
+
0,
|
102
|
+
1,
|
103
|
+
0, // Alpha unchanged
|
104
|
+
])
|
105
|
+
);
|
106
|
+
|
107
|
+
// Draw the image with the dramatic lighting
|
108
|
+
const padding = 30;
|
109
|
+
canvas.drawImageRect(
|
110
|
+
ctx.skiaLogoPng,
|
111
|
+
Skia.XYWHRect(
|
112
|
+
0,
|
113
|
+
0,
|
114
|
+
ctx.skiaLogoPng.width(),
|
115
|
+
ctx.skiaLogoPng.height()
|
116
|
+
),
|
117
|
+
Skia.XYWHRect(padding, padding, 768 - padding * 2, 768 - padding * 2),
|
118
|
+
paint
|
119
|
+
);
|
120
|
+
|
121
|
+
// Add a subtle vignette effect to enhance depth
|
122
|
+
const vignetteRect = Skia.XYWHRect(-100, -100, 968, 968);
|
123
|
+
const vignettePaint = Skia.Paint();
|
124
|
+
const vignetteShader = Skia.Shader.MakeRadialGradient(
|
125
|
+
{ x: 384, y: 384 },
|
126
|
+
500,
|
127
|
+
[Skia.Color("rgba(0,0,0,0)"), Skia.Color("rgba(0,0,0,0.7)")],
|
128
|
+
[0.5, 1.0],
|
129
|
+
ctx.TileMode.Clamp
|
130
|
+
);
|
131
|
+
vignettePaint.setShader(vignetteShader);
|
132
|
+
canvas.drawRect(vignetteRect, vignettePaint);
|
133
|
+
|
134
|
+
sur.flush();
|
135
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
136
|
+
},
|
137
|
+
{ skiaLogoPng, TileMode }
|
138
|
+
);
|
139
|
+
checkResult(base64, "lighting-image-filters/distant-lit-diffuse.png");
|
140
|
+
});
|
141
|
+
|
142
|
+
itRunsE2eOnly("PointLitDiffuse - Glowing Core", async () => {
|
143
|
+
const { skiaLogoPng } = images;
|
144
|
+
const base64 = await surface.eval(
|
145
|
+
(Skia, ctx) => {
|
146
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
147
|
+
const canvas = sur.getCanvas();
|
148
|
+
|
149
|
+
// Create a dark background (not completely black) for better visibility
|
150
|
+
const bgPaint = Skia.Paint();
|
151
|
+
bgPaint.setColor(Skia.Color("rgb(10, 10, 15)"));
|
152
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
153
|
+
|
154
|
+
// Create a glowing center effect
|
155
|
+
const paint = Skia.Paint();
|
156
|
+
|
157
|
+
// Position light inside the image for a glowing core effect
|
158
|
+
// Moved light closer to surface (z is now positive)
|
159
|
+
const location = { x: 384, y: 384, z: 200 };
|
160
|
+
|
161
|
+
// Light color (intense orange-yellow for a fiery glow)
|
162
|
+
const lightColor = Skia.Color("rgb(255, 200, 50)");
|
163
|
+
|
164
|
+
// Parameters for the filter
|
165
|
+
const surfaceScale = 2.0; // Height effect
|
166
|
+
const kd = 1.5; // Diffuse reflection strength
|
167
|
+
|
168
|
+
// Create the point light diffuse filter
|
169
|
+
const pointLitFilter = Skia.ImageFilter.MakePointLitDiffuse(
|
170
|
+
location,
|
171
|
+
lightColor,
|
172
|
+
surfaceScale,
|
173
|
+
kd,
|
174
|
+
null, // Use source bitmap as input
|
175
|
+
null // No crop rect
|
176
|
+
);
|
177
|
+
|
178
|
+
// Set the filter to our paint
|
179
|
+
paint.setImageFilter(pointLitFilter);
|
180
|
+
|
181
|
+
// Add a color boost to make the effect more visible
|
182
|
+
paint.setColorFilter(
|
183
|
+
Skia.ColorFilter.MakeMatrix([
|
184
|
+
1.2,
|
185
|
+
0,
|
186
|
+
0,
|
187
|
+
0,
|
188
|
+
20, // Boosted red
|
189
|
+
0,
|
190
|
+
1.1,
|
191
|
+
0,
|
192
|
+
0,
|
193
|
+
10, // Boosted green
|
194
|
+
0,
|
195
|
+
0,
|
196
|
+
1.0,
|
197
|
+
0,
|
198
|
+
0, // Blue unchanged
|
199
|
+
0,
|
200
|
+
0,
|
201
|
+
0,
|
202
|
+
1,
|
203
|
+
0, // Alpha unchanged
|
204
|
+
])
|
205
|
+
);
|
206
|
+
|
207
|
+
// Draw the image with the glowing core effect
|
208
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, paint);
|
209
|
+
|
210
|
+
// Add a second layer of lighting for more intensity
|
211
|
+
const accentPaint = Skia.Paint();
|
212
|
+
const accentFilter = Skia.ImageFilter.MakePointLitDiffuse(
|
213
|
+
{ x: 384, y: 384, z: 50 }, // Closer light source
|
214
|
+
Skia.Color("rgb(255, 255, 200)"), // Brighter light
|
215
|
+
surfaceScale * 0.5,
|
216
|
+
kd * 0.8,
|
217
|
+
null,
|
218
|
+
null
|
219
|
+
);
|
220
|
+
|
221
|
+
accentPaint.setImageFilter(accentFilter);
|
222
|
+
accentPaint.setBlendMode(ctx.BlendMode.Plus); // Additive lighting
|
223
|
+
|
224
|
+
// Draw second layer
|
225
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, accentPaint);
|
226
|
+
|
227
|
+
sur.flush();
|
228
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
229
|
+
},
|
230
|
+
{ skiaLogoPng, BlendMode }
|
231
|
+
);
|
232
|
+
checkResult(
|
233
|
+
base64,
|
234
|
+
`lighting-image-filters/point-lit-diffuse-${surface.OS}.png`
|
235
|
+
);
|
236
|
+
});
|
237
|
+
|
238
|
+
itRunsE2eOnly("SpotLitDiffuse - Theatrical Spotlight", async () => {
|
239
|
+
const { skiaLogoPng } = images;
|
240
|
+
const base64 = await surface.eval(
|
241
|
+
(Skia, ctx) => {
|
242
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
243
|
+
const canvas = sur.getCanvas();
|
244
|
+
|
245
|
+
// Fill background with deep black for theatrical effect
|
246
|
+
const bgPaint = Skia.Paint();
|
247
|
+
bgPaint.setColor(Skia.Color("rgb(0, 0, 0)"));
|
248
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
249
|
+
|
250
|
+
// Add a very subtle gradient stage background
|
251
|
+
const stagePaint = Skia.Paint();
|
252
|
+
const stageShader = Skia.Shader.MakeLinearGradient(
|
253
|
+
{ x: 0, y: 600 },
|
254
|
+
{ x: 0, y: 768 },
|
255
|
+
[
|
256
|
+
Skia.Color("rgba(20, 10, 30, 0)"),
|
257
|
+
Skia.Color("rgba(40, 20, 60, 0.6)"),
|
258
|
+
],
|
259
|
+
null,
|
260
|
+
ctx.TileMode.Clamp
|
261
|
+
);
|
262
|
+
stagePaint.setShader(stageShader);
|
263
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), stagePaint);
|
264
|
+
|
265
|
+
// Create multiple spotlight effects for dramatic theatre lighting
|
266
|
+
const createSpotlight = (
|
267
|
+
location: { x: number; y: number; z: number },
|
268
|
+
target: { x: number; y: number; z: number },
|
269
|
+
color: SkColor,
|
270
|
+
intensity: number,
|
271
|
+
angle: number
|
272
|
+
) => {
|
273
|
+
const paint = Skia.Paint();
|
274
|
+
|
275
|
+
// Spotlight parameters
|
276
|
+
const falloffExponent = 2.5; // Sharp falloff
|
277
|
+
const cutoffAngle = angle; // Narrow spotlight cone
|
278
|
+
|
279
|
+
// Light color
|
280
|
+
const lightColor = color;
|
281
|
+
|
282
|
+
// Surface parameters
|
283
|
+
const surfaceScale = 2.0;
|
284
|
+
const kd = intensity; // Strong diffuse coefficient for dramatic effect
|
285
|
+
|
286
|
+
// Create the spotlight diffuse filter
|
287
|
+
const spotLitFilter = Skia.ImageFilter.MakeSpotLitDiffuse(
|
288
|
+
location,
|
289
|
+
target,
|
290
|
+
falloffExponent,
|
291
|
+
cutoffAngle,
|
292
|
+
lightColor,
|
293
|
+
surfaceScale,
|
294
|
+
kd,
|
295
|
+
null, // Use source bitmap as input
|
296
|
+
null // No crop rect
|
297
|
+
);
|
298
|
+
|
299
|
+
// Set the filter and blend mode
|
300
|
+
paint.setImageFilter(spotLitFilter);
|
301
|
+
paint.setBlendMode(ctx.BlendMode.Plus); // Additive lighting
|
302
|
+
|
303
|
+
// Draw the image with spotlight effect
|
304
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, paint);
|
305
|
+
};
|
306
|
+
|
307
|
+
// Main spotlight from top-right
|
308
|
+
createSpotlight(
|
309
|
+
{ x: 600, y: 100, z: 400 },
|
310
|
+
{ x: 384, y: 384, z: 0 },
|
311
|
+
Skia.Color("rgb(255, 220, 180)"), // Warm white
|
312
|
+
2.5,
|
313
|
+
30.0
|
314
|
+
);
|
315
|
+
|
316
|
+
// Accent light from left
|
317
|
+
createSpotlight(
|
318
|
+
{ x: 100, y: 300, z: 300 },
|
319
|
+
{ x: 300, y: 384, z: 0 },
|
320
|
+
Skia.Color("rgb(90, 160, 255)"), // Cool blue
|
321
|
+
1.2,
|
322
|
+
40.0
|
323
|
+
);
|
324
|
+
|
325
|
+
// Subtle rim light from below
|
326
|
+
createSpotlight(
|
327
|
+
{ x: 384, y: 650, z: 150 },
|
328
|
+
{ x: 384, y: 500, z: 0 },
|
329
|
+
Skia.Color("rgb(255, 100, 50)"), // Warm orange/red
|
330
|
+
0.8,
|
331
|
+
60.0
|
332
|
+
);
|
333
|
+
|
334
|
+
// Add volumetric light rays
|
335
|
+
const raysPaint = Skia.Paint();
|
336
|
+
raysPaint.setColor(Skia.Color("rgba(255, 230, 180, 0.2)"));
|
337
|
+
|
338
|
+
// Primary light source position
|
339
|
+
const lightX = 600;
|
340
|
+
const lightY = 100;
|
341
|
+
|
342
|
+
// Draw 12 light rays from the main spotlight
|
343
|
+
for (let i = 0; i < 12; i++) {
|
344
|
+
const angle = (i / 12) * Math.PI * 0.5 + Math.PI * 0.75; // Angles for right-top quadrant
|
345
|
+
const length = 300 + 0.5 * 200;
|
346
|
+
const endX = lightX + Math.cos(angle) * length;
|
347
|
+
const endY = lightY + Math.sin(angle) * length;
|
348
|
+
|
349
|
+
const rayPaint = Skia.Paint();
|
350
|
+
rayPaint.setColor(Skia.Color("rgba(255, 230, 180, 0.1)"));
|
351
|
+
rayPaint.setStrokeWidth(2 + 0.5 * 4);
|
352
|
+
rayPaint.setStyle(ctx.PaintStyle.Stroke);
|
353
|
+
rayPaint.setImageFilter(
|
354
|
+
Skia.ImageFilter.MakeBlur(3, 3, ctx.TileMode.Decal)
|
355
|
+
);
|
356
|
+
|
357
|
+
canvas.drawLine(lightX, lightY, endX, endY, rayPaint);
|
358
|
+
}
|
359
|
+
|
360
|
+
sur.flush();
|
361
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
362
|
+
},
|
363
|
+
{ skiaLogoPng, TileMode, BlendMode, PaintStyle }
|
364
|
+
);
|
365
|
+
checkResult(
|
366
|
+
base64,
|
367
|
+
`lighting-image-filters/spot-lit-diffuse-${surface.OS}.png`
|
368
|
+
);
|
369
|
+
});
|
370
|
+
|
371
|
+
itRunsE2eOnly("DistantLitSpecular - Metallic Gold", async () => {
|
372
|
+
const { skiaLogoPng } = images;
|
373
|
+
const base64 = await surface.eval(
|
374
|
+
(Skia, ctx) => {
|
375
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
376
|
+
const canvas = sur.getCanvas();
|
377
|
+
|
378
|
+
// Draw a rich dark background with subtle texture
|
379
|
+
const bgPaint = Skia.Paint();
|
380
|
+
bgPaint.setColor(Skia.Color("rgb(25, 15, 10)"));
|
381
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
382
|
+
|
383
|
+
// Add subtle noise texture to background
|
384
|
+
const noisePaint = Skia.Paint();
|
385
|
+
|
386
|
+
// Use a fine turbulence noise as a background texture
|
387
|
+
for (let y = 0; y < 768; y += 4) {
|
388
|
+
for (let x = 0; x < 768; x += 4) {
|
389
|
+
// Simple noise function
|
390
|
+
const noise = Math.sin(x * 0.1) * Math.cos(y * 0.1) * 0.5 + 0.5;
|
391
|
+
const alpha = noise * 0.15; // Very subtle
|
392
|
+
|
393
|
+
noisePaint.setColor(Skia.Color(`rgba(50, 30, 10, ${alpha})`));
|
394
|
+
canvas.drawRect(Skia.XYWHRect(x, y, 4, 4), noisePaint);
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
// Create our metallic gold effect
|
399
|
+
const paint = Skia.Paint();
|
400
|
+
|
401
|
+
// Preprocess the image with a blur and contrast enhancement
|
402
|
+
const preprocessFilter = Skia.ImageFilter.MakeColorFilter(
|
403
|
+
Skia.ColorFilter.MakeMatrix([
|
404
|
+
2.0,
|
405
|
+
0,
|
406
|
+
0,
|
407
|
+
0,
|
408
|
+
-50, // High red contrast
|
409
|
+
0,
|
410
|
+
2.0,
|
411
|
+
0,
|
412
|
+
0,
|
413
|
+
-50, // High green contrast
|
414
|
+
0,
|
415
|
+
0,
|
416
|
+
2.0,
|
417
|
+
0,
|
418
|
+
-50, // High blue contrast
|
419
|
+
0,
|
420
|
+
0,
|
421
|
+
0,
|
422
|
+
1,
|
423
|
+
0, // Alpha unchanged
|
424
|
+
]),
|
425
|
+
Skia.ImageFilter.MakeBlur(1, 1, ctx.TileMode.Decal)
|
426
|
+
);
|
427
|
+
|
428
|
+
// Direction vectors for multiple lights to create more complex highlights
|
429
|
+
const direction = { x: 0.5, y: -1, z: 0.3 };
|
430
|
+
|
431
|
+
// Gold light color with intense highlights
|
432
|
+
const lightColor = Skia.Color("rgb(255, 240, 180)");
|
433
|
+
|
434
|
+
// Parameters for the filter - high shininess for gold
|
435
|
+
const surfaceScale = 0.6; // Not too high for gold
|
436
|
+
const ks = 0.9; // Strong specular coefficient
|
437
|
+
const shininess = 50.0; // Very high shininess for metallic look
|
438
|
+
|
439
|
+
// Create the distant specular filter
|
440
|
+
const specularFilter = Skia.ImageFilter.MakeDistantLitSpecular(
|
441
|
+
direction,
|
442
|
+
lightColor,
|
443
|
+
surfaceScale,
|
444
|
+
ks,
|
445
|
+
shininess,
|
446
|
+
preprocessFilter, // Use enhanced image as input
|
447
|
+
null // No crop rect
|
448
|
+
);
|
449
|
+
|
450
|
+
// Set the filter to our paint
|
451
|
+
paint.setImageFilter(specularFilter);
|
452
|
+
|
453
|
+
// Add a gold color tint
|
454
|
+
const goldMatrix = [
|
455
|
+
1.2,
|
456
|
+
0.3,
|
457
|
+
0.0,
|
458
|
+
0,
|
459
|
+
30, // Boost red with some green mixed in
|
460
|
+
0.2,
|
461
|
+
1.0,
|
462
|
+
0.0,
|
463
|
+
0,
|
464
|
+
20, // Moderate green
|
465
|
+
0.0,
|
466
|
+
0.1,
|
467
|
+
0.4,
|
468
|
+
0,
|
469
|
+
0, // Minimal blue for gold
|
470
|
+
0,
|
471
|
+
0,
|
472
|
+
0,
|
473
|
+
1,
|
474
|
+
0, // Alpha unchanged
|
475
|
+
];
|
476
|
+
|
477
|
+
const colorFilter = Skia.ColorFilter.MakeMatrix(goldMatrix);
|
478
|
+
paint.setColorFilter(colorFilter);
|
479
|
+
|
480
|
+
// Add a second light from another angle for more complex highlights
|
481
|
+
const secondaryPaint = Skia.Paint();
|
482
|
+
const secondDirection = { x: -0.5, y: -0.8, z: 0.2 };
|
483
|
+
|
484
|
+
const secondaryFilter = Skia.ImageFilter.MakeDistantLitSpecular(
|
485
|
+
secondDirection,
|
486
|
+
Skia.Color("rgb(255, 255, 255)"), // White highlights
|
487
|
+
surfaceScale * 0.5,
|
488
|
+
ks * 0.3,
|
489
|
+
shininess * 1.5, // Even sharper highlights
|
490
|
+
preprocessFilter,
|
491
|
+
null
|
492
|
+
);
|
493
|
+
|
494
|
+
secondaryPaint.setImageFilter(secondaryFilter);
|
495
|
+
secondaryPaint.setBlendMode(ctx.BlendMode.Plus); // Additive blending
|
496
|
+
|
497
|
+
// Draw with padding for a framed effect
|
498
|
+
const padding = 40;
|
499
|
+
const imageRect = Skia.XYWHRect(
|
500
|
+
padding,
|
501
|
+
padding,
|
502
|
+
768 - padding * 2,
|
503
|
+
768 - padding * 2
|
504
|
+
);
|
505
|
+
|
506
|
+
// Create an ornate frame border
|
507
|
+
const framePaint = Skia.Paint();
|
508
|
+
framePaint.setStyle(ctx.PaintStyle.Stroke);
|
509
|
+
framePaint.setStrokeWidth(10);
|
510
|
+
framePaint.setColor(Skia.Color("rgb(80, 50, 10)"));
|
511
|
+
canvas.drawRect(
|
512
|
+
Skia.XYWHRect(
|
513
|
+
padding - 15,
|
514
|
+
padding - 15,
|
515
|
+
768 - padding * 2 + 30,
|
516
|
+
768 - padding * 2 + 30
|
517
|
+
),
|
518
|
+
framePaint
|
519
|
+
);
|
520
|
+
|
521
|
+
// Add gold leaf effect to frame
|
522
|
+
const frameGoldPaint = Skia.Paint();
|
523
|
+
frameGoldPaint.setStyle(ctx.PaintStyle.Stroke);
|
524
|
+
frameGoldPaint.setStrokeWidth(6);
|
525
|
+
frameGoldPaint.setColor(Skia.Color("rgb(200, 170, 40)"));
|
526
|
+
canvas.drawRect(
|
527
|
+
Skia.XYWHRect(
|
528
|
+
padding - 15,
|
529
|
+
padding - 15,
|
530
|
+
768 - padding * 2 + 30,
|
531
|
+
768 - padding * 2 + 30
|
532
|
+
),
|
533
|
+
frameGoldPaint
|
534
|
+
);
|
535
|
+
|
536
|
+
// Draw the main image
|
537
|
+
canvas.drawImageRect(
|
538
|
+
ctx.skiaLogoPng,
|
539
|
+
Skia.XYWHRect(
|
540
|
+
0,
|
541
|
+
0,
|
542
|
+
ctx.skiaLogoPng.width(),
|
543
|
+
ctx.skiaLogoPng.height()
|
544
|
+
),
|
545
|
+
imageRect,
|
546
|
+
paint
|
547
|
+
);
|
548
|
+
|
549
|
+
// Apply secondary highlights
|
550
|
+
canvas.drawImageRect(
|
551
|
+
ctx.skiaLogoPng,
|
552
|
+
Skia.XYWHRect(
|
553
|
+
0,
|
554
|
+
0,
|
555
|
+
ctx.skiaLogoPng.width(),
|
556
|
+
ctx.skiaLogoPng.height()
|
557
|
+
),
|
558
|
+
imageRect,
|
559
|
+
secondaryPaint
|
560
|
+
);
|
561
|
+
|
562
|
+
sur.flush();
|
563
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
564
|
+
},
|
565
|
+
{ skiaLogoPng, TileMode, BlendMode, PaintStyle }
|
566
|
+
);
|
567
|
+
checkResult(base64, "lighting-image-filters/distant-lit-specular.png");
|
568
|
+
});
|
569
|
+
|
570
|
+
itRunsE2eOnly("PointLitSpecular - Wet Surface", async () => {
|
571
|
+
const { skiaLogoPng } = images;
|
572
|
+
const base64 = await surface.eval(
|
573
|
+
(Skia, ctx) => {
|
574
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
575
|
+
const canvas = sur.getCanvas();
|
576
|
+
|
577
|
+
// Create a dark wet-looking surface
|
578
|
+
const bgPaint = Skia.Paint();
|
579
|
+
const bgShader = Skia.Shader.MakeLinearGradient(
|
580
|
+
{ x: 0, y: 0 },
|
581
|
+
{ x: 768, y: 768 },
|
582
|
+
[Skia.Color("rgb(10, 20, 30)"), Skia.Color("rgb(20, 40, 60)")],
|
583
|
+
null,
|
584
|
+
ctx.TileMode.Clamp
|
585
|
+
);
|
586
|
+
bgPaint.setShader(bgShader);
|
587
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
588
|
+
|
589
|
+
// Add water droplet texture in background
|
590
|
+
const dropletPaint = Skia.Paint();
|
591
|
+
dropletPaint.setColor(Skia.Color("rgba(255, 255, 255, 0.1)"));
|
592
|
+
|
593
|
+
// Random water droplets
|
594
|
+
const numDroplets = 200;
|
595
|
+
for (let i = 0; i < numDroplets; i++) {
|
596
|
+
const x = 0.5 * 768;
|
597
|
+
const y = 0.5 * 768;
|
598
|
+
const size = 1 + 0.5 * 5;
|
599
|
+
|
600
|
+
// Make some droplets blurry for depth
|
601
|
+
if (0.5 > 0.7) {
|
602
|
+
dropletPaint.setImageFilter(
|
603
|
+
Skia.ImageFilter.MakeBlur(
|
604
|
+
1 + 0.5 * 2,
|
605
|
+
1 + 0.5 * 2,
|
606
|
+
ctx.TileMode.Decal
|
607
|
+
)
|
608
|
+
);
|
609
|
+
} else {
|
610
|
+
dropletPaint.setImageFilter(null);
|
611
|
+
}
|
612
|
+
|
613
|
+
canvas.drawCircle(x, y, size, dropletPaint);
|
614
|
+
}
|
615
|
+
|
616
|
+
// Create wet surface effect with high specularity
|
617
|
+
const mainPaint = Skia.Paint();
|
618
|
+
|
619
|
+
// Create the point specular light source
|
620
|
+
const mainLight = { x: 200, y: 200, z: 300 };
|
621
|
+
const specularFilter = Skia.ImageFilter.MakePointLitSpecular(
|
622
|
+
mainLight,
|
623
|
+
Skia.Color("rgb(240, 250, 255)"), // Slightly blue-white for water highlights
|
624
|
+
1.0, // Moderate surface scale
|
625
|
+
1.0, // Full specular strength
|
626
|
+
80.0, // Very high shininess for wet look
|
627
|
+
null,
|
628
|
+
null
|
629
|
+
);
|
630
|
+
|
631
|
+
mainPaint.setImageFilter(specularFilter);
|
632
|
+
|
633
|
+
// Create second light for additional highlights
|
634
|
+
const secondaryPaint = Skia.Paint();
|
635
|
+
const secondLight = { x: 600, y: 400, z: 400 };
|
636
|
+
const secondFilter = Skia.ImageFilter.MakePointLitSpecular(
|
637
|
+
secondLight,
|
638
|
+
Skia.Color("rgb(200, 220, 255)"), // Cooler light
|
639
|
+
0.8,
|
640
|
+
0.7,
|
641
|
+
100.0, // Even higher shininess
|
642
|
+
null,
|
643
|
+
null
|
644
|
+
);
|
645
|
+
|
646
|
+
secondaryPaint.setImageFilter(secondFilter);
|
647
|
+
secondaryPaint.setBlendMode(ctx.BlendMode.Plus);
|
648
|
+
|
649
|
+
// Create diffuse lighting for the base image
|
650
|
+
const diffusePaint = Skia.Paint();
|
651
|
+
const diffuseFilter = Skia.ImageFilter.MakePointLitDiffuse(
|
652
|
+
{ x: 384, y: 384, z: 300 },
|
653
|
+
Skia.Color("rgb(150, 160, 170)"), // Soft gray-blue
|
654
|
+
1.5,
|
655
|
+
1.0,
|
656
|
+
null,
|
657
|
+
null
|
658
|
+
);
|
659
|
+
|
660
|
+
diffusePaint.setImageFilter(diffuseFilter);
|
661
|
+
|
662
|
+
// Add a blue-tinted color adjustment for underwater effect
|
663
|
+
diffusePaint.setColorFilter(
|
664
|
+
Skia.ColorFilter.MakeMatrix([
|
665
|
+
0.8, 0.0, 0.0, 0, 0, 0.0, 0.9, 0.1, 0, 0, 0.1, 0.1, 1.0, 0, 20, 0,
|
666
|
+
0, 0, 1, 0,
|
667
|
+
])
|
668
|
+
);
|
669
|
+
|
670
|
+
// Draw with the base diffuse lighting first
|
671
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, diffusePaint);
|
672
|
+
|
673
|
+
// Draw with specular highlights
|
674
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, mainPaint);
|
675
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, secondaryPaint);
|
676
|
+
|
677
|
+
// Add water flowing/dripping effect
|
678
|
+
const waterStreakPaint = Skia.Paint();
|
679
|
+
waterStreakPaint.setColor(Skia.Color("rgba(220, 230, 255, 0.15)"));
|
680
|
+
|
681
|
+
// Create several water streaks
|
682
|
+
for (let i = 0; i < 8; i++) {
|
683
|
+
const startX = 50 + 0.5 * 700;
|
684
|
+
const startY = 20 + 0.5 * 100;
|
685
|
+
let currentX = startX;
|
686
|
+
let currentY = startY;
|
687
|
+
|
688
|
+
const flowPath = Skia.Path.Make();
|
689
|
+
flowPath.moveTo(currentX, currentY);
|
690
|
+
|
691
|
+
// Create a wavy downward path
|
692
|
+
const length = 100 + 0.5 * 600;
|
693
|
+
const segments = 10 + Math.floor(length / 30);
|
694
|
+
|
695
|
+
for (let j = 0; j < segments; j++) {
|
696
|
+
// Gravity pulls downward
|
697
|
+
currentY += length / segments;
|
698
|
+
// Random side-to-side waviness
|
699
|
+
currentX += (0.5 - 0.5) * 30;
|
700
|
+
|
701
|
+
flowPath.lineTo(currentX, currentY);
|
702
|
+
}
|
703
|
+
|
704
|
+
// Make the water streak taper and blur
|
705
|
+
const streakPaint = Skia.Paint();
|
706
|
+
streakPaint.setStyle(ctx.PaintStyle.Stroke);
|
707
|
+
streakPaint.setColor(Skia.Color("rgba(200, 240, 255, 0.2)"));
|
708
|
+
streakPaint.setStrokeWidth(1 + 0.5 * 3);
|
709
|
+
streakPaint.setImageFilter(
|
710
|
+
Skia.ImageFilter.MakeBlur(1, 1, ctx.TileMode.Decal)
|
711
|
+
);
|
712
|
+
|
713
|
+
canvas.drawPath(flowPath, streakPaint);
|
714
|
+
}
|
715
|
+
|
716
|
+
// Add water puddle at bottom
|
717
|
+
const puddlePaint = Skia.Paint();
|
718
|
+
const puddleShader = Skia.Shader.MakeLinearGradient(
|
719
|
+
{ x: 0, y: 600 },
|
720
|
+
{ x: 0, y: 768 },
|
721
|
+
[
|
722
|
+
Skia.Color("rgba(40, 80, 120, 0)"),
|
723
|
+
Skia.Color("rgba(40, 80, 120, 0.4)"),
|
724
|
+
],
|
725
|
+
null,
|
726
|
+
ctx.TileMode.Clamp
|
727
|
+
);
|
728
|
+
puddlePaint.setShader(puddleShader);
|
729
|
+
canvas.drawRect(Skia.XYWHRect(0, 600, 768, 168), puddlePaint);
|
730
|
+
|
731
|
+
sur.flush();
|
732
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
733
|
+
},
|
734
|
+
{ skiaLogoPng, BlendMode, TileMode, PaintStyle }
|
735
|
+
);
|
736
|
+
checkResult(
|
737
|
+
base64,
|
738
|
+
`lighting-image-filters/point-lit-specular-${surface.OS}.png`
|
739
|
+
);
|
740
|
+
});
|
741
|
+
itRunsE2eOnly("SpotLitSpecular - Crystal Prism", async () => {
|
742
|
+
const { skiaLogoPng } = images;
|
743
|
+
const base64 = await surface.eval(
|
744
|
+
(Skia, ctx) => {
|
745
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
746
|
+
const canvas = sur.getCanvas();
|
747
|
+
|
748
|
+
// Create a black background for maximum contrast with crystal effect
|
749
|
+
const bgPaint = Skia.Paint();
|
750
|
+
bgPaint.setColor(Skia.Color("rgb(0, 0, 0)"));
|
751
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
752
|
+
|
753
|
+
// Create a "crystal prism" effect with rainbow colors
|
754
|
+
|
755
|
+
// Draw colored ambient light beams in background
|
756
|
+
const beamColors = [
|
757
|
+
"rgba(255, 50, 50, 0.2)", // Red
|
758
|
+
"rgba(255, 150, 50, 0.2)", // Orange
|
759
|
+
"rgba(255, 255, 50, 0.2)", // Yellow
|
760
|
+
"rgba(50, 255, 50, 0.2)", // Green
|
761
|
+
"rgba(50, 150, 255, 0.2)", // Blue
|
762
|
+
"rgba(150, 50, 255, 0.2)", // Purple
|
763
|
+
];
|
764
|
+
|
765
|
+
// Create rainbow beams
|
766
|
+
for (let i = 0; i < beamColors.length; i++) {
|
767
|
+
const beamPaint = Skia.Paint();
|
768
|
+
beamPaint.setColor(Skia.Color(beamColors[i]));
|
769
|
+
|
770
|
+
// Calculate angle for each beam
|
771
|
+
const angle = (i / beamColors.length) * Math.PI + Math.PI / 2;
|
772
|
+
|
773
|
+
// Create beam path
|
774
|
+
const beamPath = Skia.Path.Make();
|
775
|
+
beamPath.moveTo(384, 384);
|
776
|
+
|
777
|
+
// End coordinates based on angle
|
778
|
+
const endX = 384 + Math.cos(angle) * 900;
|
779
|
+
const endY = 384 + Math.sin(angle) * 900;
|
780
|
+
|
781
|
+
beamPath.lineTo(endX, endY);
|
782
|
+
|
783
|
+
// Draw wide blurred beam
|
784
|
+
beamPaint.setStyle(ctx.PaintStyle.Stroke);
|
785
|
+
beamPaint.setStrokeWidth(60 + i * 10);
|
786
|
+
beamPaint.setImageFilter(
|
787
|
+
Skia.ImageFilter.MakeBlur(20, 20, ctx.TileMode.Decal)
|
788
|
+
);
|
789
|
+
|
790
|
+
canvas.drawPath(beamPath, beamPaint);
|
791
|
+
}
|
792
|
+
|
793
|
+
// Apply crystalline effect to the main image
|
794
|
+
// First, prepare a base with enhanced contrast
|
795
|
+
const basePaint = Skia.Paint();
|
796
|
+
basePaint.setColorFilter(
|
797
|
+
Skia.ColorFilter.MakeMatrix([
|
798
|
+
1.5,
|
799
|
+
0,
|
800
|
+
0,
|
801
|
+
0,
|
802
|
+
-30, // Boosted red
|
803
|
+
0,
|
804
|
+
1.5,
|
805
|
+
0,
|
806
|
+
0,
|
807
|
+
-30, // Boosted green
|
808
|
+
0,
|
809
|
+
0,
|
810
|
+
1.5,
|
811
|
+
0,
|
812
|
+
-30, // Boosted blue
|
813
|
+
0,
|
814
|
+
0,
|
815
|
+
0,
|
816
|
+
1.2,
|
817
|
+
0, // Slightly boosted alpha
|
818
|
+
])
|
819
|
+
);
|
820
|
+
|
821
|
+
// Draw base layer at reduced size to create crystal border effect
|
822
|
+
const padding = 100;
|
823
|
+
const imageRect = Skia.XYWHRect(
|
824
|
+
padding,
|
825
|
+
padding,
|
826
|
+
768 - padding * 2,
|
827
|
+
768 - padding * 2
|
828
|
+
);
|
829
|
+
|
830
|
+
canvas.drawImageRect(
|
831
|
+
ctx.skiaLogoPng,
|
832
|
+
Skia.XYWHRect(
|
833
|
+
0,
|
834
|
+
0,
|
835
|
+
ctx.skiaLogoPng.width(),
|
836
|
+
ctx.skiaLogoPng.height()
|
837
|
+
),
|
838
|
+
imageRect,
|
839
|
+
basePaint
|
840
|
+
);
|
841
|
+
|
842
|
+
// Now create multiple specular highlights from different angles
|
843
|
+
// These simulate light refracting through crystal facets
|
844
|
+
|
845
|
+
// Function to create a colored specular highlight
|
846
|
+
const createCrystalFacet = (
|
847
|
+
location: { x: number; y: number; z: number },
|
848
|
+
target: { x: number; y: number; z: number },
|
849
|
+
color: SkColor,
|
850
|
+
cutoffAngle: number,
|
851
|
+
shininess: number
|
852
|
+
) => {
|
853
|
+
const paint = Skia.Paint();
|
854
|
+
|
855
|
+
// Create the spotlight specular filter
|
856
|
+
const spotLitFilter = Skia.ImageFilter.MakeSpotLitSpecular(
|
857
|
+
location,
|
858
|
+
target,
|
859
|
+
3.0, // Sharp falloff
|
860
|
+
cutoffAngle, // Narrow spotlight cone
|
861
|
+
color, // Colored light
|
862
|
+
1.0, // Surface scale
|
863
|
+
0.9, // Strong specular coefficient
|
864
|
+
shininess, // Very high shininess
|
865
|
+
null, // Use source bitmap as input
|
866
|
+
null // No crop rect
|
867
|
+
);
|
868
|
+
|
869
|
+
// Set the filter and blend mode
|
870
|
+
paint.setImageFilter(spotLitFilter);
|
871
|
+
paint.setBlendMode(ctx.BlendMode.Plus); // Additive lighting
|
872
|
+
|
873
|
+
// Draw the specular highlight
|
874
|
+
canvas.drawImageRect(
|
875
|
+
ctx.skiaLogoPng,
|
876
|
+
Skia.XYWHRect(
|
877
|
+
0,
|
878
|
+
0,
|
879
|
+
ctx.skiaLogoPng.width(),
|
880
|
+
ctx.skiaLogoPng.height()
|
881
|
+
),
|
882
|
+
imageRect,
|
883
|
+
paint
|
884
|
+
);
|
885
|
+
};
|
886
|
+
|
887
|
+
// Create crystal facets with rainbow colors
|
888
|
+
createCrystalFacet(
|
889
|
+
{ x: 500, y: 200, z: 300 },
|
890
|
+
{ x: 384, y: 384, z: 0 },
|
891
|
+
Skia.Color("rgb(255, 50, 50)"), // Red
|
892
|
+
25.0,
|
893
|
+
100.0
|
894
|
+
);
|
895
|
+
|
896
|
+
createCrystalFacet(
|
897
|
+
{ x: 200, y: 600, z: 300 },
|
898
|
+
{ x: 300, y: 384, z: 0 },
|
899
|
+
Skia.Color("rgb(255, 150, 50)"), // Orange
|
900
|
+
30.0,
|
901
|
+
120.0
|
902
|
+
);
|
903
|
+
|
904
|
+
createCrystalFacet(
|
905
|
+
{ x: 600, y: 600, z: 300 },
|
906
|
+
{ x: 500, y: 400, z: 0 },
|
907
|
+
Skia.Color("rgb(255, 255, 50)"), // Yellow
|
908
|
+
20.0,
|
909
|
+
150.0
|
910
|
+
);
|
911
|
+
|
912
|
+
createCrystalFacet(
|
913
|
+
{ x: 200, y: 200, z: 300 },
|
914
|
+
{ x: 300, y: 300, z: 0 },
|
915
|
+
Skia.Color("rgb(50, 255, 50)"), // Green
|
916
|
+
15.0,
|
917
|
+
200.0
|
918
|
+
);
|
919
|
+
|
920
|
+
createCrystalFacet(
|
921
|
+
{ x: 400, y: 100, z: 300 },
|
922
|
+
{ x: 400, y: 300, z: 0 },
|
923
|
+
Skia.Color("rgb(50, 150, 255)"), // Blue
|
924
|
+
25.0,
|
925
|
+
180.0
|
926
|
+
);
|
927
|
+
|
928
|
+
createCrystalFacet(
|
929
|
+
{ x: 700, y: 384, z: 300 },
|
930
|
+
{ x: 500, y: 384, z: 0 },
|
931
|
+
Skia.Color("rgb(150, 50, 255)"), // Purple
|
932
|
+
20.0,
|
933
|
+
160.0
|
934
|
+
);
|
935
|
+
|
936
|
+
// Add intense white highlights for sharp crystal edges
|
937
|
+
createCrystalFacet(
|
938
|
+
{ x: 384, y: 100, z: 400 },
|
939
|
+
{ x: 384, y: 384, z: 0 },
|
940
|
+
Skia.Color("rgb(255, 255, 255)"), // Pure white
|
941
|
+
10.0,
|
942
|
+
250.0
|
943
|
+
);
|
944
|
+
|
945
|
+
// Add crystal border effect
|
946
|
+
const borderPaint = Skia.Paint();
|
947
|
+
|
948
|
+
// Create a crystal-like faceted border
|
949
|
+
const borderPath = Skia.Path.Make();
|
950
|
+
|
951
|
+
// Create an irregular crystal shape around the image
|
952
|
+
const centerX = 384;
|
953
|
+
const centerY = 384;
|
954
|
+
const facets = 12;
|
955
|
+
|
956
|
+
borderPath.moveTo(
|
957
|
+
centerX + (padding - 20) * Math.cos(0),
|
958
|
+
centerY + (padding - 20) * Math.sin(0)
|
959
|
+
);
|
960
|
+
|
961
|
+
for (let i = 1; i <= facets; i++) {
|
962
|
+
const angle = (i / facets) * Math.PI * 2;
|
963
|
+
|
964
|
+
// Vary the radius for each facet
|
965
|
+
const radiusVariation = 30 + 0.5 * 40;
|
966
|
+
const radius = padding - 20 + radiusVariation;
|
967
|
+
|
968
|
+
borderPath.lineTo(
|
969
|
+
centerX + radius * Math.cos(angle),
|
970
|
+
centerY + radius * Math.sin(angle)
|
971
|
+
);
|
972
|
+
}
|
973
|
+
|
974
|
+
borderPath.close();
|
975
|
+
|
976
|
+
// Draw crystal border with gradient effect
|
977
|
+
const borderShader = Skia.Shader.MakeLinearGradient(
|
978
|
+
{ x: 0, y: 0 },
|
979
|
+
{ x: 768, y: 768 },
|
980
|
+
[
|
981
|
+
Skia.Color("rgba(220, 240, 255, 0.6)"),
|
982
|
+
Skia.Color("rgba(180, 220, 255, 0.3)"),
|
983
|
+
Skia.Color("rgba(150, 200, 255, 0.6)"),
|
984
|
+
],
|
985
|
+
null,
|
986
|
+
ctx.TileMode.Clamp
|
987
|
+
);
|
988
|
+
|
989
|
+
borderPaint.setShader(borderShader);
|
990
|
+
borderPaint.setStyle(ctx.PaintStyle.Stroke);
|
991
|
+
borderPaint.setStrokeWidth(30);
|
992
|
+
borderPaint.setImageFilter(
|
993
|
+
Skia.ImageFilter.MakeBlur(8, 8, ctx.TileMode.Decal)
|
994
|
+
);
|
995
|
+
|
996
|
+
canvas.drawPath(borderPath, borderPaint);
|
997
|
+
|
998
|
+
// Add some star-shaped highlights
|
999
|
+
const starPaint = Skia.Paint();
|
1000
|
+
starPaint.setColor(Skia.Color("rgb(255, 255, 255)"));
|
1001
|
+
|
1002
|
+
const createStar = (x: number, y: number, size: number) => {
|
1003
|
+
const starPath = Skia.Path.Make();
|
1004
|
+
|
1005
|
+
// Draw 4-point star
|
1006
|
+
starPath.moveTo(x, y - size);
|
1007
|
+
starPath.lineTo(x + size / 4, y - size / 4);
|
1008
|
+
starPath.lineTo(x + size, y);
|
1009
|
+
starPath.lineTo(x + size / 4, y + size / 4);
|
1010
|
+
starPath.lineTo(x, y + size);
|
1011
|
+
starPath.lineTo(x - size / 4, y + size / 4);
|
1012
|
+
starPath.lineTo(x - size, y);
|
1013
|
+
starPath.lineTo(x - size / 4, y - size / 4);
|
1014
|
+
starPath.close();
|
1015
|
+
|
1016
|
+
// Add blur for glow
|
1017
|
+
const glowPaint = Skia.Paint();
|
1018
|
+
glowPaint.setColor(Skia.Color("rgba(255, 255, 255, 0.8)"));
|
1019
|
+
glowPaint.setImageFilter(
|
1020
|
+
Skia.ImageFilter.MakeBlur(size / 4, size / 4, ctx.TileMode.Decal)
|
1021
|
+
);
|
1022
|
+
|
1023
|
+
canvas.drawPath(starPath, glowPaint);
|
1024
|
+
|
1025
|
+
// Draw sharp center
|
1026
|
+
const centerPaint = Skia.Paint();
|
1027
|
+
centerPaint.setColor(Skia.Color("rgb(255, 255, 255)"));
|
1028
|
+
canvas.drawCircle(x, y, size / 10, centerPaint);
|
1029
|
+
};
|
1030
|
+
|
1031
|
+
// Add several highlight stars
|
1032
|
+
createStar(150, 200, 20);
|
1033
|
+
createStar(600, 150, 15);
|
1034
|
+
createStar(500, 600, 25);
|
1035
|
+
createStar(200, 500, 18);
|
1036
|
+
createStar(350, 250, 12);
|
1037
|
+
|
1038
|
+
sur.flush();
|
1039
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
1040
|
+
},
|
1041
|
+
{ skiaLogoPng, BlendMode, TileMode, PaintStyle }
|
1042
|
+
);
|
1043
|
+
checkResult(
|
1044
|
+
base64,
|
1045
|
+
`lighting-image-filters/spot-lit-specular-${surface.OS}.png`
|
1046
|
+
);
|
1047
|
+
});
|
1048
|
+
|
1049
|
+
itRunsE2eOnly("Combined Lighting - Elemental Fire & Ice", async () => {
|
1050
|
+
const { skiaLogoPng } = images;
|
1051
|
+
const base64 = await surface.eval(
|
1052
|
+
(Skia, ctx) => {
|
1053
|
+
const sur = Skia.Surface.MakeOffscreen(768, 768)!;
|
1054
|
+
const canvas = sur.getCanvas();
|
1055
|
+
|
1056
|
+
// Fill with dark background
|
1057
|
+
const bgPaint = Skia.Paint();
|
1058
|
+
bgPaint.setColor(Skia.Color("rgb(5, 10, 20)"));
|
1059
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 768, 768), bgPaint);
|
1060
|
+
|
1061
|
+
// Create a split-screen effect with fire and ice
|
1062
|
+
|
1063
|
+
// First, create a mask for each half
|
1064
|
+
const leftMask = Skia.Path.Make();
|
1065
|
+
leftMask.addRect(Skia.XYWHRect(0, 0, 384, 768));
|
1066
|
+
|
1067
|
+
const rightMask = Skia.Path.Make();
|
1068
|
+
rightMask.addRect(Skia.XYWHRect(384, 0, 384, 768));
|
1069
|
+
|
1070
|
+
// Prepare the image with enhanced contrast
|
1071
|
+
const preprocessFilter = Skia.ImageFilter.MakeColorFilter(
|
1072
|
+
Skia.ColorFilter.MakeMatrix([
|
1073
|
+
1.8,
|
1074
|
+
0,
|
1075
|
+
0,
|
1076
|
+
0,
|
1077
|
+
-40, // High contrast red
|
1078
|
+
0,
|
1079
|
+
1.8,
|
1080
|
+
0,
|
1081
|
+
0,
|
1082
|
+
-40, // High contrast green
|
1083
|
+
0,
|
1084
|
+
0,
|
1085
|
+
1.8,
|
1086
|
+
0,
|
1087
|
+
-40, // High contrast blue
|
1088
|
+
0,
|
1089
|
+
0,
|
1090
|
+
0,
|
1091
|
+
1.2,
|
1092
|
+
0, // Slightly boosted alpha
|
1093
|
+
]),
|
1094
|
+
Skia.ImageFilter.MakeBlur(1, 1, ctx.TileMode.Decal)
|
1095
|
+
);
|
1096
|
+
|
1097
|
+
// ******** FIRE SIDE (LEFT) ********
|
1098
|
+
canvas.save();
|
1099
|
+
canvas.clipPath(leftMask, ctx.ClipOp.Intersect, true);
|
1100
|
+
|
1101
|
+
// Create fiery background
|
1102
|
+
const fireBgPaint = Skia.Paint();
|
1103
|
+
const fireShader = Skia.Shader.MakeLinearGradient(
|
1104
|
+
{ x: 0, y: 768 },
|
1105
|
+
{ x: 384, y: 0 },
|
1106
|
+
[
|
1107
|
+
Skia.Color("rgb(80, 0, 0)"),
|
1108
|
+
Skia.Color("rgb(180, 30, 0)"),
|
1109
|
+
Skia.Color("rgb(255, 150, 0)"),
|
1110
|
+
],
|
1111
|
+
[0.2, 0.5, 0.9],
|
1112
|
+
ctx.TileMode.Clamp
|
1113
|
+
);
|
1114
|
+
fireBgPaint.setShader(fireShader);
|
1115
|
+
canvas.drawRect(Skia.XYWHRect(0, 0, 384, 768), fireBgPaint);
|
1116
|
+
|
1117
|
+
// Draw stylized flames in background
|
1118
|
+
const drawFlame = (
|
1119
|
+
x: number,
|
1120
|
+
y: number,
|
1121
|
+
width: number,
|
1122
|
+
height: number
|
1123
|
+
) => {
|
1124
|
+
const flamePath = Skia.Path.Make();
|
1125
|
+
|
1126
|
+
// Start at bottom center
|
1127
|
+
flamePath.moveTo(x, y + height);
|
1128
|
+
|
1129
|
+
// Define control points for bezier curve
|
1130
|
+
// Left side of flame
|
1131
|
+
flamePath.cubicTo(
|
1132
|
+
x - width * 0.5,
|
1133
|
+
y + height * 0.7, // Control point 1
|
1134
|
+
x - width * 0.2,
|
1135
|
+
y + height * 0.3, // Control point 2
|
1136
|
+
x,
|
1137
|
+
y // End point (top of flame)
|
1138
|
+
);
|
1139
|
+
|
1140
|
+
// Right side of flame
|
1141
|
+
flamePath.cubicTo(
|
1142
|
+
x + width * 0.2,
|
1143
|
+
y + height * 0.3, // Control point 1
|
1144
|
+
x + width * 0.5,
|
1145
|
+
y + height * 0.7, // Control point 2
|
1146
|
+
x,
|
1147
|
+
y + height // End point (back to start)
|
1148
|
+
);
|
1149
|
+
|
1150
|
+
// Fill with gradient
|
1151
|
+
const flamePaint = Skia.Paint();
|
1152
|
+
const flameShader = Skia.Shader.MakeLinearGradient(
|
1153
|
+
{ x: x, y: y + height },
|
1154
|
+
{ x: x, y: y },
|
1155
|
+
[
|
1156
|
+
Skia.Color("rgb(255, 60, 0)"),
|
1157
|
+
Skia.Color("rgb(255, 150, 0)"),
|
1158
|
+
Skia.Color("rgb(255, 220, 120)"),
|
1159
|
+
],
|
1160
|
+
[0.2, 0.6, 0.9],
|
1161
|
+
ctx.TileMode.Clamp
|
1162
|
+
);
|
1163
|
+
flamePaint.setShader(flameShader);
|
1164
|
+
|
1165
|
+
// Add glow with blur
|
1166
|
+
flamePaint.setImageFilter(
|
1167
|
+
Skia.ImageFilter.MakeBlur(
|
1168
|
+
width * 0.1,
|
1169
|
+
width * 0.1,
|
1170
|
+
ctx.TileMode.Decal
|
1171
|
+
)
|
1172
|
+
);
|
1173
|
+
|
1174
|
+
canvas.drawPath(flamePath, flamePaint);
|
1175
|
+
};
|
1176
|
+
|
1177
|
+
// Draw multiple flames
|
1178
|
+
for (let i = 0; i < 8; i++) {
|
1179
|
+
const x = 50 + 0.5 * 300;
|
1180
|
+
const baseHeight = 200 + 0.5 * 300;
|
1181
|
+
drawFlame(x, 768 - baseHeight, 20 + 0.5 * 50, baseHeight);
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
// Create fire lighting with composite of diffuse and specular
|
1185
|
+
|
1186
|
+
// Create fiery diffuse lighting from below
|
1187
|
+
const fireLight = { x: 200, y: 700, z: 100 };
|
1188
|
+
const fireColor = Skia.Color("rgb(255, 180, 50)");
|
1189
|
+
|
1190
|
+
const fireDiffuseFilter = Skia.ImageFilter.MakePointLitDiffuse(
|
1191
|
+
fireLight,
|
1192
|
+
fireColor,
|
1193
|
+
2.0, // Exaggerated surface scale
|
1194
|
+
2.0, // Strong diffuse
|
1195
|
+
preprocessFilter, // Use preprocessed image
|
1196
|
+
null
|
1197
|
+
);
|
1198
|
+
|
1199
|
+
// Create specular highlights for embers and sparks
|
1200
|
+
const fireSpecularFilter = Skia.ImageFilter.MakePointLitSpecular(
|
1201
|
+
{ x: 150, y: 550, z: 200 },
|
1202
|
+
Skia.Color("rgb(255, 230, 150)"),
|
1203
|
+
1.0,
|
1204
|
+
0.7,
|
1205
|
+
50.0, // High shininess for sparks
|
1206
|
+
preprocessFilter,
|
1207
|
+
null
|
1208
|
+
);
|
1209
|
+
|
1210
|
+
// Combine diffuse and specular with Plus blending
|
1211
|
+
const fireFilter = Skia.ImageFilter.MakeBlend(
|
1212
|
+
ctx.BlendMode.Plus,
|
1213
|
+
fireDiffuseFilter,
|
1214
|
+
fireSpecularFilter
|
1215
|
+
);
|
1216
|
+
|
1217
|
+
// Create the fire paint
|
1218
|
+
const firePaint = Skia.Paint();
|
1219
|
+
firePaint.setImageFilter(fireFilter);
|
1220
|
+
|
1221
|
+
// Add fiery color tint
|
1222
|
+
firePaint.setColorFilter(
|
1223
|
+
Skia.ColorFilter.MakeMatrix([
|
1224
|
+
1.5,
|
1225
|
+
0.3,
|
1226
|
+
0.1,
|
1227
|
+
0,
|
1228
|
+
20, // Strong red
|
1229
|
+
0.2,
|
1230
|
+
1.0,
|
1231
|
+
0.1,
|
1232
|
+
0,
|
1233
|
+
0, // Moderate green
|
1234
|
+
0.0,
|
1235
|
+
0.1,
|
1236
|
+
0.5,
|
1237
|
+
0,
|
1238
|
+
-20, // Reduced blue
|
1239
|
+
0,
|
1240
|
+
0,
|
1241
|
+
0,
|
1242
|
+
1,
|
1243
|
+
0, // Alpha unchanged
|
1244
|
+
])
|
1245
|
+
);
|
1246
|
+
|
1247
|
+
// Draw the image with fire effect
|
1248
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, firePaint);
|
1249
|
+
|
1250
|
+
// Add ember particles
|
1251
|
+
const emberPaint = Skia.Paint();
|
1252
|
+
|
1253
|
+
for (let i = 0; i < 60; i++) {
|
1254
|
+
const x = 0.5 * 384;
|
1255
|
+
const y = 300 + 0.5 * 468;
|
1256
|
+
const size = 1 + 0.5 * 3;
|
1257
|
+
|
1258
|
+
const brightness = 150 + 0.5 * 105;
|
1259
|
+
emberPaint.setColor(
|
1260
|
+
Skia.Color(`rgba(${brightness}, ${brightness * 0.6}, 0, 0.8)`)
|
1261
|
+
);
|
1262
|
+
|
1263
|
+
// Add glow to some embers
|
1264
|
+
if (0.5 > 0.6) {
|
1265
|
+
emberPaint.setImageFilter(
|
1266
|
+
Skia.ImageFilter.MakeBlur(size * 2, size * 2, ctx.TileMode.Decal)
|
1267
|
+
);
|
1268
|
+
} else {
|
1269
|
+
emberPaint.setImageFilter(null);
|
1270
|
+
}
|
1271
|
+
|
1272
|
+
canvas.drawCircle(x, y, size, emberPaint);
|
1273
|
+
}
|
1274
|
+
|
1275
|
+
canvas.restore();
|
1276
|
+
|
1277
|
+
// ******** ICE SIDE (RIGHT) ********
|
1278
|
+
canvas.save();
|
1279
|
+
canvas.clipPath(rightMask, ctx.ClipOp.Intersect, true);
|
1280
|
+
|
1281
|
+
// Create icy background
|
1282
|
+
const iceBgPaint = Skia.Paint();
|
1283
|
+
const iceShader = Skia.Shader.MakeLinearGradient(
|
1284
|
+
{ x: 768, y: 768 },
|
1285
|
+
{ x: 384, y: 0 },
|
1286
|
+
[
|
1287
|
+
Skia.Color("rgb(0, 20, 50)"),
|
1288
|
+
Skia.Color("rgb(30, 70, 120)"),
|
1289
|
+
Skia.Color("rgb(180, 220, 255)"),
|
1290
|
+
],
|
1291
|
+
[0.2, 0.5, 0.9],
|
1292
|
+
ctx.TileMode.Clamp
|
1293
|
+
);
|
1294
|
+
iceBgPaint.setShader(iceShader);
|
1295
|
+
canvas.drawRect(Skia.XYWHRect(384, 0, 384, 768), iceBgPaint);
|
1296
|
+
|
1297
|
+
// Draw ice crystals in background
|
1298
|
+
const drawCrystal = (
|
1299
|
+
x: number,
|
1300
|
+
y: number,
|
1301
|
+
size: number,
|
1302
|
+
rotation: number
|
1303
|
+
) => {
|
1304
|
+
const crystalPaint = Skia.Paint();
|
1305
|
+
crystalPaint.setColor(Skia.Color("rgba(200, 230, 255, 0.4)"));
|
1306
|
+
|
1307
|
+
// Save canvas state for rotation
|
1308
|
+
canvas.save();
|
1309
|
+
canvas.translate(x, y);
|
1310
|
+
canvas.rotate(rotation, 0, 0);
|
1311
|
+
|
1312
|
+
// Draw crystal shape
|
1313
|
+
const crystalPath = Skia.Path.Make();
|
1314
|
+
crystalPath.moveTo(0, -size); // Top
|
1315
|
+
crystalPath.lineTo(size / 3, -size / 2); // Upper right
|
1316
|
+
crystalPath.lineTo(size / 2, size / 2); // Lower right
|
1317
|
+
crystalPath.lineTo(0, size); // Bottom
|
1318
|
+
crystalPath.lineTo(-size / 2, size / 2); // Lower left
|
1319
|
+
crystalPath.lineTo(-size / 3, -size / 2); // Upper left
|
1320
|
+
crystalPath.close();
|
1321
|
+
|
1322
|
+
// Add light refraction effect
|
1323
|
+
crystalPaint.setImageFilter(
|
1324
|
+
Skia.ImageFilter.MakeBlur(
|
1325
|
+
size * 0.1,
|
1326
|
+
size * 0.1,
|
1327
|
+
ctx.TileMode.Decal
|
1328
|
+
)
|
1329
|
+
);
|
1330
|
+
|
1331
|
+
canvas.drawPath(crystalPath, crystalPaint);
|
1332
|
+
|
1333
|
+
// Add highlight
|
1334
|
+
const highlightPaint = Skia.Paint();
|
1335
|
+
highlightPaint.setColor(Skia.Color("rgba(255, 255, 255, 0.7)"));
|
1336
|
+
|
1337
|
+
const highlightPath = Skia.Path.Make();
|
1338
|
+
highlightPath.moveTo(0, -size * 0.8);
|
1339
|
+
highlightPath.lineTo(size / 5, -size / 3);
|
1340
|
+
highlightPath.lineTo(-size / 5, -size / 3);
|
1341
|
+
highlightPath.close();
|
1342
|
+
|
1343
|
+
canvas.drawPath(highlightPath, highlightPaint);
|
1344
|
+
|
1345
|
+
// Restore canvas
|
1346
|
+
canvas.restore();
|
1347
|
+
};
|
1348
|
+
|
1349
|
+
// Draw multiple crystals
|
1350
|
+
for (let i = 0; i < 15; i++) {
|
1351
|
+
const x = 384 + 0.5 * 384;
|
1352
|
+
const y = 0.5 * 768;
|
1353
|
+
const size = 20 + 0.5 * 60;
|
1354
|
+
const rotation = 0.5 * 360;
|
1355
|
+
|
1356
|
+
drawCrystal(x, y, size, rotation);
|
1357
|
+
}
|
1358
|
+
|
1359
|
+
// Create ice lighting with diffuse and specular
|
1360
|
+
|
1361
|
+
// Create ice diffuse lighting from top
|
1362
|
+
const iceLight = { x: 600, y: 100, z: 200 };
|
1363
|
+
const iceColor = Skia.Color("rgb(200, 230, 255)");
|
1364
|
+
|
1365
|
+
const iceDiffuseFilter = Skia.ImageFilter.MakePointLitDiffuse(
|
1366
|
+
iceLight,
|
1367
|
+
iceColor,
|
1368
|
+
1.5, // Moderate surface scale
|
1369
|
+
1.2, // Strong diffuse
|
1370
|
+
preprocessFilter, // Use preprocessed image
|
1371
|
+
null
|
1372
|
+
);
|
1373
|
+
|
1374
|
+
// Create specular highlights for ice crystals
|
1375
|
+
const iceSpecularFilter = Skia.ImageFilter.MakePointLitSpecular(
|
1376
|
+
{ x: 620, y: 200, z: 300 },
|
1377
|
+
Skia.Color("rgb(240, 250, 255)"),
|
1378
|
+
1.0,
|
1379
|
+
0.8,
|
1380
|
+
80.0, // Very high shininess for ice
|
1381
|
+
preprocessFilter,
|
1382
|
+
null
|
1383
|
+
);
|
1384
|
+
|
1385
|
+
// Combine diffuse and specular with Screen blending
|
1386
|
+
const iceFilter = Skia.ImageFilter.MakeBlend(
|
1387
|
+
ctx.BlendMode.Screen,
|
1388
|
+
iceDiffuseFilter,
|
1389
|
+
iceSpecularFilter
|
1390
|
+
);
|
1391
|
+
|
1392
|
+
// Create the ice paint
|
1393
|
+
const icePaint = Skia.Paint();
|
1394
|
+
icePaint.setImageFilter(iceFilter);
|
1395
|
+
|
1396
|
+
// Add icy color tint
|
1397
|
+
icePaint.setColorFilter(
|
1398
|
+
Skia.ColorFilter.MakeMatrix([
|
1399
|
+
0.7,
|
1400
|
+
0.0,
|
1401
|
+
0.0,
|
1402
|
+
0,
|
1403
|
+
-20, // Reduced red
|
1404
|
+
0.0,
|
1405
|
+
0.9,
|
1406
|
+
0.2,
|
1407
|
+
0,
|
1408
|
+
0, // Boosted green slightly
|
1409
|
+
0.2,
|
1410
|
+
0.3,
|
1411
|
+
1.2,
|
1412
|
+
0,
|
1413
|
+
30, // Strong blue
|
1414
|
+
0,
|
1415
|
+
0,
|
1416
|
+
0,
|
1417
|
+
1,
|
1418
|
+
0, // Alpha unchanged
|
1419
|
+
])
|
1420
|
+
);
|
1421
|
+
|
1422
|
+
// Draw the image with ice effect
|
1423
|
+
canvas.drawImage(ctx.skiaLogoPng, 0, 0, icePaint);
|
1424
|
+
|
1425
|
+
// Add snowflake particles
|
1426
|
+
const snowPaint = Skia.Paint();
|
1427
|
+
snowPaint.setColor(Skia.Color("rgba(255, 255, 255, 0.8)"));
|
1428
|
+
|
1429
|
+
for (let i = 0; i < 60; i++) {
|
1430
|
+
const x = 384 + 0.5 * 384;
|
1431
|
+
const y = 0.5 * 768;
|
1432
|
+
const size = 1 + 0.5 * 3;
|
1433
|
+
|
1434
|
+
// Add glow to some snowflakes
|
1435
|
+
if (0.5 > 0.7) {
|
1436
|
+
snowPaint.setImageFilter(
|
1437
|
+
Skia.ImageFilter.MakeBlur(size * 2, size * 2, ctx.TileMode.Decal)
|
1438
|
+
);
|
1439
|
+
canvas.drawCircle(x, y, size * 1.5, snowPaint);
|
1440
|
+
} else {
|
1441
|
+
snowPaint.setImageFilter(null);
|
1442
|
+
canvas.drawCircle(x, y, size, snowPaint);
|
1443
|
+
}
|
1444
|
+
}
|
1445
|
+
|
1446
|
+
canvas.restore();
|
1447
|
+
|
1448
|
+
// Draw dividing line with glowing effect
|
1449
|
+
const dividerPaint = Skia.Paint();
|
1450
|
+
const dividerShader = Skia.Shader.MakeLinearGradient(
|
1451
|
+
{ x: 384 - 20, y: 0 },
|
1452
|
+
{ x: 384 + 20, y: 0 },
|
1453
|
+
[
|
1454
|
+
Skia.Color("rgba(255, 120, 0, 0.7)"),
|
1455
|
+
Skia.Color("rgba(255, 255, 255, 1.0)"),
|
1456
|
+
Skia.Color("rgba(100, 180, 255, 0.7)"),
|
1457
|
+
],
|
1458
|
+
[0.0, 0.5, 1.0],
|
1459
|
+
ctx.TileMode.Clamp
|
1460
|
+
);
|
1461
|
+
dividerPaint.setShader(dividerShader);
|
1462
|
+
dividerPaint.setImageFilter(
|
1463
|
+
Skia.ImageFilter.MakeBlur(10, 10, ctx.TileMode.Decal)
|
1464
|
+
);
|
1465
|
+
|
1466
|
+
canvas.drawRect(Skia.XYWHRect(384 - 5, 0, 10, 768), dividerPaint);
|
1467
|
+
|
1468
|
+
sur.flush();
|
1469
|
+
return sur.makeImageSnapshot().encodeToBase64();
|
1470
|
+
},
|
1471
|
+
{ skiaLogoPng, BlendMode, TileMode, PaintStyle, ClipOp }
|
1472
|
+
);
|
1473
|
+
checkResult(
|
1474
|
+
base64,
|
1475
|
+
`lighting-image-filters/combined-lighting-fire-ice-${surface.OS}.png`
|
1476
|
+
);
|
1477
|
+
});
|
1478
|
+
});
|