@shopify/react-native-skia 0.1.220 → 0.1.222
Sign up to get free protection for your applications and to get access to all the features.
- 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
|