[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>
This commit is contained in:
Florin Malita 2021-05-20 12:23:42 -04:00 committed by Skia Commit-Bot
parent 25be58e24b
commit 934c02142e
12 changed files with 191 additions and 17 deletions

View File

@ -2495,6 +2495,7 @@ if (skia_enable_tools) {
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",

View File

@ -24,6 +24,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
}
REGISTER_NATIVES(Canvas)
REGISTER_NATIVES(Image)
REGISTER_NATIVES(Matrix)
REGISTER_NATIVES(Paint)
REGISTER_NATIVES(RuntimeShaderBuilder)

View File

@ -79,6 +79,16 @@ void Canvas_DrawRect(JNIEnv* env, jobject, jlong native_instance,
}
}
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 @@ int register_androidkit_Canvas(JNIEnv* env) {
{"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");

View File

@ -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;
}

View File

@ -225,35 +225,45 @@ static void Surface_FlushAndSubmit(JNIEnv* env, jobject, jlong native_surface) {
}
}
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");

View File

@ -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 @@ public:
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;
};

View File

@ -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 @@ public class Canvas {
);
}
// 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 @@ public class Canvas {
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);
}

View File

@ -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);
}

View File

@ -12,6 +12,7 @@ import android.os.Build;
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 @@ public class Surface {
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 @@ public class Surface {
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);
}

View File

@ -11,9 +11,11 @@ import android.app.Activity;
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 @@ public class MainActivity extends Activity implements SurfaceHolder.Callback {
// 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 @@ public class MainActivity extends Activity implements SurfaceHolder.Callback {
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);

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB