From 048b1e23cd9dd5c75112734da1ef3f919c535ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 18 Dec 2024 18:14:38 +0100 Subject: [PATCH 1/6] implement full set of image filter on native side --- .../skia/cpp/api/JsiSkImageFilterFactory.h | 601 +++++++++++++++--- .../types/ImageFilter/ImageFilterFactory.ts | 504 ++++++++++++--- 2 files changed, 946 insertions(+), 159 deletions(-) diff --git a/packages/skia/cpp/api/JsiSkImageFilterFactory.h b/packages/skia/cpp/api/JsiSkImageFilterFactory.h index 3488401b04..3a2b1ad584 100644 --- a/packages/skia/cpp/api/JsiSkImageFilterFactory.h +++ b/packages/skia/cpp/api/JsiSkImageFilterFactory.h @@ -7,12 +7,14 @@ #include "JsiSkHostObjects.h" #include "JsiSkImageFilter.h" +#include "JsiSkPicture.h" #include "JsiSkRuntimeShaderBuilder.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdocumentation" #include "include/core/SkImageFilter.h" +#include "include/core/SkPoint3.h" #pragma clang diagnostic pop @@ -22,79 +24,97 @@ namespace jsi = facebook::jsi; class JsiSkImageFilterFactory : public JsiSkHostObject { public: + JSI_HOST_FUNCTION(MakeArithmetic) { + float k1 = arguments[0].asNumber(); + float k2 = arguments[1].asNumber(); + float k3 = arguments[2].asNumber(); + float k4 = arguments[3].asNumber(); + bool enforcePMColor = arguments[4].asBool(); + sk_sp background = nullptr; + if (count > 5 && !!arguments[5].isNull() && !!arguments[5].isUndefined()) { + background = JsiSkImageFilter::fromValue(runtime, arguments[5]); + } + sk_sp imageFilter = nullptr; + if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[6]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 7 && !arguments[7].isNull() && !arguments[7].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[7]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::Arithmetic( + k1, k2, k3, k4, enforcePMColor, std::move(background), + std::move(imageFilter), cropRect))); + } + + JSI_HOST_FUNCTION(MakeBlend) { + auto mode = static_cast(arguments[0].asNumber()); + sk_sp background = + JsiSkImageFilter::fromValue(runtime, arguments[1]); + sk_sp foreground = nullptr; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + foreground = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + + SkImageFilters::CropRect cropRect = {}; + if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } + + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Blend( + std::move(mode), std::move(background), + std::move(foreground), cropRect))); + } + JSI_HOST_FUNCTION(MakeBlur) { float sigmaX = arguments[0].asNumber(); float sigmaY = arguments[1].asNumber(); int tileMode = arguments[2].asNumber(); sk_sp imageFilter; - if (!arguments[3].isNull()) { + if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[3]); } + SkImageFilters::CropRect cropRect = {}; + if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[4]); + } return jsi::Object::createFromHostObject( runtime, std::make_shared( getContext(), SkImageFilters::Blur(sigmaX, sigmaY, (SkTileMode)tileMode, - imageFilter))); + std::move(imageFilter), cropRect))); } JSI_HOST_FUNCTION(MakeColorFilter) { auto cf = JsiSkColorFilter::fromValue(runtime, arguments[0]); sk_sp input; - if (!arguments[1].isNull()) { + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[1]); } - return jsi::Object::createFromHostObject( - runtime, std::make_shared( - getContext(), SkImageFilters::ColorFilter( - std::move(cf), std::move(input)))); - } - - JSI_HOST_FUNCTION(MakeOffset) { - auto x = arguments[0].asNumber(); - auto y = arguments[1].asNumber(); - sk_sp input; - if (!arguments[2].isNull()) { - input = JsiSkImageFilter::fromValue(runtime, arguments[2]); - } - return jsi::Object::createFromHostObject( - runtime, - std::make_shared( - getContext(), SkImageFilters::Offset(x, y, std::move(input)))); - } - - JSI_HOST_FUNCTION(MakeDisplacementMap) { - auto fXChannelSelector = - static_cast(arguments[0].asNumber()); - auto fYChannelSelector = - static_cast(arguments[1].asNumber()); - auto scale = arguments[2].asNumber(); - auto in2 = JsiSkImageFilter::fromValue(runtime, arguments[3]); - sk_sp input; - if (!arguments[4].isNull()) { - input = JsiSkImageFilter::fromValue(runtime, arguments[4]); + SkImageFilters::CropRect cropRect = {}; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( - getContext(), SkImageFilters::DisplacementMap( - fXChannelSelector, fYChannelSelector, scale, - std::move(in2), std::move(input)))); - } - - JSI_HOST_FUNCTION(MakeShader) { - auto shader = JsiSkShader::fromValue(runtime, arguments[0]); - return jsi::Object::createFromHostObject( - runtime, std::make_shared( - getContext(), SkImageFilters::Shader(std::move(shader)))); + getContext(), + SkImageFilters::ColorFilter(std::move(cf), std::move(input)), + cropRect)); } JSI_HOST_FUNCTION(MakeCompose) { sk_sp outer; - if (!arguments[0].isNull() && !arguments[0].isUndefined()) { + if (count > 0 && !arguments[0].isNull() && !arguments[0].isUndefined()) { outer = JsiSkImageFilter::fromValue(runtime, arguments[0]); } sk_sp inner; - if (!arguments[1].isNull() && !arguments[1].isUndefined()) { + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { inner = JsiSkImageFilter::fromValue(runtime, arguments[1]); } return jsi::Object::createFromHostObject( @@ -103,26 +123,44 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { std::move(inner)))); } - JSI_HOST_FUNCTION(MakeBlend) { - auto mode = static_cast(arguments[0].asNumber()); - sk_sp background = - JsiSkImageFilter::fromValue(runtime, arguments[1]); - sk_sp foreground = nullptr; - - if (count > 2 && !arguments[2].isNull()) { - foreground = JsiSkImageFilter::fromValue(runtime, arguments[2]); + JSI_HOST_FUNCTION(MakeCrop) { + SkRect rect = *JsiSkRect::fromValue(runtime, arguments[0]); + SkTileMode tileMode = SkTileMode::kDecal; + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + tileMode = (SkTileMode)arguments[1].asNumber(); + } + sk_sp imageFilter; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[2]); } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), + SkImageFilters::Crop(rect, tileMode, std::move(imageFilter)))); + } + JSI_HOST_FUNCTION(MakeDisplacementMap) { + auto fXChannelSelector = + static_cast(arguments[0].asNumber()); + auto fYChannelSelector = + static_cast(arguments[1].asNumber()); + auto scale = arguments[2].asNumber(); + auto in1 = JsiSkImageFilter::fromValue(runtime, arguments[3]); + sk_sp input; + if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[4]); + } SkImageFilters::CropRect cropRect = {}; - if (count > 3 && !arguments[3].isUndefined()) { - cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); } - return jsi::Object::createFromHostObject( - runtime, std::make_shared( - getContext(), SkImageFilters::Blend( - std::move(mode), std::move(background), - std::move(foreground), cropRect))); + runtime, + std::make_shared( + getContext(), SkImageFilters::DisplacementMap( + fXChannelSelector, fYChannelSelector, scale, + std::move(in1), std::move(input), cropRect))); } JSI_HOST_FUNCTION(MakeDropShadow) { @@ -132,11 +170,11 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { auto sigmaY = arguments[3].asNumber(); auto color = JsiSkColor::fromValue(runtime, arguments[4]); sk_sp input; - if (!arguments[5].isNull() && !arguments[5].isUndefined()) { + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isUndefined()) { + if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -153,11 +191,11 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { auto sigmaY = arguments[3].asNumber(); auto color = JsiSkColor::fromValue(runtime, arguments[4]); sk_sp input; - if (!arguments[5].isNull() && !arguments[5].isUndefined()) { + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isUndefined()) { + if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -167,7 +205,262 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { std::move(input), cropRect))); } - JSI_HOST_FUNCTION(MakeErode) { + JSI_HOST_FUNCTION(MakeEmpty) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), + SkImageFilters::Empty())); + } + + JSI_HOST_FUNCTION(MakeImage) { + sk_sp image = JsiSkImage::fromValue(runtime, arguments[0]); + SkRect srcRect; + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + srcRect = *JsiSkRect::fromValue(runtime, arguments[1]); + } else { + srcRect = SkRect::Make(image->bounds()); + } + SkRect dstRect; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + dstRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } else { + dstRect = srcRect; + } + SkFilterMode filterMode = SkFilterMode::kNearest; + if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + filterMode = (SkFilterMode)arguments[3].asNumber(); + } + SkMipmapMode mipmap = SkMipmapMode::kNone; + if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + mipmap = (SkMipmapMode)arguments[4].asNumber(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Image( + std::move(image), srcRect, dstRect, + SkSamplingOptions(filterMode, mipmap)))); + } + + JSI_HOST_FUNCTION(MakeMagnifier) { + SkRect lensBounds = *JsiSkRect::fromValue(runtime, arguments[0]); + float zoomAmount = arguments[1].asNumber(); + float inset = arguments[2].asNumber(); + SkFilterMode filterMode = SkFilterMode::kNearest; + if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + filterMode = (SkFilterMode)arguments[3].asNumber(); + } + SkMipmapMode mipmap = SkMipmapMode::kNone; + if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + mipmap = (SkMipmapMode)arguments[4].asNumber(); + } + sk_sp input; + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[5]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Magnifier( + lensBounds, zoomAmount, inset, + SkSamplingOptions(filterMode, mipmap), + input, cropRect))); + } + + JSI_HOST_FUNCTION(MakeMatrixConvolution) { + SkISize kernelSize = + SkISize(arguments[0].asNumber(), arguments[1].asNumber()); + std::vector kernel; + auto kernelArray = arguments[2].asObject(runtime).asArray(runtime); + auto size = kernelArray.size(runtime); + for (size_t i = 0; i < size; i++) { + kernel.push_back(kernelArray.getValueAtIndex(runtime, i).asNumber()); + } + auto gain = arguments[3].asNumber(); + auto bias = arguments[4].asNumber(); + SkIPoint kernelOffset = + SkIPoint(arguments[5].asNumber(), arguments[6].asNumber()); + SkTileMode tileMode = (SkTileMode)arguments[7].asNumber(); + bool convolveAlpha = arguments[8].asBool(); + sk_sp input; + if (count > 9 && !arguments[9].isNull() && !arguments[9].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[9]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 10 && !arguments[10].isNull() && !arguments[10].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[10]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::MatrixConvolution( + kernelSize, kernel.data(), gain, bias, kernelOffset, + tileMode, convolveAlpha, std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeMatrixTransform) { + SkMatrix matrix = *JsiSkMatrix::fromValue(runtime, arguments[0]); + SkFilterMode filterMode = SkFilterMode::kNearest; + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + filterMode = (SkFilterMode)arguments[1].asNumber(); + } + SkMipmapMode mipmap = SkMipmapMode::kNone; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + mipmap = (SkMipmapMode)arguments[2].asNumber(); + } + sk_sp input; + if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[3]); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), SkImageFilters::MatrixTransform( + matrix, SkSamplingOptions(filterMode, mipmap), + std::move(input)))); + } + + JSI_HOST_FUNCTION(MakeMerge) { + std::vector> filters; + auto filtersArray = arguments[0].asObject(runtime).asArray(runtime); + auto filtersCount = filtersArray.size(runtime); + for (size_t i = 0; i < filtersCount; ++i) { + auto element = filtersArray.getValueAtIndex(runtime, i); + if (element.isNull()) { + filters.push_back(nullptr); + } else { + filters.push_back(JsiSkImageFilter::fromValue(runtime, element)); + } + } + SkImageFilters::CropRect cropRect = {}; + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[1]); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), + SkImageFilters::Merge(filters.data(), filtersCount, cropRect))); + } + + JSI_HOST_FUNCTION(MakeOffset) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + sk_sp input; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::Offset(x, y, std::move(input)), cropRect)); + } + + JSI_HOST_FUNCTION(MakePicture) { + sk_sp picture = JsiSkPicture::fromValue(runtime, arguments[0]); + SkRect targetRect; + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + targetRect = *JsiSkRect::fromValue(runtime, arguments[1]); + } else { + targetRect = picture ? picture->cullRect() : SkRect::MakeEmpty(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::Picture(std::move(picture), targetRect))); + } + + JSI_HOST_FUNCTION(MakeRuntimeShader) { + auto rtb = JsiSkRuntimeShaderBuilder::fromValue(runtime, arguments[0]); + + const char *childName = ""; + if (!arguments[1].isNull() && !arguments[1].isUndefined()) { + childName = arguments[1].asString(runtime).utf8(runtime).c_str(); + } + + sk_sp input; + if (!arguments[2].isNull() && !arguments[2].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::RuntimeShader( + *rtb, childName, std::move(input)))); + } + + JSI_HOST_FUNCTION(MakeRuntimeShaderWithChildren) { + auto rtb = JsiSkRuntimeShaderBuilder::fromValue(runtime, arguments[0]); + float maxSampleRadius = arguments[1].asNumber(); + std::vector childNames; + auto childNamesJS = arguments[2].asObject(runtime).asArray(runtime); + size_t length = childNamesJS.size(runtime); + for (size_t i = 0; i < length; ++i) { + auto element = childNamesJS.getValueAtIndex(runtime, i); + childNames.push_back(element.asString(runtime).utf8(runtime).c_str()); + } + std::vector childNamesStringView; + childNamesStringView.reserve(childNames.size()); + for (const auto &name : childNames) { + childNamesStringView.push_back(std::string_view(name)); + } + + std::vector> inputs; + auto inputsJS = arguments[3].asObject(runtime).asArray(runtime); + if (inputsJS.size(runtime) != length) { + return jsi::Value::null(); + } + for (size_t i = 0; i < length; ++i) { + auto element = inputsJS.getValueAtIndex(runtime, i); + if (element.isNull()) { + inputs.push_back(nullptr); + } else { + inputs.push_back(JsiSkImageFilter::fromValue(runtime, element)); + } + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::RuntimeShader(*rtb, maxSampleRadius, + childNamesStringView.data(), + inputs.data(), length))); + } + + JSI_HOST_FUNCTION(MakeShader) { + auto shader = JsiSkShader::fromValue(runtime, arguments[0]); + SkImageFilters::Dither dither = SkImageFilters::Dither::kNo; + if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + dither = arguments[1].asBool() ? SkImageFilters::Dither::kYes + : SkImageFilters::Dither::kNo; + } + SkImageFilters::CropRect cropRect = {}; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Shader(std::move(shader), + dither, cropRect))); + } + + JSI_HOST_FUNCTION(MakeTile) { + SkRect src = *JsiSkRect::fromValue(runtime, arguments[0]); + SkRect dst = *JsiSkRect::fromValue(runtime, arguments[1]); + sk_sp input; + if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), SkImageFilters::Tile(src, dst, std::move(input)))); + } + + JSI_HOST_FUNCTION(MakeDilate) { auto rx = arguments[0].asNumber(); auto ry = arguments[1].asNumber(); sk_sp input; @@ -180,11 +473,11 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { } return jsi::Object::createFromHostObject( runtime, std::make_shared( - getContext(), SkImageFilters::Erode( + getContext(), SkImageFilters::Dilate( rx, ry, std::move(input), cropRect))); } - JSI_HOST_FUNCTION(MakeDilate) { + JSI_HOST_FUNCTION(MakeErode) { auto rx = arguments[0].asNumber(); auto ry = arguments[1].asNumber(); sk_sp input; @@ -192,46 +485,186 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { input = JsiSkImageFilter::fromValue(runtime, arguments[2]); } SkImageFilters::CropRect cropRect = {}; - if (count > 3 && !arguments[3].isUndefined()) { + if (count > 3 && !arguments[3].isUndefined() && !arguments[3].isNull()) { cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( - getContext(), SkImageFilters::Dilate( + getContext(), SkImageFilters::Erode( rx, ry, std::move(input), cropRect))); } - JSI_HOST_FUNCTION(MakeRuntimeShader) { - auto rtb = JsiSkRuntimeShaderBuilder::fromValue(runtime, arguments[0]); + inline SkPoint3 SkPoint3FromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + auto x = object.getProperty(runtime, "x").asNumber(); + auto y = object.getProperty(runtime, "y").asNumber(); + auto z = object.getProperty(runtime, "z").asNumber(); + return SkPoint3::Make(x, y, z); + } - const char *childName = ""; - if (!arguments[1].isNull() && !arguments[1].isUndefined()) { - childName = arguments[1].asString(runtime).utf8(runtime).c_str(); + JSI_HOST_FUNCTION(MakeDistantLitDiffuse) { + SkPoint3 direction = SkPoint3FromValue(runtime, arguments[0]); + SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[1]); + float surfaceScale = arguments[2].asNumber(); + float kd = arguments[3].asNumber(); + sk_sp input; + if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[4]); } + SkImageFilters::CropRect cropRect = {}; + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::DistantLitDiffuse( + direction, lightColor, surfaceScale, kd, + std::move(input), cropRect))); + } + JSI_HOST_FUNCTION(MakePointLitDiffuse) { + SkPoint3 location = SkPoint3FromValue(runtime, arguments[0]); + SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[1]); + float surfaceScale = arguments[2].asNumber(); + float kd = arguments[3].asNumber(); sk_sp input; - if (!arguments[2].isNull() && !arguments[2].isUndefined()) { - input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[4]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( - getContext(), SkImageFilters::RuntimeShader( - *rtb, childName, std::move(input)))); + getContext(), SkImageFilters::PointLitDiffuse( + location, lightColor, surfaceScale, kd, + std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeSpotLitDiffuse) { + SkPoint3 location = SkPoint3FromValue(runtime, arguments[0]); + SkPoint3 target = SkPoint3FromValue(runtime, arguments[1]); + float falloffExponent = arguments[2].asNumber(); + float cutoffAngle = arguments[3].asNumber(); + SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[4]); + float surfaceScale = arguments[5].asNumber(); + float kd = arguments[6].asNumber(); + sk_sp input; + if (count > 7 && !arguments[7].isNull() && !arguments[7].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[7]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 8 && !arguments[8].isNull() && !arguments[8].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[8]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::SpotLitDiffuse( + location, target, falloffExponent, + cutoffAngle, lightColor, surfaceScale, + kd, std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeDistantLitSpecular) { + SkPoint3 direction = SkPoint3FromValue(runtime, arguments[0]); + SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[1]); + float surfaceScale = arguments[2].asNumber(); + float ks = arguments[3].asNumber(); + float shininess = arguments[4].asNumber(); + sk_sp input; + if (count > 4 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[5]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 5 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::DistantLitSpecular( + direction, lightColor, surfaceScale, ks, + shininess, std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakePointLitSpecular) { + SkPoint3 location = SkPoint3FromValue(runtime, arguments[0]); + SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[1]); + float surfaceScale = arguments[2].asNumber(); + float ks = arguments[3].asNumber(); + float shininess = arguments[4].asNumber(); + sk_sp input; + if (count > 4 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[5]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 5 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::PointLitSpecular( + location, lightColor, surfaceScale, ks, + shininess, std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeSpotLitSpecular) { + SkPoint3 location = SkPoint3FromValue(runtime, arguments[0]); + SkPoint3 target = SkPoint3FromValue(runtime, arguments[1]); + float falloffExponent = arguments[2].asNumber(); + float cutoffAngle = arguments[3].asNumber(); + SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[4]); + float surfaceScale = arguments[5].asNumber(); + float ks = arguments[6].asNumber(); + float shininess = arguments[7].asNumber(); + sk_sp input; + if (count > 8 && !arguments[8].isNull() && !arguments[8].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[8]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 9 && !arguments[9].isNull() && !arguments[9].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[9]); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), + SkImageFilters::SpotLitSpecular( + location, target, falloffExponent, cutoffAngle, lightColor, + surfaceScale, ks, shininess, std::move(input), cropRect))); } JSI_EXPORT_FUNCTIONS( + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeArithmetic), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlend), JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlur), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeOffset), JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeColorFilter), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeShader), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDisplacementMap), JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeCompose), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeErode), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDilate), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlend), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeCrop), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDisplacementMap), JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDropShadow), JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDropShadowOnly), - JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeRuntimeShader)) + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeEmpty), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeImage), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeMagnifier), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeMatrixConvolution), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeMatrixTransform), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeMerge), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeOffset), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakePicture), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeRuntimeShader), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeRuntimeShaderWithChildren), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeShader), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeTile), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDilate), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeErode), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDistantLitDiffuse), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakePointLitDiffuse), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeSpotLitDiffuse), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDistantLitSpecular), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakePointLitSpecular), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeSpotLitSpecular)) explicit JsiSkImageFilterFactory(std::shared_ptr context) : JsiSkHostObject(std::move(context)) {} diff --git a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts index ee691877c5..6b0beb0b93 100644 --- a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts +++ b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts @@ -1,5 +1,6 @@ import type { SkColor } from "../Color"; import type { SkColorFilter } from "../ColorFilter/ColorFilter"; +import type { FilterMode, MipmapMode, SkImage } from "../Image/Image"; import type { BlendMode } from "../Paint"; import type { SkRect } from "../Rect"; import type { SkRuntimeShaderBuilder } from "../RuntimeEffect"; @@ -16,40 +17,39 @@ export enum ColorChannel { export interface ImageFilterFactory { /** - * Offsets the input image - * - * @param dx - Offset along the X axis - * @param dy - Offset along the X axis - * @param input - if null, it will use the dynamic source image - */ - MakeOffset( - dx: number, - dy: number, - input: SkImageFilter | null - ): SkImageFilter; - /** - * Spatially displace pixel values of the filtered image + * Create a filter that implements a custom blend mode. Each output pixel is the result of + * combining the corresponding background and foreground pixels using the 4 coefficients: + * k1 * foreground * background + k2 * foreground + k3 * background + k4 * - * @param channelX - Color channel to be used along the X axis - * @param channelY - Color channel to be used along the Y axis - * @param scale - Scale factor to be used in the displacement - * @param in1 - Source image filter to use for the displacement - * @param input - if null, it will use the dynamic source image + * @param k1, k2, k3, k4 The four coefficients used to combine the foreground and background. + * @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha. + * @param background The background content, using the source bitmap when this is null. + * @param foreground The foreground content, using the source bitmap when this is null. + * @param cropRect Optional rectangle that crops the inputs and output. */ - MakeDisplacementMap( - channelX: ColorChannel, - channelY: ColorChannel, - scale: number, - in1: SkImageFilter, - input: SkImageFilter | null + MakeArithmetic( + k1: number, + k2: number, + k3: number, + k4: number, + enforcePMColor: boolean, + background?: SkImageFilter | null, + foreground?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter; /** - * Transforms a shader into an impage filter - * - * @param shader - The Shader to be transformed - * @param input - if null, it will use the dynamic source image + * This filter takes an SkBlendMode and uses it to composite the two filters together. + * @param mode The blend mode that defines the compositing operation + * @param background The Dst pixels used in blending, if null the source bitmap is used. + * @param foreground The Src pixels used in blending, if null the source bitmap is used. + * @param cropRect Optional rectangle to crop input and output. */ - MakeShader(shader: SkShader, input: SkImageFilter | null): SkImageFilter; + MakeBlend: ( + mode: BlendMode, + background: SkImageFilter, + foreground?: SkImageFilter | null, + cropRect?: SkRect | null + ) => SkImageFilter; /** * Create a filter that blurs its input by the separate X and Y sigmas. The provided tile mode * is used when the blur kernel goes outside the input image. @@ -58,24 +58,27 @@ export interface ImageFilterFactory { * @param sigmaY - The Gaussian sigma value for blurring along the Y axis. * @param mode * @param input - if null, it will use the dynamic source image (e.g. a saved layer) + * @param cropRect Optional rectangle to crop input and output. */ MakeBlur( sigmaX: number, sigmaY: number, mode: TileMode, - input: SkImageFilter | null + input?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter; - /** * Create a filter that applies the color filter to the input filter results. - * @param cf + * + * @param colorFilter - The color filter to apply * @param input - if null, it will use the dynamic source image (e.g. a saved layer) + * @param cropRect Optional rectangle to crop input and output. */ MakeColorFilter( - cf: SkColorFilter, - input: SkImageFilter | null + colorFilter: SkColorFilter, + input?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter; - /** * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are * treated as the source bitmap passed to 'outer'. @@ -87,7 +90,43 @@ export interface ImageFilterFactory { outer: SkImageFilter | null, inner: SkImageFilter | null ): SkImageFilter; - + /** + * Create a filter that applies a crop to the result of the 'input' filter. Pixels within the + * crop rectangle are unmodified from what 'input' produced. Pixels outside of crop match the + * provided SkTileMode (defaulting to kDecal). + * + * NOTE: The optional CropRect argument for many of the factories is equivalent to creating the + * filter without a CropRect and then wrapping it in ::Crop(rect, kDecal). Explicitly adding + * Crop filters lets you control their tiling and use different geometry for the input and the + * output of another filter. + * + * @param rect The cropping rect + * @param tileMode The TileMode applied to pixels *outside* of 'crop' @default TileMode.Decal + * @param input The input filter that is cropped, uses source image if this is null + */ + MakeCrop( + rect: SkRect, + tileMode?: TileMode | null, + input?: SkImageFilter | null + ): SkImageFilter; + /** + * Spatially displace pixel values of the filtered image + * + * @param channelX - Color channel to be used along the X axis + * @param channelY - Color channel to be used along the Y axis + * @param scale - Scale factor to be used in the displacement + * @param in1 - Source image filter to use for the displacement + * @param input - if null, it will use the dynamic source image + * @param cropRect Optional rectangle to crop input and output. + */ + MakeDisplacementMap( + channelX: ColorChannel, + channelY: ColorChannel, + scale: number, + in1: SkImageFilter, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; /** * Create a filter that draws a drop shadow under the input content. * This filter produces an image that includes the inputs' content. @@ -105,9 +144,16 @@ export interface ImageFilterFactory { sigmaX: number, sigmaY: number, color: SkColor, - input: SkImageFilter | null, - cropRect?: SkRect + input?: SkImageFilter | null, + cropRect?: SkRect | null ) => SkImageFilter; + /** + * Offsets the input image + * + * @param dx - Offset along the X axis + * @param dy - Offset along the X axis + * @param input - if null, it will use the dynamic source image + */ /** * Create a filter that renders a drop shadow, in exactly the same manner as ::DropShadow, except * that the resulting image does not include the input content. @@ -126,50 +172,134 @@ export interface ImageFilterFactory { sigmaX: number, sigmaY: number, color: SkColor, - input: SkImageFilter | null, - cropRect?: SkRect + input?: SkImageFilter | null, + cropRect?: SkRect | null ) => SkImageFilter; /** - * Create a filter that erodes each input pixel's channel values to the minimum channel value - * within the given radii along the x and y axes. - * @param radiusX The distance to erode along the x axis to either side of each pixel. - * @param radiusY The distance to erode along the y axis to either side of each pixel. - * @param input The image filter that is eroded, using source bitmap if this is null. - * @param cropRect Optional rectangle that crops the input and output. + * Create a filter that always produces transparent black. */ - MakeErode: ( - rx: number, - ry: number, - input: SkImageFilter | null, - cropRect?: SkRect - ) => SkImageFilter; + MakeEmpty(): SkImageFilter; /** - * Create a filter that dilates each input pixel's channel values to the max value within the - * given radii along the x and y axes. - * @param radiusX The distance to dilate along the x axis to either side of each pixel. - * @param radiusY The distance to dilate along the y axis to either side of each pixel. - * @param input The image filter that is dilated, using source bitmap if this is null. - * @param cropRect Optional rectangle that crops the input and output. + * Create a filter that draws the 'srcRect' portion of image into 'dstRect' using the given + * filter quality. Similar to SkCanvas::drawImageRect. The returned image filter evaluates + * to transparent black if 'image' is null. + * + * @param image The image that is output by the filter, subset by 'srcRect'. + * @param srcRect The source pixels sampled into 'dstRect', if null the image bounds are used. + * @param dstRect The local rectangle to draw the image into, if null the srcRect is used. + * @param filterMode The filter mode to use when sampling the image @default FilterMode.Nearest + * @param mipmap The mipmap mode to use when sampling the image @default MipmapMode.None */ - MakeDilate: ( - rx: number, - ry: number, - input: SkImageFilter | null, - cropRect?: SkRect - ) => SkImageFilter; + MakeImage( + image: SkImage, + srcRect?: SkRect | null, + dstRect?: SkRect | null, + filterMode?: FilterMode, + mipmap?: MipmapMode + ): SkImageFilter; /** - * This filter takes an SkBlendMode and uses it to composite the two filters together. - * @param mode The blend mode that defines the compositing operation - * @param background The Dst pixels used in blending, if null the source bitmap is used. - * @param foreground The Src pixels used in blending, if null the source bitmap is used. - * @cropRect Optional rectangle to crop input and output. + * Create a filter that fills 'lensBounds' with a magnification of the input. + * + * @param lensBounds The outer bounds of the magnifier effect + * @param zoomAmount The amount of magnification applied to the input image + * @param inset The size or width of the fish-eye distortion around the magnified content + * @param filterMode The filter mode to use when sampling the image @default FilterMode.Nearest + * @param mipmap The mipmap mode to use when sampling the image @default MipmapMode.None + * @param input The input filter that is magnified; if null the source bitmap is used + * @param cropRect Optional rectangle that crops the input and output. */ - MakeBlend: ( - mode: BlendMode, - background: SkImageFilter, - foreground: SkImageFilter | null, - cropRect?: SkRect - ) => SkImageFilter; + MakeMagnifier( + lensBounds: SkRect, + zoomAmount: number, + inset: number, + filterMode?: FilterMode, + mipmap?: MipmapMode, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that applies an NxM image processing kernel to the input image. This can be + * used to produce effects such as sharpening, blurring, edge detection, etc. + * @param kernelSizeX The width of the kernel. Must be greater than zero. + * @param kernelSizeY The height of the kernel. Must be greater than zero. + * @param kernel The image processing kernel. Must contain kernelSizeX * kernelSizeY elements, in row order. + * @param gain A scale factor applied to each pixel after convolution. This can be + * used to normalize the kernel, if it does not already sum to 1. + * @param bias A bias factor added to each pixel after convolution. + * @param kernelOffsetX An offset applied to each pixel coordinate before convolution. + * This can be used to center the kernel over the image + * (e.g., a 3x3 kernel should have an offset of {1, 1}). + * @param kernelOffsetY An offset applied to each pixel coordinate before convolution. + * This can be used to center the kernel over the image + * (e.g., a 3x3 kernel should have an offset of {1, 1}). + * @param tileMode How accesses outside the image are treated. TileMode.Mirror is not supported. + * @param convolveAlpha If true, all channels are convolved. If false, only the RGB channels + * are convolved, and alpha is copied from the source image. + * @param input The input image filter, if null the source bitmap is used instead. + * @param cropRect Optional rectangle to which the output processing will be limited. + */ + MakeMatrixConvolution( + kernelSizeX: number, + kernelSizeY: number, + kernel: number[], + gain: number, + bias: number, + kernelOffsetX: number, + kernelOffsetY: number, + tileMode: TileMode, + convolveAlpha: boolean, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that transforms the input image by 'matrix'. This matrix transforms the + * local space, which means it effectively happens prior to any transformation coming from the + * SkCanvas initiating the filtering. + * @param matrix The matrix to apply to the original content. + * @param filterMode The filter mode to use when sampling the image @default FilterMode.Nearest + * @param mipmap The mipmap mode to use when sampling the image @default MipmapMode.None + * @param input The image filter to transform, or null to use the source image. + */ + MakeMatrixTransform( + matrix: number[], + filterMode?: FilterMode, + mipmap?: MipmapMode, + input?: SkImageFilter | null + ): SkImageFilter; + /** + * Create a filter that merges filters together by drawing their results in order + * with src-over blending. + * @param filters The input filter array to merge. Any null + * filter pointers will use the source bitmap instead. + * @param cropRect Optional rectangle that crops all input filters and the output. + */ + MakeMerge( + filters: Array, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that offsets the input filter by the given vector. + * @param dx The x offset in local space that the image is shifted. + * @param dy The y offset in local space that the image is shifted. + * @param input The input that will be moved, if null the source bitmap is used instead. + * @param cropRect Optional rectangle to crop the input and output. + */ + MakeOffset( + dx: number, + dy: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that produces the SkPicture as its output, clipped to both 'targetRect' and + * the picture's internal cull rect. + * + * If 'pic' is null, the returned image filter produces transparent black. + * + * @param picture The picture that is drawn for the filter output. + * @param targetRect The drawing region for the picture. If null, the picture's bounds are used. + */ + MakePicture(picture: SkImage, targetRect?: SkRect | null): SkImageFilter; /** * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced * by the SkRuntimeShaderBuilder. The shader is defined in the image filter's local coordinate @@ -189,4 +319,228 @@ export interface ImageFilterFactory { childShaderName: string | null, input: SkImageFilter | null ) => SkImageFilter; + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced + * by the SkRuntimeEffectBuilder. The shader is defined in the image filter's local coordinate + * system, so it will automatically be affected by SkCanvas' transform. + * + * This requires a GPU backend or SkSL to be compiled in. + * + * @param builder The builder used to produce the runtime shader, that will in turn + * fill the result image + * @param childShaderNames The names of the child shaders defined in the builder that will be + * bound to the input params (or the source image if the input param + * is null). If any name is null, or appears more than once, factory + * fails and returns nullptr. + * @param sampleRadius defines the sampling radius of 'childShaderName' relative to + * the runtime shader produced by 'builder'. + * If greater than 0, the coordinate passed to childShader.eval() will + * be up to 'sampleRadius' away (maximum absolute offset in 'x' or 'y') + * from the coordinate passed into the runtime shader. + * @param inputs The image filters that will be provided as input to the runtime + * shader. If any are null, the implicit source image is used instead. + */ + MakeRuntimeShaderWithChildren: ( + builder: SkRuntimeShaderBuilder, + childShaderNames: string[], + sampleRadius: number, + inputs: Array + ) => SkImageFilter; + /** + * Transforms a shader into an impage filter + * + * @param shader - The Shader to be transformed + * @param input - if null, it will use the dynamic source image + * @param cropRect - Optional rectangle to crop input and output. + */ + MakeShader( + shader: SkShader, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a tile image filter. + * @param src Defines the pixels to tile + * @param dst Defines the pixel region that the tiles will be drawn to + * @param input The input that will be tiled, if null the source bitmap is used instead. + */ + MakeTile( + src: SkRect, + dst: SkRect, + input?: SkImageFilter | null + ): SkImageFilter; + /** + * Create a filter that dilates each input pixel's channel values to the max value within the + * given radii along the x and y axes. + * @param radiusX The distance to dilate along the x axis to either side of each pixel. + * @param radiusY The distance to dilate along the y axis to either side of each pixel. + * @param input The image filter that is dilated, using source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakeDilate: ( + rx: number, + ry: number, + input: SkImageFilter | null, + cropRect?: SkRect | null + ) => SkImageFilter; + /** + * Create a filter that erodes each input pixel's channel values to the minimum channel value + * within the given radii along the x and y axes. + * @param radiusX The distance to erode along the x axis to either side of each pixel. + * @param radiusY The distance to erode along the y axis to either side of each pixel. + * @param input The image filter that is eroded, using source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakeErode: ( + rx: number, + ry: number, + input: SkImageFilter | null, + cropRect?: SkRect | null + ) => SkImageFilter; + /** + * Create a filter that calculates the diffuse illumination from a distant light source, + * interpreting the alpha channel of the input as the height profile of the surface (to + * approximate normal vectors). + * @param direction The direction to the distance light. + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakeDistantLitDiffuse( + direction: SkPoint3, + lightColor: SkColor, + surfaceScale: number, + kd: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that calculates the diffuse illumination from a point light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). + * @param location The location of the point light. + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakePointLitDiffuse( + location: SkPoint3, + lightColor: SkColor, + surfaceScale: number, + kd: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that calculates the diffuse illumination from a spot light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between + * the location and target. + * @param location The location of the spot light. + * @param target The location that the spot light is point towards + * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle + * @param cutoffAngle Maximum angle from lighting direction that receives full light + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakeSpotLitDiffuse( + location: SkPoint3, + target: SkPoint3, + falloffExponent: number, + cutoffAngle: number, + lightColor: SkColor, + surfaceScale: number, + kd: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that calculates the specular illumination from a distant light source, + * interpreting the alpha channel of the input as the height profile of the surface (to + * approximate normal vectors). + * @param direction The direction to the distance light. + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakeDistantLitSpecular( + direction: SkPoint3, + lightColor: SkColor, + surfaceScale: number, + ks: number, + shininess: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that calculates the specular illumination from a point light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). + * @param location The location of the point light. + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakePointLitSpecular( + location: SkPoint3, + lightColor: SkColor, + surfaceScale: number, + ks: number, + shininess: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; + /** + * Create a filter that calculates the specular illumination from a spot light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between + * the location and target. + * @param location The location of the spot light. + * @param target The location that the spot light is point towards + * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle + * @param cutoffAngle Maximum angle from lighting direction that receives full light + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + MakeSpotLitSpecular( + location: SkPoint3, + target: SkPoint3, + falloffExponent: number, + cutoffAngle: number, + lightColor: SkColor, + surfaceScale: number, + ks: number, + shininess: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter; } + +export type SkPoint3 = { + x: number; + y: number; + z: number; +}; From b727a28a149f924be5d85a9ea1291613680942ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 18 Dec 2024 19:01:45 +0100 Subject: [PATCH 2/6] implement web version --- .../types/ImageFilter/ImageFilterFactory.ts | 2 +- .../src/skia/web/JsiSkImageFilterFactory.ts | 308 +++++++++++++----- 2 files changed, 235 insertions(+), 75 deletions(-) diff --git a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts index 6b0beb0b93..e252a569f8 100644 --- a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts +++ b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts @@ -380,7 +380,7 @@ export interface ImageFilterFactory { MakeDilate: ( rx: number, ry: number, - input: SkImageFilter | null, + input?: SkImageFilter | null, cropRect?: SkRect | null ) => SkImageFilter; /** diff --git a/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts b/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts index 79c203049d..5f788b8749 100644 --- a/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts +++ b/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts @@ -1,21 +1,26 @@ -import type { CanvasKit, ImageFilter } from "canvaskit-wasm"; - -import type { - ColorChannel, - ImageFilterFactory, - SkColor, - SkColorFilter, - SkImageFilter, - BlendMode, - SkRect, - SkRuntimeShaderBuilder, - SkShader, - TileMode, +import type { CanvasKit, Image, ImageFilter } from "canvaskit-wasm"; + +import { + type ColorChannel, + type ImageFilterFactory, + type SkColor, + type SkColorFilter, + type SkImageFilter, + type BlendMode, + type SkRect, + type SkRuntimeShaderBuilder, + type SkShader, + type TileMode, + type SkImage, + type FilterMode, + type MipmapMode, } from "../types"; import { Host, NotImplementedOnRNWeb, getEnum } from "./Host"; import { JsiSkImageFilter } from "./JsiSkImageFilter"; import { JsiSkColorFilter } from "./JsiSkColorFilter"; +import { JsiSkImage } from "./JsiSkImage"; +import { JsiSkRect } from "./JsiSkRect"; export class JsiSkImageFilterFactory extends Host @@ -25,62 +30,71 @@ export class JsiSkImageFilterFactory super(CanvasKit); } - MakeOffset(dx: number, dy: number, input: SkImageFilter | null) { - const inputFilter = - input === null ? null : JsiSkImageFilter.fromValue(input); - const filter = this.CanvasKit.ImageFilter.MakeOffset(dx, dy, inputFilter); - return new JsiSkImageFilter(this.CanvasKit, filter); + MakeArithmetic(): SkImageFilter { + throw new NotImplementedOnRNWeb(); } - MakeDisplacementMap( - channelX: ColorChannel, - channelY: ColorChannel, - scale: number, - in1: SkImageFilter, - input: SkImageFilter | null + MakeBlend( + mode: BlendMode, + background: SkImageFilter, + foreground?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter { const inputFilter = - input === null ? null : JsiSkImageFilter.fromValue(input); - const filter = this.CanvasKit.ImageFilter.MakeDisplacementMap( - getEnum(this.CanvasKit.ColorChannel, channelX), - getEnum(this.CanvasKit.ColorChannel, channelY), - scale, - JsiSkImageFilter.fromValue(in1), + foreground == null + ? null + : JsiSkImageFilter.fromValue(foreground); + if (cropRect) { + throw new NotImplementedOnRNWeb( + "The cropRect argument is not yet supported on React Native Web." + ); + } + const filter = this.CanvasKit.ImageFilter.MakeBlend( + getEnum(this.CanvasKit.BlendMode, mode), + JsiSkImageFilter.fromValue(background), inputFilter ); return new JsiSkImageFilter(this.CanvasKit, filter); } - MakeShader(shader: SkShader, _input: SkImageFilter | null): SkImageFilter { - const filter = this.CanvasKit.ImageFilter.MakeShader( - JsiSkImageFilter.fromValue(shader) - ); - return new JsiSkImageFilter(this.CanvasKit, filter); - } - MakeBlur( sigmaX: number, sigmaY: number, mode: TileMode, - input: SkImageFilter | null + input?: SkImageFilter | null, + cropRect?: SkRect | null ) { + if (cropRect) { + throw new NotImplementedOnRNWeb( + "The cropRect argument is not yet supported on React Native Web." + ); + } return new JsiSkImageFilter( this.CanvasKit, this.CanvasKit.ImageFilter.MakeBlur( sigmaX, sigmaY, getEnum(this.CanvasKit.TileMode, mode), - input === null ? null : JsiSkImageFilter.fromValue(input) + input == null ? null : JsiSkImageFilter.fromValue(input) ) ); } - MakeColorFilter(cf: SkColorFilter, input: SkImageFilter | null) { + MakeColorFilter( + cf: SkColorFilter, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ) { + if (cropRect) { + throw new NotImplementedOnRNWeb( + "The cropRect argument is not yet supported on React Native Web." + ); + } return new JsiSkImageFilter( this.CanvasKit, this.CanvasKit.ImageFilter.MakeColorFilter( JsiSkColorFilter.fromValue(cf), - input === null ? null : JsiSkImageFilter.fromValue(input) + input == null ? null : JsiSkImageFilter.fromValue(input) ) ); } @@ -95,17 +109,46 @@ export class JsiSkImageFilterFactory ); } + MakeCrop(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeDisplacementMap( + channelX: ColorChannel, + channelY: ColorChannel, + scale: number, + in1: SkImageFilter, + input?: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter { + if (cropRect) { + throw new NotImplementedOnRNWeb( + "The cropRect argument is not yet supported on React Native Web." + ); + } + const inputFilter = + input == null ? null : JsiSkImageFilter.fromValue(input); + const filter = this.CanvasKit.ImageFilter.MakeDisplacementMap( + getEnum(this.CanvasKit.ColorChannel, channelX), + getEnum(this.CanvasKit.ColorChannel, channelY), + scale, + JsiSkImageFilter.fromValue(in1), + inputFilter + ); + return new JsiSkImageFilter(this.CanvasKit, filter); + } + MakeDropShadow( dx: number, dy: number, sigmaX: number, sigmaY: number, color: SkColor, - input: SkImageFilter | null, - cropRect?: SkRect + input?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter { const inputFilter = - input === null ? null : JsiSkImageFilter.fromValue(input); + input == null ? null : JsiSkImageFilter.fromValue(input); if (cropRect) { throw new NotImplementedOnRNWeb( "The cropRect argument is not yet supported on React Native Web." @@ -128,11 +171,11 @@ export class JsiSkImageFilterFactory sigmaX: number, sigmaY: number, color: SkColor, - input: SkImageFilter | null, - cropRect?: SkRect + input?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter { const inputFilter = - input === null ? null : JsiSkImageFilter.fromValue(input); + input == null ? null : JsiSkImageFilter.fromValue(input); if (cropRect) { throw new NotImplementedOnRNWeb( "The cropRect argument is not yet supported on React Native Web." @@ -149,31 +192,138 @@ export class JsiSkImageFilterFactory return new JsiSkImageFilter(this.CanvasKit, filter); } - MakeErode( - rx: number, - ry: number, - input: SkImageFilter | null, - cropRect?: SkRect + MakeEmpty(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeImage( + image: SkImage, + srcRect?: SkRect | null, + dstRect?: SkRect | null, + filterMode?: FilterMode, + mipmap?: MipmapMode ): SkImageFilter { + const skImage = JsiSkImage.fromValue(image); + const sampling = { + filter: filterMode + ? getEnum(this.CanvasKit.FilterMode, filterMode) + : this.CanvasKit.FilterMode.Nearest, + mipmap: mipmap + ? getEnum(this.CanvasKit.MipmapMode, mipmap) + : this.CanvasKit.MipmapMode.None, + }; + let filter: ImageFilter | null; + if (srcRect) { + if (!dstRect) { + dstRect = srcRect; + } + filter = this.CanvasKit.ImageFilter.MakeImage( + skImage, + sampling, + JsiSkRect.fromValue(this.CanvasKit, srcRect), + JsiSkRect.fromValue(this.CanvasKit, dstRect) + ); + } else { + filter = this.CanvasKit.ImageFilter.MakeImage(skImage, sampling); + } + if (!filter) { + throw new Error("Failed to create image filter"); + } + return new JsiSkImageFilter(this.CanvasKit, filter); + } + + MakeMagnifier(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeMatrixConvolution(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeMatrixTransform( + matrix: number[], + filterMode?: FilterMode, + mipmap?: MipmapMode, + input?: SkImageFilter | null + ): SkImageFilter { + const sampling = { + filter: filterMode + ? getEnum(this.CanvasKit.FilterMode, filterMode) + : this.CanvasKit.FilterMode.Nearest, + mipmap: mipmap + ? getEnum(this.CanvasKit.MipmapMode, mipmap) + : this.CanvasKit.MipmapMode.None, + }; + const inputFilter = + input == null ? null : JsiSkImageFilter.fromValue(input); + const filter = this.CanvasKit.ImageFilter.MakeMatrixTransform( + matrix, + sampling, + inputFilter + ); + return new JsiSkImageFilter(this.CanvasKit, filter); + } + + MakeMerge(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeOffset(dx: number, dy: number, input: SkImageFilter | null) { const inputFilter = input === null ? null : JsiSkImageFilter.fromValue(input); + const filter = this.CanvasKit.ImageFilter.MakeOffset(dx, dy, inputFilter); + return new JsiSkImageFilter(this.CanvasKit, filter); + } + + MakePicture(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeRuntimeShader( + _builder: SkRuntimeShaderBuilder, + _childShaderName: string | null, + _input: SkImageFilter | null + ): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeRuntimeShaderWithChildren(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeShader( + shader: SkShader, + input: SkImageFilter | null, + cropRect?: SkRect | null + ): SkImageFilter { if (cropRect) { throw new NotImplementedOnRNWeb( "The cropRect argument is not yet supported on React Native Web." ); } - const filter = this.CanvasKit.ImageFilter.MakeErode(rx, ry, inputFilter); + if (input) { + throw new NotImplementedOnRNWeb( + "The input argument is not yet supported on React Native Web." + ); + } + const filter = this.CanvasKit.ImageFilter.MakeShader( + JsiSkImageFilter.fromValue(shader) + ); return new JsiSkImageFilter(this.CanvasKit, filter); } + MakeTile(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + MakeDilate( rx: number, ry: number, - input: SkImageFilter | null, - cropRect?: SkRect + input?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter { const inputFilter = - input === null ? null : JsiSkImageFilter.fromValue(input); + input == null ? null : JsiSkImageFilter.fromValue(input); if (cropRect) { throw new NotImplementedOnRNWeb( "The cropRect argument is not yet supported on React Native Web." @@ -183,34 +333,44 @@ export class JsiSkImageFilterFactory return new JsiSkImageFilter(this.CanvasKit, filter); } - MakeBlend( - mode: BlendMode, - background: SkImageFilter, - foreground: SkImageFilter | null, - cropRect?: SkRect + MakeErode( + rx: number, + ry: number, + input?: SkImageFilter | null, + cropRect?: SkRect | null ): SkImageFilter { const inputFilter = - foreground === null - ? null - : JsiSkImageFilter.fromValue(foreground); + input == null ? null : JsiSkImageFilter.fromValue(input); if (cropRect) { throw new NotImplementedOnRNWeb( "The cropRect argument is not yet supported on React Native Web." ); } - const filter = this.CanvasKit.ImageFilter.MakeBlend( - getEnum(this.CanvasKit.BlendMode, mode), - JsiSkImageFilter.fromValue(background), - inputFilter - ); + const filter = this.CanvasKit.ImageFilter.MakeErode(rx, ry, inputFilter); return new JsiSkImageFilter(this.CanvasKit, filter); } - MakeRuntimeShader( - _builder: SkRuntimeShaderBuilder, - _childShaderName: string | null, - _input: SkImageFilter | null - ): SkImageFilter { + MakeDistantLitDiffuse(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakePointLitDiffuse(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeSpotLitDiffuse(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeDistantLitSpecular(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakePointLitSpecular(): SkImageFilter { + throw new NotImplementedOnRNWeb(); + } + + MakeSpotLitSpecular(): SkImageFilter { throw new NotImplementedOnRNWeb(); } } From 594c6ba9c86dd07738b658972ca471ca0220c7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Thu, 19 Dec 2024 13:28:35 +0100 Subject: [PATCH 3/6] fix wrong signatures --- .../skia/cpp/api/JsiSkImageFilterFactory.h | 31 +++++++++---------- .../types/ImageFilter/ImageFilterFactory.ts | 12 ++++--- .../src/skia/web/JsiSkImageFilterFactory.ts | 11 ++++--- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/skia/cpp/api/JsiSkImageFilterFactory.h b/packages/skia/cpp/api/JsiSkImageFilterFactory.h index 3a2b1ad584..c5ebd23496 100644 --- a/packages/skia/cpp/api/JsiSkImageFilterFactory.h +++ b/packages/skia/cpp/api/JsiSkImageFilterFactory.h @@ -31,12 +31,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float k4 = arguments[3].asNumber(); bool enforcePMColor = arguments[4].asBool(); sk_sp background = nullptr; - if (count > 5 && !!arguments[5].isNull() && !!arguments[5].isUndefined()) { + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { background = JsiSkImageFilter::fromValue(runtime, arguments[5]); } - sk_sp imageFilter = nullptr; + sk_sp foreground = nullptr; if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { - imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[6]); + foreground = JsiSkImageFilter::fromValue(runtime, arguments[6]); } SkImageFilters::CropRect cropRect = {}; if (count > 7 && !arguments[7].isNull() && !arguments[7].isUndefined()) { @@ -47,7 +47,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { getContext(), SkImageFilters::Arithmetic( k1, k2, k3, k4, enforcePMColor, std::move(background), - std::move(imageFilter), cropRect))); + std::move(foreground), cropRect))); } JSI_HOST_FUNCTION(MakeBlend) { @@ -98,14 +98,13 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { } SkImageFilters::CropRect cropRect = {}; if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { - cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + cropRect = *JsiSkRect::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( getContext(), - SkImageFilters::ColorFilter(std::move(cf), std::move(input)), - cropRect)); + SkImageFilters::ColorFilter(std::move(cf), std::move(input), cropRect))); } JSI_HOST_FUNCTION(MakeCompose) { @@ -221,7 +220,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { } SkRect dstRect; if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { - dstRect = *JsiSkRect::fromValue(runtime, arguments[3]); + dstRect = *JsiSkRect::fromValue(runtime, arguments[2]); } else { dstRect = srcRect; } @@ -358,7 +357,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { return jsi::Object::createFromHostObject( runtime, std::make_shared( getContext(), - SkImageFilters::Offset(x, y, std::move(input)), cropRect)); + SkImageFilters::Offset(x, y, std::move(input), cropRect))); } JSI_HOST_FUNCTION(MakePicture) { @@ -439,7 +438,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { } SkImageFilters::CropRect cropRect = {}; if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { - cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + cropRect = *JsiSkRect::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( @@ -574,12 +573,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float ks = arguments[3].asNumber(); float shininess = arguments[4].asNumber(); sk_sp input; - if (count > 4 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 5 && !arguments[6].isNull() && !arguments[6].isUndefined()) { - cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); + if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( @@ -595,12 +594,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float ks = arguments[3].asNumber(); float shininess = arguments[4].asNumber(); sk_sp input; - if (count > 4 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 5 && !arguments[6].isNull() && !arguments[6].isUndefined()) { - cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); + if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( diff --git a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts index e252a569f8..bdaf20285f 100644 --- a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts +++ b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts @@ -1,7 +1,9 @@ import type { SkColor } from "../Color"; import type { SkColorFilter } from "../ColorFilter/ColorFilter"; import type { FilterMode, MipmapMode, SkImage } from "../Image/Image"; +import type { SkMatrix } from "../Matrix"; import type { BlendMode } from "../Paint"; +import type { SkPicture } from "../Picture"; import type { SkRect } from "../Rect"; import type { SkRuntimeShaderBuilder } from "../RuntimeEffect"; import type { SkShader } from "../Shader"; @@ -261,7 +263,7 @@ export interface ImageFilterFactory { * @param input The image filter to transform, or null to use the source image. */ MakeMatrixTransform( - matrix: number[], + matrix: SkMatrix, filterMode?: FilterMode, mipmap?: MipmapMode, input?: SkImageFilter | null @@ -299,7 +301,7 @@ export interface ImageFilterFactory { * @param picture The picture that is drawn for the filter output. * @param targetRect The drawing region for the picture. If null, the picture's bounds are used. */ - MakePicture(picture: SkImage, targetRect?: SkRect | null): SkImageFilter; + MakePicture(picture: SkPicture, targetRect?: SkRect | null): SkImageFilter; /** * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced * by the SkRuntimeShaderBuilder. The shader is defined in the image filter's local coordinate @@ -342,20 +344,20 @@ export interface ImageFilterFactory { */ MakeRuntimeShaderWithChildren: ( builder: SkRuntimeShaderBuilder, - childShaderNames: string[], sampleRadius: number, + childShaderNames: string[], inputs: Array ) => SkImageFilter; /** * Transforms a shader into an impage filter * * @param shader - The Shader to be transformed - * @param input - if null, it will use the dynamic source image + * @param dither * @param cropRect - Optional rectangle to crop input and output. */ MakeShader( shader: SkShader, - input?: SkImageFilter | null, + dither?: boolean, cropRect?: SkRect | null ): SkImageFilter; /** diff --git a/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts b/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts index 5f788b8749..a7fda5ae24 100644 --- a/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts +++ b/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts @@ -14,6 +14,7 @@ import { type SkImage, type FilterMode, type MipmapMode, + SkMatrix, } from "../types"; import { Host, NotImplementedOnRNWeb, getEnum } from "./Host"; @@ -241,7 +242,7 @@ export class JsiSkImageFilterFactory } MakeMatrixTransform( - matrix: number[], + matrix: SkMatrix, filterMode?: FilterMode, mipmap?: MipmapMode, input?: SkImageFilter | null @@ -257,7 +258,7 @@ export class JsiSkImageFilterFactory const inputFilter = input == null ? null : JsiSkImageFilter.fromValue(input); const filter = this.CanvasKit.ImageFilter.MakeMatrixTransform( - matrix, + matrix.get(), sampling, inputFilter ); @@ -293,7 +294,7 @@ export class JsiSkImageFilterFactory MakeShader( shader: SkShader, - input: SkImageFilter | null, + dither?: boolean, cropRect?: SkRect | null ): SkImageFilter { if (cropRect) { @@ -301,9 +302,9 @@ export class JsiSkImageFilterFactory "The cropRect argument is not yet supported on React Native Web." ); } - if (input) { + if (dither != null) { throw new NotImplementedOnRNWeb( - "The input argument is not yet supported on React Native Web." + "The dither argument is not yet supported on React Native Web." ); } const filter = this.CanvasKit.ImageFilter.MakeShader( From 53f1ca5c68beaaff2941be1348264e98ce6694e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Thu, 19 Dec 2024 14:19:38 +0100 Subject: [PATCH 4/6] factorize optional argument management --- .../skia/cpp/api/JsiSkImageFilterFactory.h | 160 +++++++++--------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/packages/skia/cpp/api/JsiSkImageFilterFactory.h b/packages/skia/cpp/api/JsiSkImageFilterFactory.h index c5ebd23496..7a496d2663 100644 --- a/packages/skia/cpp/api/JsiSkImageFilterFactory.h +++ b/packages/skia/cpp/api/JsiSkImageFilterFactory.h @@ -22,6 +22,12 @@ namespace RNSkia { namespace jsi = facebook::jsi; +inline bool hasOptionalArgument(const jsi::Value *arguments, size_t count, + size_t index) { + return (index < count && !arguments[index].isNull() && + !arguments[index].isUndefined()); +} + class JsiSkImageFilterFactory : public JsiSkHostObject { public: JSI_HOST_FUNCTION(MakeArithmetic) { @@ -31,15 +37,15 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float k4 = arguments[3].asNumber(); bool enforcePMColor = arguments[4].asBool(); sk_sp background = nullptr; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + if (hasOptionalArgument(arguments, count, 5)) { background = JsiSkImageFilter::fromValue(runtime, arguments[5]); } sk_sp foreground = nullptr; - if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + if (hasOptionalArgument(arguments, count, 6)) { foreground = JsiSkImageFilter::fromValue(runtime, arguments[6]); } SkImageFilters::CropRect cropRect = {}; - if (count > 7 && !arguments[7].isNull() && !arguments[7].isUndefined()) { + if (hasOptionalArgument(arguments, count, 7)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[7]); } return jsi::Object::createFromHostObject( @@ -55,12 +61,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { sk_sp background = JsiSkImageFilter::fromValue(runtime, arguments[1]); sk_sp foreground = nullptr; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + if (hasOptionalArgument(arguments, count, 2)) { foreground = JsiSkImageFilter::fromValue(runtime, arguments[2]); } SkImageFilters::CropRect cropRect = {}; - if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + if (hasOptionalArgument(arguments, count, 3)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); } @@ -76,11 +82,11 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float sigmaY = arguments[1].asNumber(); int tileMode = arguments[2].asNumber(); sk_sp imageFilter; - if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + if (hasOptionalArgument(arguments, count, 3)) { imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[3]); } SkImageFilters::CropRect cropRect = {}; - if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + if (hasOptionalArgument(arguments, count, 4)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[4]); } return jsi::Object::createFromHostObject( @@ -92,28 +98,28 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeColorFilter) { auto cf = JsiSkColorFilter::fromValue(runtime, arguments[0]); - sk_sp input; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 1)) { input = JsiSkImageFilter::fromValue(runtime, arguments[1]); } SkImageFilters::CropRect cropRect = {}; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + if (hasOptionalArgument(arguments, count, 2)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( runtime, std::make_shared( - getContext(), - SkImageFilters::ColorFilter(std::move(cf), std::move(input), cropRect))); + getContext(), SkImageFilters::ColorFilter( + std::move(cf), std::move(input), cropRect))); } JSI_HOST_FUNCTION(MakeCompose) { - sk_sp outer; - if (count > 0 && !arguments[0].isNull() && !arguments[0].isUndefined()) { + sk_sp outer = nullptr; + if (hasOptionalArgument(arguments, count, 0)) { outer = JsiSkImageFilter::fromValue(runtime, arguments[0]); } - sk_sp inner; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + sk_sp inner = nullptr; + if (hasOptionalArgument(arguments, count, 1)) { inner = JsiSkImageFilter::fromValue(runtime, arguments[1]); } return jsi::Object::createFromHostObject( @@ -125,11 +131,11 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeCrop) { SkRect rect = *JsiSkRect::fromValue(runtime, arguments[0]); SkTileMode tileMode = SkTileMode::kDecal; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { tileMode = (SkTileMode)arguments[1].asNumber(); } - sk_sp imageFilter; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + sk_sp imageFilter = nullptr; + if (hasOptionalArgument(arguments, count, 2)) { imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( @@ -146,12 +152,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { static_cast(arguments[1].asNumber()); auto scale = arguments[2].asNumber(); auto in1 = JsiSkImageFilter::fromValue(runtime, arguments[3]); - sk_sp input; - if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 4)) { input = JsiSkImageFilter::fromValue(runtime, arguments[4]); } SkImageFilters::CropRect cropRect = {}; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + if (hasOptionalArgument(arguments, count, 5)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); } return jsi::Object::createFromHostObject( @@ -168,12 +174,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { auto sigmaX = arguments[2].asNumber(); auto sigmaY = arguments[3].asNumber(); auto color = JsiSkColor::fromValue(runtime, arguments[4]); - sk_sp input; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 5)) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + if (hasOptionalArgument(arguments, count, 6)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -189,12 +195,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { auto sigmaX = arguments[2].asNumber(); auto sigmaY = arguments[3].asNumber(); auto color = JsiSkColor::fromValue(runtime, arguments[4]); - sk_sp input; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 5)) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + if (hasOptionalArgument(arguments, count, 6)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -213,23 +219,23 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeImage) { sk_sp image = JsiSkImage::fromValue(runtime, arguments[0]); SkRect srcRect; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { srcRect = *JsiSkRect::fromValue(runtime, arguments[1]); } else { srcRect = SkRect::Make(image->bounds()); } SkRect dstRect; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + if (hasOptionalArgument(arguments, count, 2)) { dstRect = *JsiSkRect::fromValue(runtime, arguments[2]); } else { dstRect = srcRect; } SkFilterMode filterMode = SkFilterMode::kNearest; - if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + if (hasOptionalArgument(arguments, count, 3)) { filterMode = (SkFilterMode)arguments[3].asNumber(); } SkMipmapMode mipmap = SkMipmapMode::kNone; - if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + if (hasOptionalArgument(arguments, count, 4)) { mipmap = (SkMipmapMode)arguments[4].asNumber(); } return jsi::Object::createFromHostObject( @@ -244,19 +250,19 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float zoomAmount = arguments[1].asNumber(); float inset = arguments[2].asNumber(); SkFilterMode filterMode = SkFilterMode::kNearest; - if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + if (hasOptionalArgument(arguments, count, 3)) { filterMode = (SkFilterMode)arguments[3].asNumber(); } SkMipmapMode mipmap = SkMipmapMode::kNone; - if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + if (hasOptionalArgument(arguments, count, 4)) { mipmap = (SkMipmapMode)arguments[4].asNumber(); } - sk_sp input; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 5)) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + if (hasOptionalArgument(arguments, count, 6)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -282,12 +288,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { SkIPoint(arguments[5].asNumber(), arguments[6].asNumber()); SkTileMode tileMode = (SkTileMode)arguments[7].asNumber(); bool convolveAlpha = arguments[8].asBool(); - sk_sp input; - if (count > 9 && !arguments[9].isNull() && !arguments[9].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 9)) { input = JsiSkImageFilter::fromValue(runtime, arguments[9]); } SkImageFilters::CropRect cropRect = {}; - if (count > 10 && !arguments[10].isNull() && !arguments[10].isUndefined()) { + if (hasOptionalArgument(arguments, count, 10)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[10]); } return jsi::Object::createFromHostObject( @@ -301,15 +307,15 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeMatrixTransform) { SkMatrix matrix = *JsiSkMatrix::fromValue(runtime, arguments[0]); SkFilterMode filterMode = SkFilterMode::kNearest; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { filterMode = (SkFilterMode)arguments[1].asNumber(); } SkMipmapMode mipmap = SkMipmapMode::kNone; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + if (hasOptionalArgument(arguments, count, 2)) { mipmap = (SkMipmapMode)arguments[2].asNumber(); } - sk_sp input; - if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 3)) { input = JsiSkImageFilter::fromValue(runtime, arguments[3]); } return jsi::Object::createFromHostObject( @@ -333,7 +339,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { } } SkImageFilters::CropRect cropRect = {}; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[1]); } return jsi::Object::createFromHostObject( @@ -346,12 +352,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeOffset) { auto x = arguments[0].asNumber(); auto y = arguments[1].asNumber(); - sk_sp input; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 2)) { input = JsiSkImageFilter::fromValue(runtime, arguments[2]); } SkImageFilters::CropRect cropRect = {}; - if (count > 3 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + if (hasOptionalArgument(arguments, count, 3)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); } return jsi::Object::createFromHostObject( @@ -363,7 +369,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakePicture) { sk_sp picture = JsiSkPicture::fromValue(runtime, arguments[0]); SkRect targetRect; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { targetRect = *JsiSkRect::fromValue(runtime, arguments[1]); } else { targetRect = picture ? picture->cullRect() : SkRect::MakeEmpty(); @@ -376,14 +382,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeRuntimeShader) { auto rtb = JsiSkRuntimeShaderBuilder::fromValue(runtime, arguments[0]); - const char *childName = ""; - if (!arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { childName = arguments[1].asString(runtime).utf8(runtime).c_str(); } - - sk_sp input; - if (!arguments[2].isNull() && !arguments[2].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 2)) { input = JsiSkImageFilter::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( @@ -432,12 +436,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeShader) { auto shader = JsiSkShader::fromValue(runtime, arguments[0]); SkImageFilters::Dither dither = SkImageFilters::Dither::kNo; - if (count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + if (hasOptionalArgument(arguments, count, 1)) { dither = arguments[1].asBool() ? SkImageFilters::Dither::kYes : SkImageFilters::Dither::kNo; } SkImageFilters::CropRect cropRect = {}; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + if (hasOptionalArgument(arguments, count, 2)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( @@ -449,8 +453,8 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeTile) { SkRect src = *JsiSkRect::fromValue(runtime, arguments[0]); SkRect dst = *JsiSkRect::fromValue(runtime, arguments[1]); - sk_sp input; - if (count > 2 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 2)) { input = JsiSkImageFilter::fromValue(runtime, arguments[2]); } return jsi::Object::createFromHostObject( @@ -462,7 +466,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeDilate) { auto rx = arguments[0].asNumber(); auto ry = arguments[1].asNumber(); - sk_sp input; + sk_sp input = nullptr; if (!arguments[2].isNull() && !arguments[2].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[2]); } @@ -479,7 +483,7 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { JSI_HOST_FUNCTION(MakeErode) { auto rx = arguments[0].asNumber(); auto ry = arguments[1].asNumber(); - sk_sp input; + sk_sp input = nullptr; if (!arguments[2].isNull() && !arguments[2].isUndefined()) { input = JsiSkImageFilter::fromValue(runtime, arguments[2]); } @@ -507,12 +511,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[1]); float surfaceScale = arguments[2].asNumber(); float kd = arguments[3].asNumber(); - sk_sp input; - if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 4)) { input = JsiSkImageFilter::fromValue(runtime, arguments[4]); } SkImageFilters::CropRect cropRect = {}; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + if (hasOptionalArgument(arguments, count, 5)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); } return jsi::Object::createFromHostObject( @@ -527,12 +531,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[1]); float surfaceScale = arguments[2].asNumber(); float kd = arguments[3].asNumber(); - sk_sp input; - if (count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 4)) { input = JsiSkImageFilter::fromValue(runtime, arguments[4]); } SkImageFilters::CropRect cropRect = {}; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + if (hasOptionalArgument(arguments, count, 5)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[5]); } return jsi::Object::createFromHostObject( @@ -550,12 +554,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { SkColor lightColor = JsiSkColor::fromValue(runtime, arguments[4]); float surfaceScale = arguments[5].asNumber(); float kd = arguments[6].asNumber(); - sk_sp input; - if (count > 7 && !arguments[7].isNull() && !arguments[7].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 7)) { input = JsiSkImageFilter::fromValue(runtime, arguments[7]); } SkImageFilters::CropRect cropRect = {}; - if (count > 8 && !arguments[8].isNull() && !arguments[8].isUndefined()) { + if (hasOptionalArgument(arguments, count, 8)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[8]); } return jsi::Object::createFromHostObject( @@ -572,12 +576,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float surfaceScale = arguments[2].asNumber(); float ks = arguments[3].asNumber(); float shininess = arguments[4].asNumber(); - sk_sp input; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 5)) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + if (hasOptionalArgument(arguments, count, 6)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -593,12 +597,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float surfaceScale = arguments[2].asNumber(); float ks = arguments[3].asNumber(); float shininess = arguments[4].asNumber(); - sk_sp input; - if (count > 5 && !arguments[5].isNull() && !arguments[5].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 5)) { input = JsiSkImageFilter::fromValue(runtime, arguments[5]); } SkImageFilters::CropRect cropRect = {}; - if (count > 6 && !arguments[6].isNull() && !arguments[6].isUndefined()) { + if (hasOptionalArgument(arguments, count, 6)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); } return jsi::Object::createFromHostObject( @@ -617,12 +621,12 @@ class JsiSkImageFilterFactory : public JsiSkHostObject { float surfaceScale = arguments[5].asNumber(); float ks = arguments[6].asNumber(); float shininess = arguments[7].asNumber(); - sk_sp input; - if (count > 8 && !arguments[8].isNull() && !arguments[8].isUndefined()) { + sk_sp input = nullptr; + if (hasOptionalArgument(arguments, count, 8)) { input = JsiSkImageFilter::fromValue(runtime, arguments[8]); } SkImageFilters::CropRect cropRect = {}; - if (count > 9 && !arguments[9].isNull() && !arguments[9].isUndefined()) { + if (hasOptionalArgument(arguments, count, 9)) { cropRect = *JsiSkRect::fromValue(runtime, arguments[9]); } return jsi::Object::createFromHostObject( From 2bc324bb0e3de52104b277f355d8fded3979c6fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Thu, 19 Dec 2024 14:54:59 +0100 Subject: [PATCH 5/6] lint --- .../skia/src/skia/types/ImageFilter/ImageFilterFactory.ts | 2 +- packages/skia/src/skia/web/JsiSkImageFilterFactory.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts index bdaf20285f..fc3506b90c 100644 --- a/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts +++ b/packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts @@ -352,7 +352,7 @@ export interface ImageFilterFactory { * Transforms a shader into an impage filter * * @param shader - The Shader to be transformed - * @param dither + * @param dither * @param cropRect - Optional rectangle to crop input and output. */ MakeShader( diff --git a/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts b/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts index a7fda5ae24..092ee59485 100644 --- a/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts +++ b/packages/skia/src/skia/web/JsiSkImageFilterFactory.ts @@ -1,6 +1,7 @@ import type { CanvasKit, Image, ImageFilter } from "canvaskit-wasm"; -import { +import type { + SkMatrix, type ColorChannel, type ImageFilterFactory, type SkColor, @@ -14,7 +15,6 @@ import { type SkImage, type FilterMode, type MipmapMode, - SkMatrix, } from "../types"; import { Host, NotImplementedOnRNWeb, getEnum } from "./Host"; From 00fe164983fcaf3c3e5dddad4601af51834b0972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Thu, 19 Dec 2024 14:56:22 +0100 Subject: [PATCH 6/6] fix types --- .../skia/src/dom/nodes/paint/ImageFilters.ts | 2 +- .../src/skia/web/JsiSkImageFilterFactory.ts | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/skia/src/dom/nodes/paint/ImageFilters.ts b/packages/skia/src/dom/nodes/paint/ImageFilters.ts index c3636fc016..5e154e4061 100644 --- a/packages/skia/src/dom/nodes/paint/ImageFilters.ts +++ b/packages/skia/src/dom/nodes/paint/ImageFilters.ts @@ -109,7 +109,7 @@ export class DisplacementMapImageFilterNode extends ImageFilterDeclaration