Skip to content

Instantly share code, notes, and snippets.

@ncruces
Last active March 14, 2019 14:54
Show Gist options
  • Save ncruces/b6e87f98250c638708d5d2e3a2936376 to your computer and use it in GitHub Desktop.
Save ncruces/b6e87f98250c638708d5d2e3a2936376 to your computer and use it in GitHub Desktop.
JNA wrapper for Android NDK bitmap.h
package io.github.ncruces.utils;
import android.graphics.Bitmap;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.sun.jna.JNIEnv;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.PointerByReference;
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static com.sun.jna.Library.OPTION_ALLOW_OBJECTS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import static java.util.Objects.requireNonNull;
@RequiresApi(8)
@SuppressWarnings({"unused", "JniMissingFunction", "WeakerAccess"})
public final class AndroidBitmap {
static {
NativeLibrary lib = NativeLibrary.getInstance("jnigraphics",
Collections.singletonMap(OPTION_ALLOW_OBJECTS, true));
Native.register(AndroidBitmap.class, lib);
}
private AndroidBitmap() {}
public static Info getInfo(Bitmap bitmap) {
requireNonNull(bitmap);
Info info = new Info();
info.setAutoWrite(false);
check(AndroidBitmap_getInfo(JNIEnv.CURRENT, bitmap, info));
return info;
}
public static Pointer lockPixels(Bitmap bitmap) {
requireNonNull(bitmap);
PointerByReference ptr = new PointerByReference();
check(AndroidBitmap_lockPixels(JNIEnv.CURRENT, bitmap, ptr));
return ptr.getValue();
}
public static void unlockPixels(Bitmap bitmap) {
requireNonNull(bitmap);
check(AndroidBitmap_unlockPixels(JNIEnv.CURRENT, bitmap));
}
@Retention(SOURCE)
@IntDef({Format.NONE, Format.RGBA_8888, Format.RGB_565, Format.RGBA_4444, Format.A_8})
public @interface Format {
int NONE = 0;
int RGBA_8888 = 1;
int RGB_565 = 4;
int RGBA_4444 = 7;
int A_8 = 8;
}
public static final class Info extends Structure {
public int width;
public int height;
public int stride;
public @Format int format;
public int flags;
public Info() {}
@Override
protected @NonNull List<String> getFieldOrder() {
return Arrays.asList("width", "height", "stride", "format", "flags");
}
}
private static native @Result int AndroidBitmap_getInfo(JNIEnv env, Bitmap jbitmap, Info info);
private static native @Result int AndroidBitmap_lockPixels(JNIEnv env, Bitmap jbitmap, PointerByReference addrPtr);
private static native @Result int AndroidBitmap_unlockPixels(JNIEnv env, Bitmap jbitmap);
@Retention(SOURCE)
@IntDef({Result.SUCCESS, Result.BAD_PARAMETER, Result.JNI_EXCEPTION, Result.ALLOCATION_FAILED})
private @interface Result {
int SUCCESS = 0;
int BAD_PARAMETER = -1;
int JNI_EXCEPTION = -2;
int ALLOCATION_FAILED = -3;
}
private static void check(@Result int result) {
switch (result) {
case Result.SUCCESS: break;
case Result.BAD_PARAMETER: throw new IllegalArgumentException();
case Result.JNI_EXCEPTION: throw new RuntimeException();
case Result.ALLOCATION_FAILED: throw new OutOfMemoryError();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment