diff --git a/.gitignore b/.gitignore index c3740ad..74e3654 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ gradle.properties *.apk *.ap_ *.jar +.externalNativeBuild # files for the dex VM *.dex diff --git a/JniBitmapOperationsLibrary/AndroidManifest.xml b/JniBitmapOperationsLibrary/AndroidManifest.xml index f93a35b..02e8b88 100644 --- a/JniBitmapOperationsLibrary/AndroidManifest.xml +++ b/JniBitmapOperationsLibrary/AndroidManifest.xml @@ -1,11 +1,4 @@ - - - - - + android:versionName="1.0" /> diff --git a/JniBitmapOperationsLibrary/build.gradle b/JniBitmapOperationsLibrary/build.gradle index dc7bb5f..f3c931a 100644 --- a/JniBitmapOperationsLibrary/build.gradle +++ b/JniBitmapOperationsLibrary/build.gradle @@ -25,9 +25,15 @@ android { cFlags "-DANDROID_NDK_HOME" stl "stlport_shared" } + minSdkVersion 8 + targetSdkVersion 23 } - + externalNativeBuild { + ndkBuild { + path 'jni/Android.mk' + } + } /* task buildNative(type: Exec, description: 'Compile JNI source via NDK') { diff --git a/JniBitmapOperationsLibrary/jni/JniBitmapOperationsLibrary.cpp b/JniBitmapOperationsLibrary/jni/JniBitmapOperationsLibrary.cpp index f6aef1e..723a375 100644 --- a/JniBitmapOperationsLibrary/jni/JniBitmapOperationsLibrary.cpp +++ b/JniBitmapOperationsLibrary/jni/JniBitmapOperationsLibrary.cpp @@ -87,7 +87,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniCropBi uint32_t right, uint32_t bottom) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t* previousData = jniBitmap->_storedBitmapPixels; uint32_t oldWidth = jniBitmap->_bitmapInfo.width; @@ -113,7 +113,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotate JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t* previousData = jniBitmap->_storedBitmapPixels; uint32_t newWidth = jniBitmap->_bitmapInfo.height; @@ -141,7 +141,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotate JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t* previousData = jniBitmap->_storedBitmapPixels; uint32_t newWidth = jniBitmap->_bitmapInfo.height; @@ -169,7 +169,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotate JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t* pixels = jniBitmap->_storedBitmapPixels; uint32_t* pixels2 = jniBitmap->_storedBitmapPixels; @@ -211,7 +211,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFreeBi JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; delete[] jniBitmap->_storedBitmapPixels; jniBitmap->_storedBitmapPixels = NULL; @@ -223,7 +223,7 @@ JNIEXPORT jobject JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniGet JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) { LOGD("no bitmap data was stored. returning null..."); return NULL; @@ -311,7 +311,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniScaleN uint32_t newHeight) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t oldWidth = jniBitmap->_bitmapInfo.width; uint32_t oldHeight = jniBitmap->_bitmapInfo.height; @@ -353,7 +353,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniScaleB { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t oldWidth = jniBitmap->_bitmapInfo.width; uint32_t oldHeight = jniBitmap->_bitmapInfo.height; @@ -422,7 +422,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniScaleB &rgbTopLeft); //rgbTopRight=startingImageData[xTopLeft+1][yTopLeft]; convertIntToArgb( - previousData[((yTopLeft + 1) * oldWidth) + xTopLeft], + previousData[(yTopLeft* oldWidth) + xTopLeft + 1], &rgbTopRight); rgbTopMiddle.alpha = rgbTopLeft.alpha * xcRatio2 + rgbTopRight.alpha * xcratio1; @@ -486,7 +486,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFlipBi JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t* previousData = jniBitmap->_storedBitmapPixels; int width = jniBitmap->_bitmapInfo.width, middle = width / 2, height = @@ -518,7 +518,7 @@ JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFlipBi JNIEnv * env, jobject obj, jobject handle) { JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); - if (jniBitmap->_storedBitmapPixels == NULL) + if (jniBitmap == NULL || jniBitmap->_storedBitmapPixels == NULL) return; uint32_t* previousData = jniBitmap->_storedBitmapPixels; int width = jniBitmap->_bitmapInfo.width, height = diff --git a/README.md b/README.md index 4249397..242e270 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ This library was first introduced via StackOverflow, and many of the notes writt Please read it here: http://stackoverflow.com/questions/18250951/jni-bitmap-operations-for-helping-to-avoid-oom-when-using-large-images/18250952?noredirect=1 +Starting from Android 11 (R - API 30), it seems to be possible to also decode the bitmaps right in JNI, so this might be handy to perform operations on it right away (though not sure how to do it) : +https://developer.android.com/ndk/guides/image-decoder + ## Screenshot Here's a sample of what can be done: @@ -80,6 +83,29 @@ Just import the whole cloned project and run the sample. #### Further configuring and using as the library +#### Option 1 + 1. Add this repository as a git submodule. For these instructions we added in a folder named `AndroidJniBitmapOperations` + 2. Add the following lines to your `settings.gradle` file + + ``` + include ':JniBitmapOperationsLibrary' + project(':JniBitmapOperationsLibrary').projectDir = new File(rootProject.getProjectDir(), 'AndroidJniBitmapOperations/JniBitmapOperationsLibrary') + ``` + 3. Add the following lines to your top level `build.gradle` file inside the `buildscript` section. Replace the versions with whatever your project is using as needed. + + ``` + // Variables for JniBitmapOperationsLibrary + ext.propCompileSdkVersion = 23 + ext.propBuildToolsVersion = "27.0.3" + ``` + 4. Add the following lines to your app `build.gradle` file inside the `dependancies` section + + ``` + implementation project(':JniBitmapOperationsLibrary') + ``` + +#### Option 2 + 1. Copy `JniBitmapOperationsLibrary.cpp` into `src/main/jni` directory: ![Studio folder structure](https://s3.amazonaws.com/uploads.hipchat.com/22412/120721/qZyoFrgpUnFmnHu/upload.png) @@ -104,7 +130,15 @@ Just import the whole cloned project and run the sample. You now should be able to use `JniBitmapHolder` to process images on NDK side. - +## Similar libraries + +If you are interested in more features, and don't want to modify the code of this library, you could try out those similar libraries: + + - https://github.com/suckgamony/RapidDecoder + - https://github.com/facebook/fresco + - https://android-arsenal.com/tag/63 + + [1]: http://stackoverflow.com/questions/22263253/how-to-correctly-import-an-android-library-with-jni-code/22956790?noredirect=1#comment35057887_22956790 [2]: https://developer.android.com/tools/sdk/ndk/index.html diff --git a/build.gradle b/build.gradle index b181f5f..9c44237 100644 --- a/build.gradle +++ b/build.gradle @@ -7,9 +7,10 @@ buildscript { repositories { mavenCentral() + google() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:3.2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files