@shopify/react-native-skia 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/android/CMakeLists.txt +1 -0
  2. package/android/build.gradle +1 -0
  3. package/android/cpp/rnskia-android/AHardwareBufferUtils.cpp +31 -0
  4. package/android/cpp/rnskia-android/AHardwareBufferUtils.h +13 -0
  5. package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +75 -0
  6. package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +29 -11
  7. package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +1 -2
  8. package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +3 -2
  9. package/cpp/api/JsiPlatformBuffer.h +51 -0
  10. package/cpp/api/JsiSkApi.h +4 -0
  11. package/cpp/api/JsiSkImage.h +1 -1
  12. package/cpp/api/JsiSkImageFactory.h +15 -2
  13. package/cpp/api/JsiSkSurface.h +9 -1
  14. package/cpp/rnskia/RNSkJsiViewApi.h +48 -0
  15. package/cpp/rnskia/RNSkPlatformContext.h +13 -0
  16. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +6 -0
  17. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +115 -0
  18. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h +4 -0
  19. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +12 -0
  20. package/lib/commonjs/external/reanimated/textures.js +11 -2
  21. package/lib/commonjs/external/reanimated/textures.js.map +1 -1
  22. package/lib/commonjs/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  23. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js +8 -4
  24. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js.map +1 -1
  25. package/lib/commonjs/mock/index.js +1 -0
  26. package/lib/commonjs/mock/index.js.map +1 -1
  27. package/lib/commonjs/renderer/Offscreen.d.ts +2 -2
  28. package/lib/commonjs/renderer/Offscreen.js +2 -2
  29. package/lib/commonjs/renderer/Offscreen.js.map +1 -1
  30. package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +14 -0
  31. package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
  32. package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +12 -0
  33. package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.js +6 -0
  34. package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.js.map +1 -0
  35. package/lib/commonjs/skia/types/PlatformBuffer/index.d.ts +1 -0
  36. package/lib/commonjs/skia/types/PlatformBuffer/index.js +17 -0
  37. package/lib/commonjs/skia/types/PlatformBuffer/index.js.map +1 -0
  38. package/lib/commonjs/skia/types/Skia.d.ts +2 -0
  39. package/lib/commonjs/skia/types/Skia.js.map +1 -1
  40. package/lib/commonjs/skia/types/Surface/Surface.d.ts +8 -0
  41. package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
  42. package/lib/commonjs/skia/types/index.d.ts +1 -0
  43. package/lib/commonjs/skia/types/index.js +11 -0
  44. package/lib/commonjs/skia/types/index.js.map +1 -1
  45. package/lib/commonjs/skia/web/JsiSkImage.d.ts +1 -2
  46. package/lib/commonjs/skia/web/JsiSkImage.js +5 -12
  47. package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
  48. package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +2 -2
  49. package/lib/commonjs/skia/web/JsiSkImageFactory.js +3 -0
  50. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  51. package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.d.ts +8 -0
  52. package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.js +20 -0
  53. package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.js.map +1 -0
  54. package/lib/commonjs/skia/web/JsiSkSurface.d.ts +3 -2
  55. package/lib/commonjs/skia/web/JsiSkSurface.js +8 -6
  56. package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
  57. package/lib/commonjs/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  58. package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js +2 -17
  59. package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js.map +1 -1
  60. package/lib/commonjs/skia/web/JsiSkia.js +3 -1
  61. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  62. package/lib/commonjs/views/SkiaDomView.d.ts +6 -0
  63. package/lib/commonjs/views/SkiaDomView.js +10 -0
  64. package/lib/commonjs/views/SkiaDomView.js.map +1 -1
  65. package/lib/commonjs/views/types.d.ts +1 -0
  66. package/lib/commonjs/views/types.js.map +1 -1
  67. package/lib/module/external/reanimated/textures.js +11 -2
  68. package/lib/module/external/reanimated/textures.js.map +1 -1
  69. package/lib/module/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  70. package/lib/module/external/reanimated/useAnimatedImageValue.js +8 -4
  71. package/lib/module/external/reanimated/useAnimatedImageValue.js.map +1 -1
  72. package/lib/module/mock/index.js +1 -0
  73. package/lib/module/mock/index.js.map +1 -1
  74. package/lib/module/renderer/Offscreen.d.ts +2 -2
  75. package/lib/module/renderer/Offscreen.js +2 -2
  76. package/lib/module/renderer/Offscreen.js.map +1 -1
  77. package/lib/module/skia/types/Image/ImageFactory.d.ts +14 -0
  78. package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
  79. package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +12 -0
  80. package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.js +2 -0
  81. package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.js.map +1 -0
  82. package/lib/module/skia/types/PlatformBuffer/index.d.ts +1 -0
  83. package/lib/module/skia/types/PlatformBuffer/index.js +2 -0
  84. package/lib/module/skia/types/PlatformBuffer/index.js.map +1 -0
  85. package/lib/module/skia/types/Skia.d.ts +2 -0
  86. package/lib/module/skia/types/Skia.js.map +1 -1
  87. package/lib/module/skia/types/Surface/Surface.d.ts +8 -0
  88. package/lib/module/skia/types/Surface/Surface.js.map +1 -1
  89. package/lib/module/skia/types/index.d.ts +1 -0
  90. package/lib/module/skia/types/index.js +1 -0
  91. package/lib/module/skia/types/index.js.map +1 -1
  92. package/lib/module/skia/web/JsiSkImage.d.ts +1 -2
  93. package/lib/module/skia/web/JsiSkImage.js +5 -12
  94. package/lib/module/skia/web/JsiSkImage.js.map +1 -1
  95. package/lib/module/skia/web/JsiSkImageFactory.d.ts +2 -2
  96. package/lib/module/skia/web/JsiSkImageFactory.js +3 -0
  97. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  98. package/lib/module/skia/web/JsiSkPlatformBufferFactory.d.ts +8 -0
  99. package/lib/module/skia/web/JsiSkPlatformBufferFactory.js +13 -0
  100. package/lib/module/skia/web/JsiSkPlatformBufferFactory.js.map +1 -0
  101. package/lib/module/skia/web/JsiSkSurface.d.ts +3 -2
  102. package/lib/module/skia/web/JsiSkSurface.js +8 -6
  103. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  104. package/lib/module/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  105. package/lib/module/skia/web/JsiSkSurfaceFactory.js +2 -17
  106. package/lib/module/skia/web/JsiSkSurfaceFactory.js.map +1 -1
  107. package/lib/module/skia/web/JsiSkia.js +3 -1
  108. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  109. package/lib/module/views/SkiaDomView.d.ts +6 -0
  110. package/lib/module/views/SkiaDomView.js +10 -0
  111. package/lib/module/views/SkiaDomView.js.map +1 -1
  112. package/lib/module/views/types.d.ts +1 -0
  113. package/lib/module/views/types.js.map +1 -1
  114. package/lib/typescript/src/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  115. package/lib/typescript/src/renderer/Offscreen.d.ts +2 -2
  116. package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +14 -0
  117. package/lib/typescript/src/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +12 -0
  118. package/lib/typescript/src/skia/types/PlatformBuffer/index.d.ts +1 -0
  119. package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
  120. package/lib/typescript/src/skia/types/Surface/Surface.d.ts +8 -0
  121. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  122. package/lib/typescript/src/skia/web/JsiSkImage.d.ts +1 -2
  123. package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +2 -2
  124. package/lib/typescript/src/skia/web/JsiSkPlatformBufferFactory.d.ts +8 -0
  125. package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +3 -2
  126. package/lib/typescript/src/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  127. package/lib/typescript/src/views/SkiaDomView.d.ts +6 -0
  128. package/lib/typescript/src/views/types.d.ts +1 -0
  129. package/package.json +1 -1
  130. package/src/external/reanimated/textures.tsx +8 -2
  131. package/src/external/reanimated/useAnimatedImageValue.ts +12 -6
  132. package/src/mock/index.ts +1 -0
  133. package/src/renderer/Offscreen.tsx +3 -3
  134. package/src/skia/types/Image/ImageFactory.ts +15 -0
  135. package/src/skia/types/PlatformBuffer/PlatformBufferFactory.ts +14 -0
  136. package/src/skia/types/PlatformBuffer/index.ts +1 -0
  137. package/src/skia/types/Skia.ts +2 -1
  138. package/src/skia/types/Surface/Surface.ts +10 -0
  139. package/src/skia/types/index.ts +1 -0
  140. package/src/skia/web/JsiSkImage.ts +5 -22
  141. package/src/skia/web/JsiSkImageFactory.ts +13 -2
  142. package/src/skia/web/JsiSkPlatformBufferFactory.ts +22 -0
  143. package/src/skia/web/JsiSkSurface.ts +10 -9
  144. package/src/skia/web/JsiSkSurfaceFactory.ts +4 -20
  145. package/src/skia/web/JsiSkia.ts +2 -0
  146. package/src/views/SkiaDomView.tsx +10 -0
  147. package/src/views/types.ts +1 -0
  148. package/cpp/skia/include/third_party/vulkan/LICENSE +0 -29
  149. package/cpp/skia/modules/skcms/README.chromium +0 -6
  150. package/cpp/skia/readme.txt +0 -1
@@ -47,6 +47,7 @@ add_library(
47
47
  "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp"
48
48
  "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp"
49
49
  "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/GrAHardwareBufferUtils.cpp"
50
+ "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/AHardwareBufferUtils.cpp"
50
51
 
51
52
  "${PROJECT_SOURCE_DIR}/../cpp/jsi/JsiHostObject.cpp"
52
53
  "${PROJECT_SOURCE_DIR}/../cpp/jsi/JsiValue.cpp"
@@ -137,6 +137,7 @@ android {
137
137
  targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
138
138
  versionCode 1
139
139
  versionName "1.0"
140
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
140
141
 
141
142
  externalNativeBuild {
142
143
  cmake {
@@ -0,0 +1,31 @@
1
+ #if __ANDROID_API__ >= 26
2
+
3
+ #include "AHardwareBufferUtils.h"
4
+ #include <android/hardware_buffer.h>
5
+
6
+ namespace RNSkia {
7
+
8
+ uint32_t GetBufferFormatFromSkColorType(SkColorType bufferFormat) {
9
+ switch (bufferFormat) {
10
+ case kRGBA_8888_SkColorType:
11
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
12
+ case kRGB_888x_SkColorType:
13
+ return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
14
+ case kRGBA_F16_SkColorType:
15
+ return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
16
+ case kRGB_565_SkColorType:
17
+ return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
18
+ case kRGBA_1010102_SkColorType:
19
+ return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
20
+ #if __ANDROID_API__ >= 33
21
+ case kAlpha_8_SkColorType:
22
+ return AHARDWAREBUFFER_FORMAT_R8_UNORM;
23
+ #endif
24
+ default:
25
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
26
+ }
27
+ }
28
+
29
+ } // namespace RNSkia
30
+
31
+ #endif
@@ -0,0 +1,13 @@
1
+ #pragma once
2
+
3
+ #include "include/core/SkColorType.h"
4
+
5
+ #if __ANDROID_API__ >= 26
6
+
7
+ namespace RNSkia {
8
+
9
+ uint32_t GetBufferFormatFromSkColorType(SkColorType bufferFormat);
10
+
11
+ } // namespace RNSkia
12
+
13
+ #endif
@@ -1,10 +1,15 @@
1
1
  #pragma once
2
2
 
3
+ // TODO: Add android flags
4
+ #if __ANDROID_API__ >= 26
5
+ #include <android/hardware_buffer.h>
6
+ #endif
3
7
  #include <exception>
4
8
  #include <functional>
5
9
  #include <memory>
6
10
  #include <string>
7
11
 
12
+ #include "AHardwareBufferUtils.h"
8
13
  #include "JniPlatformContext.h"
9
14
  #include "RNSkPlatformContext.h"
10
15
  #include "SkiaOpenGLSurfaceFactory.h"
@@ -48,6 +53,76 @@ public:
48
53
  return SkiaOpenGLSurfaceFactory::makeOffscreenSurface(width, height);
49
54
  }
50
55
 
56
+ sk_sp<SkImage> makeImageFromPlatformBuffer(void *buffer) override {
57
+ return SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(buffer);
58
+ }
59
+
60
+ void releasePlatformBuffer(uint64_t pointer) override {
61
+ #if __ANDROID_API__ >= 26
62
+ AHardwareBuffer *buffer = reinterpret_cast<AHardwareBuffer *>(pointer);
63
+ AHardwareBuffer_release(buffer);
64
+ #endif
65
+ }
66
+
67
+ uint64_t makePlatformBuffer(sk_sp<SkImage> image) override {
68
+ #if __ANDROID_API__ >= 26
69
+ auto bytesPerPixel = image->imageInfo().bytesPerPixel();
70
+ int bytesPerRow = image->width() * bytesPerPixel;
71
+ auto buf = SkData::MakeUninitialized(image->width() * image->height() *
72
+ bytesPerPixel);
73
+ SkImageInfo info =
74
+ SkImageInfo::Make(image->width(), image->height(), image->colorType(),
75
+ image->alphaType());
76
+ image->readPixels(nullptr, info, const_cast<void *>(buf->data()),
77
+ bytesPerRow, 0, 0);
78
+ const void *pixelData = buf->data();
79
+
80
+ // Define the buffer description
81
+ AHardwareBuffer_Desc desc = {};
82
+ // TODO: use image info here
83
+ desc.width = image->width();
84
+ desc.height = image->height();
85
+ desc.layers = 1; // Single image layer
86
+ desc.format = GetBufferFormatFromSkColorType(
87
+ image->colorType()); // Assuming the image
88
+ // is in this format
89
+ desc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
90
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
91
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
92
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
93
+ desc.stride = bytesPerRow; // Stride in pixels, not in bytes
94
+
95
+ // Allocate the buffer
96
+ AHardwareBuffer *buffer = nullptr;
97
+ if (AHardwareBuffer_allocate(&desc, &buffer) != 0) {
98
+ // Handle allocation failure
99
+ return 0;
100
+ }
101
+
102
+ // Map the buffer to gain access to its memory
103
+ void *mappedBuffer = nullptr;
104
+ AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1,
105
+ nullptr, &mappedBuffer);
106
+ if (mappedBuffer == nullptr) {
107
+ // Handle mapping failure
108
+ AHardwareBuffer_release(buffer);
109
+ return 0;
110
+ }
111
+
112
+ // Copy the image data to the buffer
113
+ memcpy(mappedBuffer, pixelData, desc.height * bytesPerRow);
114
+
115
+ // Unmap the buffer
116
+ AHardwareBuffer_unlock(buffer, nullptr);
117
+
118
+ // Return the buffer pointer as a uint64_t. It's the caller's responsibility
119
+ // to manage this buffer.
120
+ return reinterpret_cast<uint64_t>(buffer);
121
+ #else
122
+ return 0;
123
+ #endif
124
+ }
125
+
51
126
  sk_sp<SkFontMgr> createFontMgr() override {
52
127
  return SkFontMgr_New_Android(nullptr);
53
128
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include "include/gpu/ganesh/SkImageGanesh.h"
9
9
  #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
10
+ #include "src/gpu/ganesh/gl/GrGLDefines.h"
10
11
 
11
12
  #pragma clang diagnostic pop
12
13
 
@@ -15,30 +16,47 @@ namespace RNSkia {
15
16
  thread_local SkiaOpenGLContext ThreadContextHolder::ThreadSkiaOpenGLContext;
16
17
 
17
18
  sk_sp<SkImage>
18
- SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(const SkImageInfo &info,
19
- void *buffer) {
19
+ SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer) {
20
20
  #if __ANDROID_API__ >= 26
21
+ // Setup OpenGL and Skia:
22
+ if (!SkiaOpenGLHelper::createSkiaDirectContextIfNecessary(
23
+ &ThreadContextHolder::ThreadSkiaOpenGLContext)) {
24
+
25
+ RNSkLogger::logToConsole(
26
+ "Could not create Skia Surface from native window / surface. "
27
+ "Failed creating Skia Direct Context");
28
+ return nullptr;
29
+ }
21
30
  const AHardwareBuffer *hardwareBuffer =
22
31
  static_cast<AHardwareBuffer *>(buffer);
23
32
  DeleteImageProc deleteImageProc = nullptr;
24
33
  UpdateImageProc updateImageProc = nullptr;
25
34
  TexImageCtx deleteImageCtx = nullptr;
35
+
36
+ AHardwareBuffer_Desc description;
37
+ AHardwareBuffer_describe(hardwareBuffer, &description);
38
+ if (description.format != AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) {
39
+ throw std::runtime_error("AHardwareBuffer has unknown format (" +
40
+ std::to_string(description.format) +
41
+ ") - cannot convert to SkImage!");
42
+ }
43
+ GrBackendFormat format =
44
+ GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
45
+
26
46
  auto backendTex = MakeGLBackendTexture(
27
47
  ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
28
- const_cast<AHardwareBuffer *>(hardwareBuffer), info.width(),
29
- info.height(), &deleteImageProc, &updateImageProc, &deleteImageCtx, false,
30
- // GR_GL_RGBA8 0x8058
31
- // GR_GL_TEXTURE_EXTERNAL 0x8D65
32
- GrBackendFormats::MakeGL(0x8058, 0x8D65), false);
48
+ const_cast<AHardwareBuffer *>(hardwareBuffer), description.width,
49
+ description.height, &deleteImageProc, &updateImageProc, &deleteImageCtx,
50
+ false, format, false);
33
51
  sk_sp<SkImage> image = SkImages::BorrowTextureFrom(
34
52
  ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
35
53
  backendTex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
36
- kPremul_SkAlphaType, nullptr);
54
+ kOpaque_SkAlphaType, nullptr);
37
55
  return image;
38
56
  #else
39
- RNSkLogger::logToConsole(
40
- "Hardware buffer in only supported on Android API level 26 and above.");
41
- return nullptr;
57
+ throw std::runtime_error(
58
+ "HardwareBuffers are only supported on Android API 26 or higher! Set "
59
+ "your minSdk to 26 (or higher) and try again.");
42
60
  #endif
43
61
  }
44
62
 
@@ -149,8 +149,7 @@ public:
149
149
  */
150
150
  static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
151
151
 
152
- static sk_sp<SkImage> makeImageFromHardwareBuffer(const SkImageInfo &info,
153
- void *buffer);
152
+ static sk_sp<SkImage> makeImageFromHardwareBuffer(void *buffer);
154
153
 
155
154
  /**
156
155
  * Creates a windowed Skia Surface holder.
@@ -17,7 +17,8 @@ import android.view.ViewGroup;
17
17
  import android.widget.ScrollView;
18
18
  import androidx.annotation.NonNull;
19
19
  import com.facebook.react.bridge.ReactContext;
20
- import com.facebook.react.uimanager.UIManagerModule;
20
+ import com.facebook.react.bridge.UIManager;
21
+ import com.facebook.react.uimanager.UIManagerHelper;
21
22
  import com.facebook.react.views.view.ReactViewGroup;
22
23
 
23
24
  import java.lang.reflect.Method;
@@ -29,7 +30,7 @@ public class ViewScreenshotService {
29
30
  private static final String TAG = "SkiaScreenshot";
30
31
 
31
32
  public static Bitmap makeViewScreenshotFromTag(ReactContext context, int tag) {
32
- UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
33
+ UIManager uiManager = UIManagerHelper.getUIManagerForReactTag(context, tag);
33
34
  View view = null;
34
35
  try {
35
36
  view = uiManager.resolveView(tag);
@@ -0,0 +1,51 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <utility>
5
+
6
+ #include <jsi/jsi.h>
7
+
8
+ #include "JsiSkImage.h"
9
+
10
+ namespace RNSkia {
11
+
12
+ namespace jsi = facebook::jsi;
13
+
14
+ /**
15
+ Implementation of the ParagraphBuilderFactory for making ParagraphBuilder JSI
16
+ object
17
+ */
18
+ class JsiPlatformBufferFactory : public JsiSkHostObject {
19
+ public:
20
+ JSI_HOST_FUNCTION(MakeFromImage) {
21
+ auto image = JsiSkImage::fromValue(runtime, arguments[0]);
22
+ image->makeNonTextureImage();
23
+
24
+ uint64_t pointer = getContext()->makePlatformBuffer(image);
25
+ jsi::HostFunctionType deleteFunc =
26
+ [=](jsi::Runtime &runtime, const jsi::Value &thisArg,
27
+ const jsi::Value *args, size_t count) -> jsi::Value {
28
+ getContext()->releasePlatformBuffer(pointer);
29
+ return jsi::Value::undefined();
30
+ };
31
+ return jsi::BigInt::fromUint64(runtime, pointer);
32
+ }
33
+
34
+ JSI_HOST_FUNCTION(Release) {
35
+
36
+ jsi::BigInt pointer = arguments[0].asBigInt(runtime);
37
+ const uintptr_t platformBufferPointer = pointer.asUint64(runtime);
38
+
39
+ getContext()->releasePlatformBuffer(platformBufferPointer);
40
+ return jsi::Value::undefined();
41
+ }
42
+
43
+ JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiPlatformBufferFactory, Release),
44
+ JSI_EXPORT_FUNC(JsiPlatformBufferFactory, MakeFromImage))
45
+
46
+ explicit JsiPlatformBufferFactory(
47
+ std::shared_ptr<RNSkPlatformContext> context)
48
+ : JsiSkHostObject(std::move(context)) {}
49
+ };
50
+
51
+ } // namespace RNSkia
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include "JsiSkHostObjects.h"
8
8
 
9
+ #include "JsiPlatformBuffer.h"
9
10
  #include "JsiSkAnimatedImage.h"
10
11
  #include "JsiSkAnimatedImageFactory.h"
11
12
  #include "JsiSkColor.h"
@@ -122,6 +123,9 @@ public:
122
123
  installReadonlyProperty(
123
124
  "ParagraphBuilder",
124
125
  std::make_shared<JsiSkParagraphBuilderFactory>(context));
126
+
127
+ installReadonlyProperty(
128
+ "PlatformBuffer", std::make_shared<JsiPlatformBufferFactory>(context));
125
129
  }
126
130
  };
127
131
  } // namespace RNSkia
@@ -177,7 +177,7 @@ public:
177
177
  if (!getObject()->readPixels(info, bfrPtr, bytesPerRow, srcX, srcY)) {
178
178
  return jsi::Value::null();
179
179
  }
180
- return std::move(dest);
180
+ return dest;
181
181
  }
182
182
 
183
183
  JSI_HOST_FUNCTION(makeNonTextureImage) {
@@ -27,6 +27,18 @@ public:
27
27
  runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
28
28
  }
29
29
 
30
+ JSI_HOST_FUNCTION(MakeImageFromPlatformBuffer) {
31
+ jsi::BigInt pointer = arguments[0].asBigInt(runtime);
32
+ const uintptr_t platformBufferPointer = pointer.asUint64(runtime);
33
+ void *rawPointer = reinterpret_cast<void *>(platformBufferPointer);
34
+ auto image = getContext()->makeImageFromPlatformBuffer(rawPointer);
35
+ if (image == nullptr) {
36
+ throw std::runtime_error("Failed to convert PlatformBuffer to SkImage!");
37
+ }
38
+ return jsi::Object::createFromHostObject(
39
+ runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
40
+ }
41
+
30
42
  JSI_HOST_FUNCTION(MakeImage) {
31
43
  auto imageInfo = JsiSkImageInfo::fromValue(runtime, arguments[0]);
32
44
  auto pixelData = JsiSkData::fromValue(runtime, arguments[1]);
@@ -47,7 +59,6 @@ public:
47
59
  [context = std::move(context), viewTag](
48
60
  jsi::Runtime &runtime,
49
61
  std::shared_ptr<RNJsi::JsiPromises::Promise> promise) -> void {
50
- // Create a stream operation - this will be run on the main thread
51
62
  context->makeViewScreenshot(
52
63
  viewTag, [&runtime, context = std::move(context),
53
64
  promise = std::move(promise)](sk_sp<SkImage> image) {
@@ -69,7 +80,9 @@ public:
69
80
 
70
81
  JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromEncoded),
71
82
  JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromViewTag),
72
- JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage), )
83
+ JSI_EXPORT_FUNC(JsiSkImageFactory,
84
+ MakeImageFromPlatformBuffer),
85
+ JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage))
73
86
 
74
87
  explicit JsiSkImageFactory(std::shared_ptr<RNSkPlatformContext> context)
75
88
  : JsiSkHostObject(std::move(context)) {}
@@ -31,6 +31,12 @@ public:
31
31
 
32
32
  EXPORT_JSI_API_TYPENAME(JsiSkSurface, Surface)
33
33
 
34
+ // TODO-API: Properties?
35
+ JSI_HOST_FUNCTION(width) { return static_cast<double>(getObject()->width()); }
36
+ JSI_HOST_FUNCTION(height) {
37
+ return static_cast<double>(getObject()->height());
38
+ }
39
+
34
40
  JSI_HOST_FUNCTION(getCanvas) {
35
41
  return jsi::Object::createFromHostObject(
36
42
  runtime,
@@ -57,7 +63,9 @@ public:
57
63
  runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
58
64
  }
59
65
 
60
- JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSurface, getCanvas),
66
+ JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSurface, width),
67
+ JSI_EXPORT_FUNC(JsiSkSurface, height),
68
+ JSI_EXPORT_FUNC(JsiSkSurface, getCanvas),
61
69
  JSI_EXPORT_FUNC(JsiSkSurface, makeImageSnapshot),
62
70
  JSI_EXPORT_FUNC(JsiSkSurface, flush),
63
71
  JSI_EXPORT_FUNC(JsiSkSurface, dispose))
@@ -5,6 +5,7 @@
5
5
  #include <mutex>
6
6
  #include <string>
7
7
  #include <unordered_map>
8
+ #include <utility>
8
9
  #include <vector>
9
10
 
10
11
  #include "JsiHostObject.h"
@@ -177,9 +178,56 @@ public:
177
178
  return jsi::Value::undefined();
178
179
  }
179
180
 
181
+ JSI_HOST_FUNCTION(makeImageSnapshotAsync) {
182
+ if (count < 1) {
183
+ _platformContext->raiseError(std::string(
184
+ "makeImageSnapshotAsync: Expected at least 1 argument, got " +
185
+ std::to_string(count) + "."));
186
+ return jsi::Value::undefined();
187
+ }
188
+
189
+ if (!arguments[0].isNumber()) {
190
+ _platformContext->raiseError(
191
+ "makeImageSnapshot: First argument must be a number");
192
+ return jsi::Value::undefined();
193
+ }
194
+
195
+ // find Skia view
196
+ int nativeId = arguments[0].asNumber();
197
+ auto info = getEnsuredViewInfo(nativeId);
198
+ auto context = _platformContext;
199
+ auto bounds =
200
+ count > 1 && !arguments[1].isUndefined() && !arguments[1].isNull()
201
+ ? JsiSkRect::fromValue(runtime, arguments[1])
202
+ : nullptr;
203
+ return RNJsi::JsiPromises::createPromiseAsJSIValue(
204
+ runtime, [context = std::move(context), info, bounds](
205
+ jsi::Runtime &runtime,
206
+ std::shared_ptr<RNJsi::JsiPromises::Promise> promise) {
207
+ context->runOnMainThread([&runtime, info = std::move(info),
208
+ promise = std::move(promise),
209
+ context = std::move(context), bounds]() {
210
+ auto image = info->view->makeImageSnapshot(
211
+ bounds == nullptr ? nullptr : bounds.get());
212
+ context->runOnJavascriptThread(
213
+ [&runtime, context = std::move(context),
214
+ promise = std::move(promise), image = std::move(image)]() {
215
+ if (image == nullptr) {
216
+ promise->reject("Failed to make snapshot from view.");
217
+ return;
218
+ }
219
+ promise->resolve(jsi::Object::createFromHostObject(
220
+ runtime, std::make_shared<JsiSkImage>(std::move(context),
221
+ std::move(image))));
222
+ });
223
+ });
224
+ });
225
+ }
226
+
180
227
  JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkJsiViewApi, setJsiProperty),
181
228
  JSI_EXPORT_FUNC(RNSkJsiViewApi, callJsiMethod),
182
229
  JSI_EXPORT_FUNC(RNSkJsiViewApi, requestRedraw),
230
+ JSI_EXPORT_FUNC(RNSkJsiViewApi, makeImageSnapshotAsync),
183
231
  JSI_EXPORT_FUNC(RNSkJsiViewApi, makeImageSnapshot))
184
232
 
185
233
  /**
@@ -133,6 +133,19 @@ public:
133
133
  */
134
134
  virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height) = 0;
135
135
 
136
+ /**
137
+ * Creates an image from a native platform buffer.
138
+ * - On iOS, this is a `CMSampleBuffer`
139
+ * - On Android, this is a `AHardwareBuffer*`
140
+ * @param buffer The native platform buffer.
141
+ * @return sk_sp<SkImage>
142
+ */
143
+ virtual sk_sp<SkImage> makeImageFromPlatformBuffer(void *buffer) = 0;
144
+
145
+ virtual void releasePlatformBuffer(uint64_t pointer) = 0;
146
+
147
+ virtual uint64_t makePlatformBuffer(sk_sp<SkImage> image) = 0;
148
+
136
149
  /**
137
150
  * Return the Platform specific font manager
138
151
  */
@@ -59,6 +59,12 @@ public:
59
59
 
60
60
  sk_sp<SkImage> takeScreenshotFromViewTag(size_t tag) override;
61
61
 
62
+ sk_sp<SkImage> makeImageFromPlatformBuffer(void *buffer) override;
63
+
64
+ uint64_t makePlatformBuffer(sk_sp<SkImage> image) override;
65
+
66
+ void releasePlatformBuffer(uint64_t pointer) override;
67
+
62
68
  virtual void performStreamOperation(
63
69
  const std::string &sourceUri,
64
70
  const std::function<void(std::unique_ptr<SkStreamAsset>)> &op) override;
@@ -1,5 +1,6 @@
1
1
  #include "RNSkiOSPlatformContext.h"
2
2
 
3
+ #import <CoreMedia/CMSampleBuffer.h>
3
4
  #import <React/RCTUtils.h>
4
5
  #include <thread>
5
6
  #include <utility>
@@ -56,6 +57,89 @@ void RNSkiOSPlatformContext::performStreamOperation(
56
57
  std::thread(loader).detach();
57
58
  }
58
59
 
60
+ void RNSkiOSPlatformContext::releasePlatformBuffer(uint64_t pointer) {
61
+ CMSampleBufferRef sampleBuffer = reinterpret_cast<CMSampleBufferRef>(pointer);
62
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
63
+ if (sampleBuffer) {
64
+ CFRelease(sampleBuffer);
65
+ }
66
+ if (pixelBuffer) {
67
+ CFRelease(pixelBuffer);
68
+ }
69
+ }
70
+
71
+ uint64_t RNSkiOSPlatformContext::makePlatformBuffer(sk_sp<SkImage> image) {
72
+ auto bytesPerPixel = image->imageInfo().bytesPerPixel();
73
+ int bytesPerRow = image->width() * bytesPerPixel;
74
+ auto buf = SkData::MakeUninitialized(image->width() * image->height() *
75
+ bytesPerPixel);
76
+ SkImageInfo info = SkImageInfo::Make(image->width(), image->height(),
77
+ image->colorType(), image->alphaType());
78
+ image->readPixels(nullptr, info, const_cast<void *>(buf->data()), bytesPerRow,
79
+ 0, 0);
80
+ auto pixelData = const_cast<void *>(buf->data());
81
+
82
+ // Create a CVPixelBuffer from the raw pixel data
83
+ CVPixelBufferRef pixelBuffer = nullptr;
84
+ // OSType pixelFormatType = MapSkColorTypeToOSType(image->colorType());
85
+
86
+ // You will need to fill in the details for creating the pixel buffer
87
+ // CVPixelBufferCreateWithBytes or CVPixelBufferCreateWithPlanarBytes
88
+ // Create the CVPixelBuffer with the image data
89
+ void *context = static_cast<void *>(
90
+ new sk_sp<SkData>(buf)); // Create a copy for the context
91
+ CVReturn r = CVPixelBufferCreateWithBytes(
92
+ nullptr, // allocator
93
+ image->width(), image->height(), kCVPixelFormatType_32BGRA,
94
+ pixelData, // pixel data
95
+ bytesPerRow, // bytes per row
96
+ [](void *releaseRefCon, const void *baseAddress) { // release callback
97
+ auto buf = static_cast<sk_sp<SkData> *>(releaseRefCon);
98
+ buf->reset(); // This effectively calls unref on the SkData object
99
+ delete buf; // Cleanup the dynamically allocated context
100
+ },
101
+ context, // release callback context
102
+ nullptr, // pixel buffer attributes
103
+ &pixelBuffer // the newly created pixel buffer
104
+ );
105
+
106
+ if (r != kCVReturnSuccess) {
107
+ return 0; // or handle error appropriately
108
+ }
109
+
110
+ // Wrap the CVPixelBuffer in a CMSampleBuffer
111
+ CMSampleBufferRef sampleBuffer = nullptr;
112
+
113
+ CMFormatDescriptionRef formatDescription = nullptr;
114
+ CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer,
115
+ &formatDescription);
116
+
117
+ // Assuming no specific timing is required, we initialize the timing info to
118
+ // zero.
119
+ CMSampleTimingInfo timingInfo = {0};
120
+ timingInfo.duration = kCMTimeInvalid; // Indicate an unknown duration.
121
+ timingInfo.presentationTimeStamp = kCMTimeZero; // Start at time zero.
122
+ timingInfo.decodeTimeStamp = kCMTimeInvalid; // No specific decode time.
123
+
124
+ // Create the sample buffer.
125
+ OSStatus status = CMSampleBufferCreateReadyWithImageBuffer(
126
+ kCFAllocatorDefault, pixelBuffer, formatDescription, &timingInfo,
127
+ &sampleBuffer);
128
+
129
+ if (status != noErr) {
130
+ if (formatDescription) {
131
+ CFRelease(formatDescription);
132
+ }
133
+ if (pixelBuffer) {
134
+ CFRelease(pixelBuffer);
135
+ }
136
+ return 0;
137
+ }
138
+
139
+ // Return sampleBuffer casted to uint64_t
140
+ return reinterpret_cast<uint64_t>(sampleBuffer);
141
+ }
142
+
59
143
  void RNSkiOSPlatformContext::raiseError(const std::exception &err) {
60
144
  RCTFatal(RCTErrorWithMessage([NSString stringWithUTF8String:err.what()]));
61
145
  }
@@ -65,6 +149,37 @@ sk_sp<SkSurface> RNSkiOSPlatformContext::makeOffscreenSurface(int width,
65
149
  return SkiaMetalSurfaceFactory::makeOffscreenSurface(width, height);
66
150
  }
67
151
 
152
+ sk_sp<SkImage>
153
+ RNSkiOSPlatformContext::makeImageFromPlatformBuffer(void *buffer) {
154
+ CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)buffer;
155
+ // DO the CPU transfer (debugging only)
156
+ // Step 1: Extract the CVPixelBufferRef from the CMSampleBufferRef
157
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
158
+
159
+ // Step 2: Lock the pixel buffer to access the raw pixel data
160
+ CVPixelBufferLockBaseAddress(pixelBuffer, 0);
161
+
162
+ // Step 3: Get information about the image
163
+ void *baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
164
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
165
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
166
+ size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
167
+
168
+ // Assuming the pixel format is 32BGRA, which is common for iOS video frames.
169
+ // You might need to adjust this based on the actual pixel format.
170
+ SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
171
+ kUnpremul_SkAlphaType);
172
+
173
+ // Step 4: Create an SkImage from the pixel buffer
174
+ sk_sp<SkData> data =
175
+ SkData::MakeWithoutCopy(baseAddress, height * bytesPerRow);
176
+ sk_sp<SkImage> image = SkImages::RasterFromData(info, data, bytesPerRow);
177
+ auto texture = SkiaMetalSurfaceFactory::makeTextureFromImage(image);
178
+ // Step 5: Unlock the pixel buffer
179
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
180
+ return texture;
181
+ }
182
+
68
183
  sk_sp<SkFontMgr> RNSkiOSPlatformContext::createFontMgr() {
69
184
  return SkFontMgr_New_CoreText(nullptr);
70
185
  }
@@ -4,6 +4,8 @@
4
4
  #pragma clang diagnostic ignored "-Wdocumentation"
5
5
 
6
6
  #import "include/core/SkCanvas.h"
7
+ #import <CoreMedia/CMSampleBuffer.h>
8
+ #import <CoreVideo/CVMetalTextureCache.h>
7
9
  #import <include/gpu/GrDirectContext.h>
8
10
 
9
11
  #pragma clang diagnostic pop
@@ -24,6 +26,8 @@ public:
24
26
  int height);
25
27
  static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
26
28
 
29
+ static sk_sp<SkImage> makeTextureFromImage(sk_sp<SkImage> image);
30
+
27
31
  private:
28
32
  static id<MTLDevice> device;
29
33
  static bool
@@ -11,7 +11,9 @@
11
11
 
12
12
  #import <include/gpu/GrBackendSurface.h>
13
13
  #import <include/gpu/GrDirectContext.h>
14
+ #import <include/gpu/ganesh/SkImageGanesh.h>
14
15
  #import <include/gpu/ganesh/SkSurfaceGanesh.h>
16
+ #import <include/gpu/ganesh/mtl/SkSurfaceMetal.h>
15
17
 
16
18
  #pragma clang diagnostic pop
17
19
 
@@ -103,3 +105,13 @@ sk_sp<SkSurface> SkiaMetalSurfaceFactory::makeOffscreenSurface(int width,
103
105
 
104
106
  return surface;
105
107
  }
108
+
109
+ sk_sp<SkImage>
110
+ SkiaMetalSurfaceFactory::makeTextureFromImage(sk_sp<SkImage> image) {
111
+ if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary(
112
+ &ThreadContextHolder::ThreadSkiaMetalContext)) {
113
+ throw std::runtime_error("Failed to create Skia Context for this Thread!");
114
+ }
115
+ return SkImages::TextureFromImage(
116
+ ThreadContextHolder::ThreadSkiaMetalContext.skContext.get(), image);
117
+ }