@shopify/react-native-skia 0.1.220 → 0.1.222
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/cpp/rnskia-android/RNSkAndroidView.h +3 -0
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +1 -0
- package/android/cpp/rnskia-android/SkiaOpenGLHelper.h +0 -1
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +46 -6
- package/android/src/main/java/com/shopify/reactnative/skia/PlatformContext.java +3 -3
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +8 -14
- package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +93 -105
- package/cpp/api/JsiSkCanvas.h +38 -1
- package/cpp/api/JsiSkImage.h +66 -1
- package/cpp/api/JsiSkImageInfo.h +19 -0
- package/cpp/utils/RNSkLog.h +3 -3
- package/cpp/utils/RNSkTypedArray.h +41 -0
- package/lib/commonjs/skia/types/Canvas.d.ts +9 -1
- package/lib/commonjs/skia/types/Canvas.js.map +1 -1
- package/lib/commonjs/skia/types/Image/Image.d.ts +13 -0
- package/lib/commonjs/skia/types/Image/Image.js.map +1 -1
- package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +14 -11
- package/lib/commonjs/skia/types/Image/ImageFactory.js +14 -11
- package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/commonjs/skia/web/Host.d.ts +2 -1
- package/lib/commonjs/skia/web/Host.js +10 -1
- package/lib/commonjs/skia/web/Host.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkCanvas.d.ts +2 -1
- package/lib/commonjs/skia/web/JsiSkCanvas.js +11 -0
- package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkFontMgrFactory.js +1 -3
- package/lib/commonjs/skia/web/JsiSkFontMgrFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkImage.d.ts +3 -1
- package/lib/commonjs/skia/web/JsiSkImage.js +22 -0
- package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkTypefaceFontProvider.d.ts +2 -2
- package/lib/commonjs/skia/web/JsiSkTypefaceFontProvider.js +0 -4
- package/lib/commonjs/skia/web/JsiSkTypefaceFontProvider.js.map +1 -1
- package/lib/module/skia/types/Canvas.d.ts +9 -1
- package/lib/module/skia/types/Canvas.js.map +1 -1
- package/lib/module/skia/types/Image/Image.d.ts +13 -0
- package/lib/module/skia/types/Image/Image.js.map +1 -1
- package/lib/module/skia/types/Image/ImageFactory.d.ts +14 -11
- package/lib/module/skia/types/Image/ImageFactory.js +14 -11
- package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/module/skia/web/Host.d.ts +2 -1
- package/lib/module/skia/web/Host.js +6 -0
- package/lib/module/skia/web/Host.js.map +1 -1
- package/lib/module/skia/web/JsiSkCanvas.d.ts +2 -1
- package/lib/module/skia/web/JsiSkCanvas.js +12 -1
- package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
- package/lib/module/skia/web/JsiSkFontMgrFactory.js +1 -3
- package/lib/module/skia/web/JsiSkFontMgrFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkImage.d.ts +3 -1
- package/lib/module/skia/web/JsiSkImage.js +25 -1
- package/lib/module/skia/web/JsiSkImage.js.map +1 -1
- package/lib/module/skia/web/JsiSkTypefaceFontProvider.d.ts +2 -2
- package/lib/module/skia/web/JsiSkTypefaceFontProvider.js +0 -4
- package/lib/module/skia/web/JsiSkTypefaceFontProvider.js.map +1 -1
- package/lib/typescript/src/skia/types/Canvas.d.ts +9 -1
- package/lib/typescript/src/skia/types/Image/Image.d.ts +13 -0
- package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +14 -11
- package/lib/typescript/src/skia/web/Host.d.ts +2 -1
- package/lib/typescript/src/skia/web/JsiSkCanvas.d.ts +2 -1
- package/lib/typescript/src/skia/web/JsiSkImage.d.ts +3 -1
- package/lib/typescript/src/skia/web/JsiSkTypefaceFontProvider.d.ts +2 -2
- package/package.json +2 -2
- package/src/skia/types/Canvas.ts +14 -1
- package/src/skia/types/Image/Image.ts +20 -0
- package/src/skia/types/Image/ImageFactory.ts +30 -25
- package/src/skia/web/Host.ts +3 -1
- package/src/skia/web/JsiSkCanvas.ts +13 -1
- package/src/skia/web/JsiSkFontMgrFactory.ts +0 -2
- package/src/skia/web/JsiSkImage.ts +36 -3
- package/src/skia/web/JsiSkTypefaceFontProvider.ts +0 -4
@@ -56,6 +56,9 @@ public:
|
|
56
56
|
void surfaceSizeChanged(int width, int height) override {
|
57
57
|
std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
|
58
58
|
->surfaceSizeChanged(width, height);
|
59
|
+
// This is only need for the first time to frame, this renderImmediate call
|
60
|
+
// will invoke updateTexImage for the previous frame
|
61
|
+
RNSkView::renderImmediate();
|
59
62
|
}
|
60
63
|
|
61
64
|
float getPixelDensity() override {
|
@@ -6,6 +6,8 @@
|
|
6
6
|
#include <jni.h>
|
7
7
|
|
8
8
|
#include <android/native_window_jni.h>
|
9
|
+
#include <android/surface_texture.h>
|
10
|
+
#include <android/surface_texture_jni.h>
|
9
11
|
#include <condition_variable>
|
10
12
|
#include <memory>
|
11
13
|
#include <thread>
|
@@ -42,12 +44,34 @@ public:
|
|
42
44
|
*/
|
43
45
|
class WindowSurfaceHolder {
|
44
46
|
public:
|
45
|
-
WindowSurfaceHolder(jobject
|
46
|
-
: _width(width), _height(height)
|
47
|
-
|
48
|
-
|
47
|
+
WindowSurfaceHolder(jobject jSurfaceTexture, int width, int height)
|
48
|
+
: _width(width), _height(height) {
|
49
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
50
|
+
_jSurfaceTexture = env->NewGlobalRef(jSurfaceTexture);
|
51
|
+
jclass surfaceClass = env->FindClass("android/view/Surface");
|
52
|
+
jmethodID surfaceConstructor = env->GetMethodID(
|
53
|
+
surfaceClass, "<init>", "(Landroid/graphics/SurfaceTexture;)V");
|
54
|
+
// Create a new Surface instance
|
55
|
+
jobject jSurface =
|
56
|
+
env->NewObject(surfaceClass, surfaceConstructor, jSurfaceTexture);
|
57
|
+
|
58
|
+
jclass surfaceTextureClass = env->GetObjectClass(_jSurfaceTexture);
|
59
|
+
_updateTexImageMethod =
|
60
|
+
env->GetMethodID(surfaceTextureClass, "updateTexImage", "()V");
|
61
|
+
|
62
|
+
// Acquire the native window from the Surface
|
63
|
+
_window = ANativeWindow_fromSurface(env, jSurface);
|
64
|
+
// Clean up local references
|
65
|
+
env->DeleteLocalRef(jSurface);
|
66
|
+
env->DeleteLocalRef(surfaceClass);
|
67
|
+
env->DeleteLocalRef(surfaceTextureClass);
|
68
|
+
}
|
49
69
|
|
50
|
-
~WindowSurfaceHolder() {
|
70
|
+
~WindowSurfaceHolder() {
|
71
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
72
|
+
env->DeleteGlobalRef(_jSurfaceTexture);
|
73
|
+
ANativeWindow_release(_window);
|
74
|
+
}
|
51
75
|
|
52
76
|
int getWidth() { return _width; }
|
53
77
|
int getHeight() { return _height; }
|
@@ -57,6 +81,20 @@ public:
|
|
57
81
|
*/
|
58
82
|
sk_sp<SkSurface> getSurface();
|
59
83
|
|
84
|
+
void updateTexImage() {
|
85
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
86
|
+
|
87
|
+
// Call updateTexImage on the SurfaceTexture object
|
88
|
+
env->CallVoidMethod(_jSurfaceTexture, _updateTexImageMethod);
|
89
|
+
|
90
|
+
// Check for exceptions
|
91
|
+
if (env->ExceptionCheck()) {
|
92
|
+
RNSkLogger::logToConsole(
|
93
|
+
"updateTexImage() failed. The exception above can safely be ignored");
|
94
|
+
env->ExceptionClear();
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
60
98
|
/**
|
61
99
|
* Resizes the surface
|
62
100
|
* @param width
|
@@ -92,9 +130,11 @@ public:
|
|
92
130
|
}
|
93
131
|
|
94
132
|
private:
|
95
|
-
ANativeWindow *_window
|
133
|
+
ANativeWindow *_window;
|
96
134
|
sk_sp<SkSurface> _skSurface = nullptr;
|
135
|
+
jobject _jSurfaceTexture = nullptr;
|
97
136
|
EGLSurface _glSurface = EGL_NO_SURFACE;
|
137
|
+
jmethodID _updateTexImageMethod = nullptr;
|
98
138
|
int _width = 0;
|
99
139
|
int _height = 0;
|
100
140
|
};
|
@@ -52,13 +52,13 @@ public class PlatformContext {
|
|
52
52
|
Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
|
53
53
|
@Override
|
54
54
|
public void doFrame(long frameTimeNanos) {
|
55
|
+
if (_drawLoopActive) {
|
56
|
+
Choreographer.getInstance().postFrameCallback(this);
|
57
|
+
}
|
55
58
|
if (_isPaused) {
|
56
59
|
return;
|
57
60
|
}
|
58
61
|
notifyDrawLoop();
|
59
|
-
if (_drawLoopActive) {
|
60
|
-
postFrameLoop();
|
61
|
-
}
|
62
62
|
}
|
63
63
|
};
|
64
64
|
Choreographer.getInstance().postFrameCallback(frameCallback);
|
@@ -4,16 +4,11 @@ import android.content.Context;
|
|
4
4
|
import android.graphics.SurfaceTexture;
|
5
5
|
import android.util.Log;
|
6
6
|
import android.view.MotionEvent;
|
7
|
-
import android.view.Surface;
|
8
7
|
import android.view.TextureView;
|
9
8
|
|
10
|
-
import com.facebook.jni.annotations.DoNotStrip;
|
11
9
|
import com.facebook.react.views.view.ReactViewGroup;
|
12
10
|
|
13
11
|
public abstract class SkiaBaseView extends ReactViewGroup implements TextureView.SurfaceTextureListener {
|
14
|
-
|
15
|
-
@DoNotStrip
|
16
|
-
private Surface mSurface;
|
17
12
|
private TextureView mTexture;
|
18
13
|
|
19
14
|
private String tag = "SkiaView";
|
@@ -30,12 +25,8 @@ public abstract class SkiaBaseView extends ReactViewGroup implements TextureView
|
|
30
25
|
}
|
31
26
|
|
32
27
|
public void destroySurface() {
|
33
|
-
|
34
|
-
|
35
|
-
surfaceDestroyed();
|
36
|
-
mSurface.release();
|
37
|
-
mSurface = null;
|
38
|
-
}
|
28
|
+
Log.i(tag, "destroySurface");
|
29
|
+
surfaceDestroyed();
|
39
30
|
}
|
40
31
|
|
41
32
|
private void createSurfaceTexture() {
|
@@ -138,8 +129,7 @@ public abstract class SkiaBaseView extends ReactViewGroup implements TextureView
|
|
138
129
|
@Override
|
139
130
|
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
140
131
|
Log.i(tag, "onSurfaceTextureAvailable " + width + "/" + height);
|
141
|
-
|
142
|
-
surfaceAvailable(mSurface, width, height);
|
132
|
+
surfaceAvailable(surface, width, height);
|
143
133
|
}
|
144
134
|
|
145
135
|
@Override
|
@@ -153,6 +143,10 @@ public abstract class SkiaBaseView extends ReactViewGroup implements TextureView
|
|
153
143
|
Log.i(tag, "onSurfaceTextureDestroyed");
|
154
144
|
// https://developer.android.com/reference/android/view/TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed(android.graphics.SurfaceTexture)
|
155
145
|
destroySurface();
|
146
|
+
// Because of React Native Screens (which dettach the view), we always keep the surface alive.
|
147
|
+
// If not, Texture view will recreate the texture surface by itself and
|
148
|
+
// we will lose the fast first time to frame.
|
149
|
+
// We only delete the surface when the view is dropped (destroySurface invoked by SkiaBaseViewManager);
|
156
150
|
createSurfaceTexture();
|
157
151
|
return false;
|
158
152
|
}
|
@@ -181,4 +175,4 @@ public abstract class SkiaBaseView extends ReactViewGroup implements TextureView
|
|
181
175
|
protected abstract void registerView(int nativeId);
|
182
176
|
|
183
177
|
protected abstract void unregisterView();
|
184
|
-
}
|
178
|
+
}
|
@@ -1,11 +1,10 @@
|
|
1
1
|
package com.shopify.reactnative.skia;
|
2
2
|
|
3
|
-
import static android.view.View.VISIBLE;
|
4
|
-
|
5
3
|
import android.graphics.Bitmap;
|
6
4
|
import android.graphics.Canvas;
|
7
5
|
import android.graphics.Matrix;
|
8
6
|
import android.graphics.Paint;
|
7
|
+
import android.graphics.drawable.Drawable;
|
9
8
|
import android.os.Build;
|
10
9
|
import android.os.Handler;
|
11
10
|
import android.os.Looper;
|
@@ -15,14 +14,12 @@ import android.view.SurfaceView;
|
|
15
14
|
import android.view.TextureView;
|
16
15
|
import android.view.View;
|
17
16
|
import android.view.ViewGroup;
|
18
|
-
|
19
17
|
import androidx.annotation.NonNull;
|
20
|
-
|
21
18
|
import com.facebook.react.bridge.ReactContext;
|
22
19
|
import com.facebook.react.uimanager.UIManagerModule;
|
20
|
+
import com.facebook.react.views.view.ReactViewGroup;
|
23
21
|
|
24
|
-
import java.
|
25
|
-
import java.util.List;
|
22
|
+
import java.lang.reflect.Method;
|
26
23
|
import java.util.concurrent.CountDownLatch;
|
27
24
|
import java.util.concurrent.TimeUnit;
|
28
25
|
|
@@ -42,143 +39,134 @@ public class ViewScreenshotService {
|
|
42
39
|
return null;
|
43
40
|
}
|
44
41
|
|
45
|
-
// Measure and get size of view
|
46
42
|
int width = view.getWidth();
|
47
43
|
int height = view.getHeight();
|
48
|
-
|
49
44
|
if (width <= 0 || height <= 0) {
|
50
45
|
return null;
|
51
46
|
}
|
52
47
|
|
53
|
-
// The following code is taken from react-native-view-shot to be able to handle and
|
54
|
-
// correctly render all kinds of views, also including TextureViews and SurfaceViews
|
55
48
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
49
|
+
final Canvas canvas = new Canvas(bitmap);
|
50
|
+
final Paint paint = createPaint();
|
51
|
+
|
52
|
+
canvas.save();
|
53
|
+
canvas.translate(-view.getLeft(), -view.getTop());
|
54
|
+
renderViewToCanvas(canvas, view, paint, 1.0f); // Initial opacity
|
55
|
+
canvas.restore();
|
56
|
+
|
57
|
+
return bitmap;
|
58
|
+
}
|
56
59
|
|
60
|
+
private static Paint createPaint() {
|
57
61
|
final Paint paint = new Paint();
|
58
62
|
paint.setAntiAlias(true);
|
59
63
|
paint.setFilterBitmap(true);
|
60
64
|
paint.setDither(true);
|
61
|
-
|
62
|
-
// Render the main view and its children
|
63
|
-
final Canvas canvas = new Canvas(bitmap);
|
64
|
-
|
65
|
-
// Renders view with child views to canvas
|
66
|
-
renderViewToCanvas(canvas, view, paint);
|
67
|
-
|
68
|
-
return bitmap;
|
65
|
+
return paint;
|
69
66
|
}
|
70
67
|
|
71
|
-
private static void renderViewToCanvas(Canvas canvas, View view, Paint paint) {
|
72
|
-
|
68
|
+
private static void renderViewToCanvas(Canvas canvas, View view, Paint paint, float parentOpacity) {
|
69
|
+
float combinedOpacity = parentOpacity * view.getAlpha();
|
73
70
|
canvas.save();
|
74
71
|
applyTransformations(canvas, view);
|
75
72
|
|
76
|
-
|
77
|
-
if ((view instanceof ViewGroup)) {
|
78
|
-
// Draw children
|
73
|
+
if (view instanceof ViewGroup) {
|
79
74
|
ViewGroup group = (ViewGroup) view;
|
75
|
+
drawBackgroundIfPresent(canvas, view, combinedOpacity);
|
76
|
+
drawChildren(canvas, group, paint, combinedOpacity);
|
77
|
+
} else {
|
78
|
+
drawView(canvas, view, paint, combinedOpacity);
|
79
|
+
}
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
// views to be rendered twice - once by view.draw() and once when we
|
84
|
-
// enumerate children. We therefore need to turn off rendering of visible
|
85
|
-
// children before we call view.draw:
|
86
|
-
List<View> visibleChildren = new ArrayList<>();
|
87
|
-
for (int i = 0; i < group.getChildCount(); i++) {
|
88
|
-
View child = group.getChildAt(i);
|
89
|
-
if (child.getVisibility() == VISIBLE) {
|
90
|
-
visibleChildren.add(child);
|
91
|
-
child.setVisibility(View.INVISIBLE);
|
92
|
-
}
|
93
|
-
}
|
81
|
+
canvas.restore();
|
82
|
+
}
|
94
83
|
|
95
|
-
|
96
|
-
|
97
|
-
|
84
|
+
private static void drawBackgroundIfPresent(Canvas canvas, View view, float opacity) {
|
85
|
+
Drawable bg = view.getBackground();
|
86
|
+
if (bg != null) {
|
87
|
+
canvas.saveLayerAlpha(null, Math.round(opacity * 255));
|
88
|
+
bg.draw(canvas);
|
98
89
|
canvas.restore();
|
90
|
+
}
|
91
|
+
}
|
99
92
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
93
|
+
private static void drawChildren(Canvas canvas, ViewGroup group, Paint paint, float parentOpacity) {
|
94
|
+
// Handle clipping for ReactViewGroup
|
95
|
+
if (group instanceof ReactViewGroup) {
|
96
|
+
try {
|
97
|
+
Class[] cArg = new Class[1];
|
98
|
+
cArg[0] = Canvas.class;
|
99
|
+
Method method = ReactViewGroup.class.getDeclaredMethod("dispatchOverflowDraw", cArg);
|
100
|
+
method.setAccessible(true);
|
101
|
+
method.invoke(group, canvas);
|
102
|
+
} catch (Exception e) {
|
103
|
+
Log.e(TAG, "couldn't invoke dispatchOverflowDraw() on ReactViewGroup", e);
|
104
104
|
}
|
105
|
+
}
|
106
|
+
for (int i = 0; i < group.getChildCount(); i++) {
|
107
|
+
View child = group.getChildAt(i);
|
108
|
+
if (child.getVisibility() != View.VISIBLE) continue;
|
109
|
+
|
110
|
+
if (child instanceof TextureView) {
|
111
|
+
drawTextureView(canvas, (TextureView) child, paint, parentOpacity);
|
112
|
+
} else if (child instanceof SurfaceView) {
|
113
|
+
drawSurfaceView(canvas, (SurfaceView) child, paint, parentOpacity);
|
114
|
+
} else {
|
115
|
+
renderViewToCanvas(canvas, child, paint, parentOpacity);
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
105
119
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
if (child.getVisibility() != VISIBLE) continue;
|
120
|
+
private static void drawView(Canvas canvas, View view, Paint paint, float opacity) {
|
121
|
+
canvas.saveLayerAlpha(null, Math.round(opacity * 255));
|
122
|
+
view.draw(canvas);
|
123
|
+
canvas.restore();
|
124
|
+
}
|
112
125
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
126
|
+
private static void drawTextureView(Canvas canvas, TextureView tv, Paint paint, float opacity) {
|
127
|
+
tv.setOpaque(false);
|
128
|
+
Bitmap childBitmapBuffer = tv.getBitmap(Bitmap.createBitmap(tv.getWidth(), tv.getHeight(), Bitmap.Config.ARGB_8888));
|
129
|
+
canvas.save();
|
130
|
+
applyTransformations(canvas, tv);
|
131
|
+
paint.setAlpha(Math.round(opacity * 255)); // Set paint alpha based on opacity
|
132
|
+
canvas.drawBitmap(childBitmapBuffer, 0, 0, paint);
|
133
|
+
canvas.restore();
|
134
|
+
}
|
117
135
|
|
136
|
+
private static void drawSurfaceView(Canvas canvas, SurfaceView sv, Paint paint, float opacity) {
|
137
|
+
final CountDownLatch latch = new CountDownLatch(1);
|
138
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
139
|
+
Bitmap childBitmapBuffer = Bitmap.createBitmap(sv.getWidth(), sv.getHeight(), Bitmap.Config.ARGB_8888);
|
140
|
+
try {
|
141
|
+
PixelCopy.request(sv, childBitmapBuffer, copyResult -> {
|
118
142
|
canvas.save();
|
119
|
-
applyTransformations(canvas,
|
120
|
-
|
121
|
-
// TextureView should use bitmaps with matching size,
|
122
|
-
// otherwise content of the TextureView will be scaled to provided bitmap dimensions
|
123
|
-
final Bitmap childBitmapBuffer = tvChild.getBitmap(Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888));
|
143
|
+
applyTransformations(canvas, sv);
|
144
|
+
paint.setAlpha(Math.round(opacity * 255)); // Set paint alpha based on opacity
|
124
145
|
canvas.drawBitmap(childBitmapBuffer, 0, 0, paint);
|
125
|
-
|
126
146
|
canvas.restore();
|
127
|
-
|
128
|
-
}
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
133
|
-
final Bitmap childBitmapBuffer = Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888);
|
134
|
-
try {
|
135
|
-
PixelCopy.request(svChild, childBitmapBuffer, copyResult -> {
|
136
|
-
canvas.save();
|
137
|
-
applyTransformations(canvas, child);
|
138
|
-
canvas.drawBitmap(childBitmapBuffer, 0, 0, paint);
|
139
|
-
canvas.restore();
|
140
|
-
latch.countDown();
|
141
|
-
}, new Handler(Looper.getMainLooper()));
|
142
|
-
latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS);
|
143
|
-
} catch (Exception e) {
|
144
|
-
Log.e(TAG, "Cannot PixelCopy for " + svChild, e);
|
145
|
-
}
|
146
|
-
} else {
|
147
|
-
Bitmap cache = svChild.getDrawingCache();
|
148
|
-
if (cache != null) {
|
149
|
-
canvas.save();
|
150
|
-
applyTransformations(canvas, child);
|
151
|
-
canvas.drawBitmap(svChild.getDrawingCache(), 0, 0, paint);
|
152
|
-
canvas.restore();
|
153
|
-
}
|
154
|
-
}
|
155
|
-
} else {
|
156
|
-
// Regular views needs to be rendered again to ensure correct z-index
|
157
|
-
// order with texture views and surface views.
|
158
|
-
renderViewToCanvas(canvas, child, paint);
|
159
|
-
}
|
147
|
+
latch.countDown();
|
148
|
+
}, new Handler(Looper.getMainLooper()));
|
149
|
+
latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS);
|
150
|
+
} catch (Exception e) {
|
151
|
+
Log.e(TAG, "Cannot PixelCopy for " + sv, e);
|
160
152
|
}
|
161
153
|
} else {
|
162
|
-
|
163
|
-
|
154
|
+
Bitmap cache = sv.getDrawingCache();
|
155
|
+
if (cache != null) {
|
156
|
+
canvas.save();
|
157
|
+
applyTransformations(canvas, sv);
|
158
|
+
paint.setAlpha(Math.round(opacity * 255)); // Set paint alpha based on opacity
|
159
|
+
canvas.drawBitmap(cache, 0, 0, paint);
|
160
|
+
canvas.restore();
|
161
|
+
}
|
164
162
|
}
|
165
|
-
|
166
|
-
// Restore canvas
|
167
|
-
canvas.restore();
|
168
163
|
}
|
169
164
|
|
170
165
|
@NonNull
|
171
166
|
private static void applyTransformations(final Canvas c, @NonNull final View view) {
|
172
|
-
// Get the transformation matrix of the view
|
173
167
|
final Matrix matrix = view.getMatrix();
|
174
|
-
|
175
|
-
// Create a new matrix for translation
|
176
168
|
final Matrix translateMatrix = new Matrix();
|
177
|
-
|
178
|
-
final float dy = view.getTop() + view.getPaddingTop();
|
179
|
-
translateMatrix.setTranslate(dx, dy);
|
180
|
-
|
181
|
-
// Pre-concatenate the current matrix of the canvas with the translation and transformation matrices of the view
|
169
|
+
translateMatrix.setTranslate(view.getLeft() + view.getPaddingLeft(), view.getTop() + view.getPaddingTop());
|
182
170
|
c.concat(translateMatrix);
|
183
171
|
c.concat(matrix);
|
184
172
|
}
|
package/cpp/api/JsiSkCanvas.h
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
#include "JsiSkFont.h"
|
8
8
|
#include "JsiSkHostObjects.h"
|
9
9
|
#include "JsiSkImage.h"
|
10
|
+
#include "JsiSkImageInfo.h"
|
10
11
|
#include "JsiSkMatrix.h"
|
11
12
|
#include "JsiSkPaint.h"
|
12
13
|
#include "JsiSkPath.h"
|
@@ -17,6 +18,8 @@
|
|
17
18
|
#include "JsiSkTextBlob.h"
|
18
19
|
#include "JsiSkVertices.h"
|
19
20
|
|
21
|
+
#include "RNSkTypedArray.h"
|
22
|
+
|
20
23
|
#include <jsi/jsi.h>
|
21
24
|
|
22
25
|
#pragma clang diagnostic push
|
@@ -491,6 +494,39 @@ public:
|
|
491
494
|
return jsi::Value::undefined();
|
492
495
|
}
|
493
496
|
|
497
|
+
JSI_HOST_FUNCTION(readPixels) {
|
498
|
+
auto srcX = static_cast<int>(arguments[0].asNumber());
|
499
|
+
auto srcY = static_cast<int>(arguments[1].asNumber());
|
500
|
+
auto info = JsiSkImageInfo::fromValue(runtime, arguments[2]);
|
501
|
+
if (!info) {
|
502
|
+
return jsi::Value::null();
|
503
|
+
}
|
504
|
+
size_t bytesPerRow = 0;
|
505
|
+
if (count > 4 && !arguments[4].isUndefined()) {
|
506
|
+
bytesPerRow = static_cast<size_t>(arguments[4].asNumber());
|
507
|
+
} else {
|
508
|
+
bytesPerRow = info->minRowBytes();
|
509
|
+
}
|
510
|
+
auto dest =
|
511
|
+
count > 3
|
512
|
+
? RNSkTypedArray::getTypedArray(runtime, arguments[3], *info)
|
513
|
+
: RNSkTypedArray::getTypedArray(runtime, jsi::Value::null(), *info);
|
514
|
+
if (!dest.isObject()) {
|
515
|
+
return jsi::Value::null();
|
516
|
+
}
|
517
|
+
jsi::ArrayBuffer buffer =
|
518
|
+
dest.asObject(runtime)
|
519
|
+
.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
|
520
|
+
.asObject(runtime)
|
521
|
+
.getArrayBuffer(runtime);
|
522
|
+
auto bfrPtr = reinterpret_cast<void *>(buffer.data(runtime));
|
523
|
+
|
524
|
+
if (!_canvas->readPixels(*info, bfrPtr, bytesPerRow, srcX, srcY)) {
|
525
|
+
return jsi::Value::null();
|
526
|
+
}
|
527
|
+
return std::move(dest);
|
528
|
+
}
|
529
|
+
|
494
530
|
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkCanvas, drawPaint),
|
495
531
|
JSI_EXPORT_FUNC(JsiSkCanvas, drawLine),
|
496
532
|
JSI_EXPORT_FUNC(JsiSkCanvas, drawRect),
|
@@ -529,7 +565,8 @@ public:
|
|
529
565
|
JSI_EXPORT_FUNC(JsiSkCanvas, drawColor),
|
530
566
|
JSI_EXPORT_FUNC(JsiSkCanvas, clear),
|
531
567
|
JSI_EXPORT_FUNC(JsiSkCanvas, concat),
|
532
|
-
JSI_EXPORT_FUNC(JsiSkCanvas, drawPicture)
|
568
|
+
JSI_EXPORT_FUNC(JsiSkCanvas, drawPicture),
|
569
|
+
JSI_EXPORT_FUNC(JsiSkCanvas, readPixels))
|
533
570
|
|
534
571
|
explicit JsiSkCanvas(std::shared_ptr<RNSkPlatformContext> context)
|
535
572
|
: JsiSkHostObject(std::move(context)) {}
|
package/cpp/api/JsiSkImage.h
CHANGED
@@ -5,9 +5,12 @@
|
|
5
5
|
#include <utility>
|
6
6
|
|
7
7
|
#include "JsiSkHostObjects.h"
|
8
|
+
#include "JsiSkImageInfo.h"
|
8
9
|
#include "JsiSkMatrix.h"
|
9
10
|
#include "JsiSkShader.h"
|
10
11
|
|
12
|
+
#include "RNSkTypedArray.h"
|
13
|
+
|
11
14
|
#pragma clang diagnostic push
|
12
15
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
13
16
|
|
@@ -17,6 +20,7 @@
|
|
17
20
|
#include "include/codec/SkEncodedImageFormat.h"
|
18
21
|
#include "include/encode/SkJpegEncoder.h"
|
19
22
|
#include "include/encode/SkPngEncoder.h"
|
23
|
+
#include "include/encode/SkWebpEncoder.h"
|
20
24
|
|
21
25
|
#pragma clang diagnostic pop
|
22
26
|
|
@@ -34,6 +38,11 @@ public:
|
|
34
38
|
return static_cast<double>(getObject()->height());
|
35
39
|
}
|
36
40
|
|
41
|
+
JSI_HOST_FUNCTION(getImageInfo) {
|
42
|
+
return JsiSkImageInfo::toValue(runtime, getContext(),
|
43
|
+
getObject()->imageInfo());
|
44
|
+
}
|
45
|
+
|
37
46
|
JSI_HOST_FUNCTION(makeShaderOptions) {
|
38
47
|
auto tmx = (SkTileMode)arguments[0].asNumber();
|
39
48
|
auto tmy = (SkTileMode)arguments[1].asNumber();
|
@@ -70,20 +79,34 @@ public:
|
|
70
79
|
count >= 1 ? static_cast<SkEncodedImageFormat>(arguments[0].asNumber())
|
71
80
|
: SkEncodedImageFormat::kPNG;
|
72
81
|
|
73
|
-
auto quality = count
|
82
|
+
auto quality = (count >= 2 && arguments[1].isNumber())
|
83
|
+
? arguments[1].asNumber()
|
84
|
+
: 100.0;
|
74
85
|
auto image = getObject();
|
75
86
|
if (image->isTextureBacked()) {
|
76
87
|
image = image->makeNonTextureImage();
|
77
88
|
}
|
78
89
|
sk_sp<SkData> data;
|
90
|
+
|
79
91
|
if (format == SkEncodedImageFormat::kJPEG) {
|
80
92
|
SkJpegEncoder::Options options;
|
81
93
|
options.fQuality = quality;
|
82
94
|
data = SkJpegEncoder::Encode(nullptr, image.get(), options);
|
95
|
+
} else if (format == SkEncodedImageFormat::kWEBP) {
|
96
|
+
SkWebpEncoder::Options options;
|
97
|
+
if (quality >= 100) {
|
98
|
+
options.fCompression = SkWebpEncoder::Compression::kLossless;
|
99
|
+
options.fQuality = 75; // This is effort to compress
|
100
|
+
} else {
|
101
|
+
options.fCompression = SkWebpEncoder::Compression::kLossy;
|
102
|
+
options.fQuality = quality;
|
103
|
+
}
|
104
|
+
data = SkWebpEncoder::Encode(nullptr, image.get(), options);
|
83
105
|
} else {
|
84
106
|
SkPngEncoder::Options options;
|
85
107
|
data = SkPngEncoder::Encode(nullptr, image.get(), options);
|
86
108
|
}
|
109
|
+
|
87
110
|
return data;
|
88
111
|
}
|
89
112
|
|
@@ -117,6 +140,46 @@ public:
|
|
117
140
|
return jsi::String::createFromAscii(runtime, buffer);
|
118
141
|
}
|
119
142
|
|
143
|
+
JSI_HOST_FUNCTION(readPixels) {
|
144
|
+
int srcX = 0;
|
145
|
+
int srcY = 0;
|
146
|
+
if (count > 0 && !arguments[0].isUndefined()) {
|
147
|
+
srcX = static_cast<int>(arguments[0].asNumber());
|
148
|
+
}
|
149
|
+
if (count > 1 && !arguments[1].isUndefined()) {
|
150
|
+
srcY = static_cast<int>(arguments[1].asNumber());
|
151
|
+
}
|
152
|
+
SkImageInfo info =
|
153
|
+
(count > 2 && !arguments[2].isUndefined())
|
154
|
+
? *JsiSkImageInfo::fromValue(runtime, arguments[2])
|
155
|
+
: SkImageInfo::MakeN32(getObject()->width(), getObject()->height(),
|
156
|
+
getObject()->imageInfo().alphaType());
|
157
|
+
size_t bytesPerRow = 0;
|
158
|
+
if (count > 4 && !arguments[4].isUndefined()) {
|
159
|
+
bytesPerRow = static_cast<size_t>(arguments[4].asNumber());
|
160
|
+
} else {
|
161
|
+
bytesPerRow = info.minRowBytes();
|
162
|
+
}
|
163
|
+
auto dest =
|
164
|
+
count > 3
|
165
|
+
? RNSkTypedArray::getTypedArray(runtime, arguments[3], info)
|
166
|
+
: RNSkTypedArray::getTypedArray(runtime, jsi::Value::null(), info);
|
167
|
+
if (!dest.isObject()) {
|
168
|
+
return jsi::Value::null();
|
169
|
+
}
|
170
|
+
jsi::ArrayBuffer buffer =
|
171
|
+
dest.asObject(runtime)
|
172
|
+
.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
|
173
|
+
.asObject(runtime)
|
174
|
+
.getArrayBuffer(runtime);
|
175
|
+
auto bfrPtr = reinterpret_cast<void *>(buffer.data(runtime));
|
176
|
+
|
177
|
+
if (!getObject()->readPixels(info, bfrPtr, bytesPerRow, srcX, srcY)) {
|
178
|
+
return jsi::Value::null();
|
179
|
+
}
|
180
|
+
return std::move(dest);
|
181
|
+
}
|
182
|
+
|
120
183
|
JSI_HOST_FUNCTION(makeNonTextureImage) {
|
121
184
|
auto image = getObject()->makeNonTextureImage();
|
122
185
|
return jsi::Object::createFromHostObject(
|
@@ -127,10 +190,12 @@ public:
|
|
127
190
|
|
128
191
|
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImage, width),
|
129
192
|
JSI_EXPORT_FUNC(JsiSkImage, height),
|
193
|
+
JSI_EXPORT_FUNC(JsiSkImage, getImageInfo),
|
130
194
|
JSI_EXPORT_FUNC(JsiSkImage, makeShaderOptions),
|
131
195
|
JSI_EXPORT_FUNC(JsiSkImage, makeShaderCubic),
|
132
196
|
JSI_EXPORT_FUNC(JsiSkImage, encodeToBytes),
|
133
197
|
JSI_EXPORT_FUNC(JsiSkImage, encodeToBase64),
|
198
|
+
JSI_EXPORT_FUNC(JsiSkImage, readPixels),
|
134
199
|
JSI_EXPORT_FUNC(JsiSkImage, makeNonTextureImage),
|
135
200
|
JSI_EXPORT_FUNC(JsiSkImage, dispose))
|
136
201
|
|
package/cpp/api/JsiSkImageInfo.h
CHANGED
@@ -56,5 +56,24 @@ public:
|
|
56
56
|
runtime,
|
57
57
|
std::make_shared<JsiSkImageInfo>(std::move(context), imageInfo));
|
58
58
|
}
|
59
|
+
|
60
|
+
JSI_PROPERTY_GET(width) { return static_cast<double>(getObject()->width()); }
|
61
|
+
JSI_PROPERTY_GET(height) {
|
62
|
+
return static_cast<double>(getObject()->height());
|
63
|
+
}
|
64
|
+
JSI_PROPERTY_GET(colorType) {
|
65
|
+
return static_cast<double>(getObject()->colorType());
|
66
|
+
}
|
67
|
+
JSI_PROPERTY_GET(alphaType) {
|
68
|
+
return static_cast<double>(getObject()->alphaType());
|
69
|
+
}
|
70
|
+
|
71
|
+
JSI_API_TYPENAME(ImageInfo);
|
72
|
+
|
73
|
+
JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkImageInfo, width),
|
74
|
+
JSI_EXPORT_PROP_GET(JsiSkImageInfo, height),
|
75
|
+
JSI_EXPORT_PROP_GET(JsiSkImageInfo, colorType),
|
76
|
+
JSI_EXPORT_PROP_GET(JsiSkImageInfo, alphaType),
|
77
|
+
JSI_EXPORT_PROP_GET(JsiSkImageInfo, __typename__))
|
59
78
|
};
|
60
79
|
} // namespace RNSkia
|