implement BitmapFactory.decodeStream() using gdk_pixbuf_new_from_stream

The java InputStream is wrapped into a custom GInputStream
implementation
This commit is contained in:
Julian Winkler 2023-09-01 13:09:04 +02:00
parent 30b990f60a
commit ceb5df9d39
7 changed files with 95 additions and 8 deletions

View file

@ -67,6 +67,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [
'src/api-impl-jni/database/android_database_SQLiteCommon.c',
'src/api-impl-jni/database/android_database_SQLiteConnection.c',
'src/api-impl-jni/drawables/ninepatch.c',
'src/api-impl-jni/graphics/android_graphics_BitmapFactory.c',
'src/api-impl-jni/android_content_res_AssetManager.c',
'src/api-impl-jni/audio/android_media_AudioTrack.c',
'src/api-impl-jni/audio/android_media_SoundPool.c',

View file

@ -52,3 +52,15 @@ JNIEXPORT jboolean JNICALL Java_android_graphics_Bitmap_nativeRecycle(JNIEnv *en
g_object_unref(pixbuf);
return true;
}
JNIEXPORT jlong JNICALL Java_android_graphics_Bitmap_native_1copy(JNIEnv *env, jclass, jlong src_ptr) {
GdkPixbuf *src = _PTR(src_ptr);
GdkPixbuf *copy = gdk_pixbuf_copy(src);
return _INTPTR(copy);
}
JNIEXPORT jint JNICALL Java_android_graphics_Bitmap_nativeRowBytes(JNIEnv *env, jclass, jlong pixbuf_ptr) {
GdkPixbuf *pixbuf = _PTR(pixbuf_ptr);
return gdk_pixbuf_get_rowstride(pixbuf);
}

View file

@ -19,6 +19,14 @@ extern "C" {
JNIEXPORT jlong JNICALL Java_android_graphics_Bitmap_native_1bitmap_1from_1path
(JNIEnv *, jobject, jobject);
/*
* Class: android_graphics_Bitmap
* Method: native_copy
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_android_graphics_Bitmap_native_1copy
(JNIEnv *, jclass, jlong);
/*
* Class: android_graphics_Bitmap
* Method: getWidth
@ -86,10 +94,10 @@ JNIEXPORT void JNICALL Java_android_graphics_Bitmap_nativeErase
/*
* Class: android_graphics_Bitmap
* Method: nativeRowBytes
* Signature: (I)I
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_android_graphics_Bitmap_nativeRowBytes
(JNIEnv *, jclass, jint);
(JNIEnv *, jclass, jlong);
/*
* Class: android_graphics_Bitmap

View file

@ -12,9 +12,9 @@ extern "C" {
/*
* Class: android_graphics_BitmapFactory
* Method: nativeDecodeStream
* Signature: (Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory/Options;)Landroid/graphics/Bitmap;
* Signature: (Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory/Options;)J
*/
JNIEXPORT jobject JNICALL Java_android_graphics_BitmapFactory_nativeDecodeStream
JNIEXPORT jlong JNICALL Java_android_graphics_BitmapFactory_nativeDecodeStream
(JNIEnv *, jclass, jobject, jbyteArray, jobject, jobject);
/*

View file

@ -0,0 +1,60 @@
#include <gtk/gtk.h>
#include <string.h>
#include "../defines.h"
#include "../util.h"
#include "../generated_headers/android_graphics_BitmapFactory.h"
struct _JavaInputStream
{
GInputStream parent_instance;
jobject is;
jbyteArray storage;
int storage_size;
};
G_DECLARE_FINAL_TYPE(JavaInputStream, java_input_stream, ATL, JAVA_INPUT_STREAM, GInputStream);
static gssize java_input_stream_read(GInputStream *gstream, void *buffer, gsize count, GCancellable *cancellable, GError **error) {
JavaInputStream *stream = ATL_JAVA_INPUT_STREAM(gstream);
JNIEnv *env = get_jni_env();
count = MIN(count, stream->storage_size);
count = (*env)->CallIntMethod(env, stream->is, _METHOD(_CLASS(stream->is), "read", "([BII)I"), stream->storage, 0, count);
if (count == -1) { // end of stream
return 0;
}
jbyte *storage_buf = (*env)->GetByteArrayElements(env, stream->storage, NULL);
memcpy(buffer, storage_buf, count);
(*env)->ReleaseByteArrayElements(env, stream->storage, storage_buf, 0);
return count;
}
static void java_input_stream_class_init(JavaInputStreamClass *klass) {
klass->parent_class.read_fn = java_input_stream_read;
}
static void java_input_stream_init(JavaInputStream *self) {
}
G_DEFINE_TYPE(JavaInputStream, java_input_stream, G_TYPE_INPUT_STREAM)
static GInputStream *java_input_stream_new(JNIEnv *env, jobject is, jbyteArray storage) {
JavaInputStream *stream = g_object_new(java_input_stream_get_type(), NULL);
stream->is = is;
stream->storage = storage;
stream->storage_size = (*env)->GetArrayLength(env, storage);
return &stream->parent_instance;
}
JNIEXPORT jlong JNICALL Java_android_graphics_BitmapFactory_nativeDecodeStream(JNIEnv *env, jclass, jobject is, jbyteArray storage, jobject outPadding, jobject opts) {
GInputStream *stream = java_input_stream_new(env, is, storage);
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, NULL);
g_object_unref(stream);
return _INTPTR(pixbuf);
}

View file

@ -136,7 +136,13 @@ public final class Bitmap {
mLayoutBounds = null;
}
Bitmap(long pixbuf) {
this();
this.pixbuf = pixbuf;
}
private native long native_bitmap_from_path(CharSequence path);
static native long native_copy(long src);
/**
* Private constructor that must received an already allocated native bitmap
@ -784,7 +790,7 @@ public final class Bitmap {
return bitmap;
*/
return new Bitmap();
return new Bitmap(native_copy(source.pixbuf));
}
/**
@ -1606,7 +1612,7 @@ public final class Bitmap {
int quality, OutputStream stream,
byte[] tempStorage);
private static native void nativeErase(int nativeBitmap, int color);
private static native int nativeRowBytes(int nativeBitmap);
private static native int nativeRowBytes(long nativeBitmap);
private static native int nativeConfig(int nativeBitmap);
private static native int nativeGetPixel(int nativeBitmap, int x, int y,

View file

@ -596,7 +596,7 @@ public class BitmapFactory {
tempStorage = opts.inTempStorage;
if (tempStorage == null)
tempStorage = new byte[DECODE_BUFFER_SIZE];
return nativeDecodeStream(is, tempStorage, outPadding, opts);
return new Bitmap(nativeDecodeStream(is, tempStorage, outPadding, opts));
}
/**
@ -669,7 +669,7 @@ public class BitmapFactory {
return decodeFileDescriptor(fd, null, null);
}
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
private static native long nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts);
private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
Rect padding, Options opts);