[androidkit] Introduce Image support
Two sources from now:
- encoded data factory
- Surface.makeImageSnapshot()
Change-Id: Icbf2f855e489839dc82db425916c8644418a2fb7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410324
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 390e616..45bc668 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2495,6 +2495,7 @@
sources = [
"modules/androidkit/src/AndroidKit.cpp",
"modules/androidkit/src/Canvas.cpp",
+ "modules/androidkit/src/Image.cpp",
"modules/androidkit/src/Matrix.cpp",
"modules/androidkit/src/Paint.cpp",
"modules/androidkit/src/RuntimeShaderBuilder.cpp",
diff --git a/modules/androidkit/src/AndroidKit.cpp b/modules/androidkit/src/AndroidKit.cpp
index c967650..cf02523 100644
--- a/modules/androidkit/src/AndroidKit.cpp
+++ b/modules/androidkit/src/AndroidKit.cpp
@@ -24,6 +24,7 @@
}
REGISTER_NATIVES(Canvas)
+ REGISTER_NATIVES(Image)
REGISTER_NATIVES(Matrix)
REGISTER_NATIVES(Paint)
REGISTER_NATIVES(RuntimeShaderBuilder)
diff --git a/modules/androidkit/src/Canvas.cpp b/modules/androidkit/src/Canvas.cpp
index 038437e..3a37f0a 100644
--- a/modules/androidkit/src/Canvas.cpp
+++ b/modules/androidkit/src/Canvas.cpp
@@ -79,6 +79,16 @@
}
}
+void Canvas_DrawImage(JNIEnv* env, jobject, jlong native_instance, jlong native_image,
+ jfloat x, jfloat y) {
+ auto* canvas = reinterpret_cast<SkCanvas*>(native_instance);
+ auto* image = reinterpret_cast<SkImage *>(native_image);
+
+ if (canvas && image) {
+ canvas->drawImage(image, x, y);
+ }
+}
+
} // namespace
int register_androidkit_Canvas(JNIEnv* env) {
@@ -92,6 +102,7 @@
{"nConcat16f" , "(J[F)V" , reinterpret_cast<void*>(Canvas_Concat16f) },
{"nDrawColor" , "(JFFFF)V" , reinterpret_cast<void*>(Canvas_DrawColor) },
{"nDrawRect" , "(JFFFFJ)V", reinterpret_cast<void*>(Canvas_DrawRect) },
+ {"nDrawImage" , "(JJFF)V" , reinterpret_cast<void*>(Canvas_DrawImage) },
};
const auto clazz = env->FindClass("org/skia/androidkit/Canvas");
diff --git a/modules/androidkit/src/Image.cpp b/modules/androidkit/src/Image.cpp
new file mode 100644
index 0000000..435d085
--- /dev/null
+++ b/modules/androidkit/src/Image.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <jni.h>
+
+#include "include/core/SkImage.h"
+
+namespace {
+
+jlong Image_Create(JNIEnv* env, jobject, jbyteArray jdata) {
+ auto size = env->GetArrayLength(jdata);
+ auto* data = env->GetByteArrayElements(jdata, nullptr);
+ auto image = SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, SkToSizeT(size)));
+
+ env->ReleaseByteArrayElements(jdata, data, 0);
+
+ return reinterpret_cast<jlong>(image.release());
+}
+
+void Image_Release(JNIEnv*, jobject, jlong native_instance) {
+ SkSafeUnref(reinterpret_cast<const SkImage*>(native_instance));
+}
+
+jint Image_GetWidth(JNIEnv*, jobject, jlong native_instance) {
+ const auto* image = reinterpret_cast<const SkImage*>(native_instance);
+ return image ? image->width() : 0;
+}
+
+jint Image_GetHeight(JNIEnv*, jobject, jlong native_instance) {
+ const auto* image = reinterpret_cast<const SkImage*>(native_instance);
+ return image ? image->height() : 0;
+}
+
+} // namespace
+
+int register_androidkit_Image(JNIEnv* env) {
+ static const JNINativeMethod methods[] = {
+ {"nCreate" , "([B)J", reinterpret_cast<void*>(Image_Create) },
+ {"nRelease" , "(J)V" , reinterpret_cast<void*>(Image_Release) },
+
+ {"nGetWidth" , "(J)I" , reinterpret_cast<void*>(Image_GetWidth) },
+ {"nGetHeight", "(J)I" , reinterpret_cast<void*>(Image_GetHeight)},
+ };
+
+ const auto clazz = env->FindClass("org/skia/androidkit/Image");
+ return clazz
+ ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
+ : JNI_ERR;
+}
diff --git a/modules/androidkit/src/Surface.cpp b/modules/androidkit/src/Surface.cpp
index b24891a..8732f9f 100644
--- a/modules/androidkit/src/Surface.cpp
+++ b/modules/androidkit/src/Surface.cpp
@@ -225,35 +225,45 @@
}
}
-static int Surface_GetWidth(JNIEnv* env, jobject, jlong native_surface) {
+static jint Surface_GetWidth(JNIEnv* env, jobject, jlong native_surface) {
const auto* surface = reinterpret_cast<Surface*>(native_surface);
return surface ? surface->width() : 0;
}
-static int Surface_GetHeight(JNIEnv* env, jobject, jlong native_surface) {
+static jint Surface_GetHeight(JNIEnv* env, jobject, jlong native_surface) {
const auto* surface = reinterpret_cast<Surface*>(native_surface);
return surface ? surface->height() : 0;
}
+static jlong Surface_MakeSnapshot(JNIEnv* env, jobject, jlong native_surface) {
+ if (const auto* surface = reinterpret_cast<Surface*>(native_surface)) {
+ auto snapshot = surface->makeImageSnapshot();
+ return reinterpret_cast<jlong>(snapshot.release());
+ }
+
+ return 0;
+}
+
// *** End of JNI methods ***
} // namespace
int register_androidkit_Surface(JNIEnv* env) {
static const JNINativeMethod methods[] = {
- {"nCreateBitmap" , "(Landroid/graphics/Bitmap;)J",
- reinterpret_cast<void*>(Surface_CreateBitmap) },
+ {"nCreateBitmap" , "(Landroid/graphics/Bitmap;)J",
+ reinterpret_cast<void*>(Surface_CreateBitmap) },
{"nCreateThreadedSurface" , "(Landroid/view/Surface;)J",
- reinterpret_cast<void*>(Surface_CreateThreadedSurface) },
- {"nCreateVKSurface", "(Landroid/view/Surface;)J",
- reinterpret_cast<void*>(Surface_CreateVK) },
- {"nCreateGLSurface", "(Landroid/view/Surface;)J",
- reinterpret_cast<void*>(Surface_CreateGL) },
- {"nRelease" , "(J)V", reinterpret_cast<void*>(Surface_Release) },
- {"nGetNativeCanvas", "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
- {"nFlushAndSubmit" , "(J)V", reinterpret_cast<void*>(Surface_FlushAndSubmit) },
- {"nGetWidth" , "(J)I", reinterpret_cast<void*>(Surface_GetWidth) },
- {"nGetHeight" , "(J)I", reinterpret_cast<void*>(Surface_GetHeight) },
+ reinterpret_cast<void*>(Surface_CreateThreadedSurface) },
+ {"nCreateVKSurface" , "(Landroid/view/Surface;)J",
+ reinterpret_cast<void*>(Surface_CreateVK) },
+ {"nCreateGLSurface" , "(Landroid/view/Surface;)J",
+ reinterpret_cast<void*>(Surface_CreateGL) },
+ {"nRelease" , "(J)V", reinterpret_cast<void*>(Surface_Release) },
+ {"nGetNativeCanvas" , "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
+ {"nFlushAndSubmit" , "(J)V", reinterpret_cast<void*>(Surface_FlushAndSubmit) },
+ {"nGetWidth" , "(J)I", reinterpret_cast<void*>(Surface_GetWidth) },
+ {"nGetHeight" , "(J)I", reinterpret_cast<void*>(Surface_GetHeight) },
+ {"nMakeImageSnapshot", "(J)J", reinterpret_cast<void*>(Surface_MakeSnapshot) },
};
const auto clazz = env->FindClass("org/skia/androidkit/Surface");
diff --git a/modules/androidkit/src/Surface.h b/modules/androidkit/src/Surface.h
index 7162087..6da122a 100644
--- a/modules/androidkit/src/Surface.h
+++ b/modules/androidkit/src/Surface.h
@@ -17,6 +17,7 @@
#include "tools/sk_app/WindowContext.h"
+#include "include/core/SkImage.h"
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurface.h"
@@ -34,6 +35,10 @@
int width() const { return fSurface ? fSurface->width() : 0; }
int height() const { return fSurface ? fSurface->height() : 0; }
+ sk_sp<SkImage> makeImageSnapshot() const {
+ return fSurface ? fSurface->makeImageSnapshot() : nullptr;
+ }
+
protected:
sk_sp<SkSurface> fSurface;
};
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
index f804126..e427e43 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
@@ -8,6 +8,7 @@
package org.skia.androidkit;
import org.skia.androidkit.Color;
+import org.skia.androidkit.Image;
import org.skia.androidkit.Matrix;
import org.skia.androidkit.Paint;
import org.skia.androidkit.Surface;
@@ -70,6 +71,11 @@
);
}
+ // TODO: sampling options
+ public void drawImage(Image image, float x, float y) {
+ nDrawImage(mNativeInstance, image.getNativeInstance(), x, y);
+ }
+
// package private
Canvas(Surface surface, long native_instance) {
mNativeInstance = native_instance;
@@ -92,4 +98,5 @@
private static native void nDrawRect(long nativeInstance,
float left, float right, float top, float bottom,
long nativePaint);
+ private static native void nDrawImage(long nativeInstance, long nativeImage, float x, float y);
}
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Image.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Image.java
new file mode 100644
index 0000000..dea8f21
--- /dev/null
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Image.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.androidkit;
+
+public class Image {
+ private long mNativeInstance;
+
+ /**
+ * Construct an Image from encoded (PNG, GIF, etc) data.
+ *
+ * Returns null for unsupported formats or invalid data.
+ */
+ public static Image fromEncoded(byte[] encodedData) {
+ long nativeImage = nCreate(encodedData);
+ return nativeImage != 0
+ ? new Image(nativeImage)
+ : null;
+ }
+
+ public int getWidth() {
+ return nGetWidth(mNativeInstance);
+ }
+
+ public int getHeight() {
+ return nGetHeight(mNativeInstance);
+ }
+
+ /**
+ * Releases any resources associated with this Paint.
+ */
+ public void release() {
+ nRelease(mNativeInstance);
+ mNativeInstance = 0;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ release();
+ }
+
+ // package private
+ Image(long nativeInstance) {
+ mNativeInstance = nativeInstance;
+ }
+
+ // package private
+ long getNativeInstance() { return mNativeInstance; }
+
+ private static native long nCreate(byte[] encodedData);
+ private static native void nRelease(long nativeInstance);
+
+ private static native int nGetWidth(long nativeInstance);
+ private static native int nGetHeight(long nativeInstance);
+}
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Surface.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Surface.java
index dded1b0..541dd17 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Surface.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Surface.java
@@ -12,6 +12,7 @@
import android.support.annotation.RequiresApi;
import org.skia.androidkit.Canvas;
+import org.skia.androidkit.Image;
public class Surface {
private long mNativeInstance;
@@ -51,6 +52,15 @@
return new Canvas(this, nGetNativeCanvas(mNativeInstance));
}
+
+ /**
+ * Returns an Image capturing the Surface contents.
+ * Subsequent drawing to Surface contents are not captured.
+ */
+ public Image makeImageSnapshot() {
+ return new Image(nMakeImageSnapshot(mNativeInstance));
+ }
+
/***
* Triggers the immediate execution of all pending draw operations.
*
@@ -104,4 +114,5 @@
private static native void nFlushAndSubmit(long nativeInstance);
private static native int nGetWidth(long nativeInstance);
private static native int nGetHeight(long nativeInstance);
+ private static native long nMakeImageSnapshot(long nativeInstance);
}
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
index 94ab98e..79fb2b3 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
+++ b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
@@ -11,9 +11,11 @@
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;
+import java.io.InputStream;
import org.skia.androidkit.*;
public class MainActivity extends Activity implements SurfaceHolder.Callback {
@@ -33,7 +35,7 @@
// Bitmap
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
- Bitmap bmp = Bitmap.createBitmap(200, 200, conf);
+ Bitmap bmp = Bitmap.createBitmap(400, 400, conf);
Surface bitmapSurface = new Surface(bmp);
Canvas canvas = bitmapSurface.getCanvas();
@@ -49,6 +51,20 @@
canvas.drawRect(0, 0, 100, 100, p);
canvas.restore();
+ Image snapshot = bitmapSurface.makeImageSnapshot();
+ canvas.drawImage(snapshot, 0, 200);
+
+ try {
+ InputStream is = getResources().openRawResource(R.raw.brickwork_texture);
+ byte[] data = new byte[is.available()];
+ is.read(data);
+
+ Image image = Image.fromEncoded(data);
+ canvas.drawImage(image, 200, 0);
+ } catch (Exception e) {
+ Log.e("AndroidKit Demo", "Could not load Image resource: " + R.raw.brickwork_texture);
+ }
+
ImageView image = findViewById(R.id.image);
image.setImageBitmap(bmp);
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml b/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml
index 00e9d0f..b42da69 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml
+++ b/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml
@@ -16,8 +16,8 @@
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/image"
- android:layout_width="200px"
- android:layout_height="200px"
+ android:layout_width="400px"
+ android:layout_height="400px"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
</ImageView>
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/res/raw/brickwork_texture.jpg b/platform_tools/android/apps/androidkitdemo/src/main/res/raw/brickwork_texture.jpg
new file mode 100644
index 0000000..9a7dd11
--- /dev/null
+++ b/platform_tools/android/apps/androidkitdemo/src/main/res/raw/brickwork_texture.jpg
Binary files differ