|
| 1 | +#include <jni.h> |
| 2 | +#include <jni.h> |
| 3 | +#include <android/log.h> |
| 4 | +#include <stdio.h> |
| 5 | +#include <android/bitmap.h> |
| 6 | +#include <cstring> |
| 7 | +#include <unistd.h> |
| 8 | + |
| 9 | +#define LOG_TAG "DEBUG" |
| 10 | +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) |
| 11 | +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) |
| 12 | + |
| 13 | +extern "C" |
| 14 | + { |
| 15 | + JNIEXPORT jobject JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniStoreBitmapData(JNIEnv * env, jobject obj, jobject bitmap); |
| 16 | + JNIEXPORT jobject JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniGetBitmapFromStoredBitmapData(JNIEnv * env, jobject obj, jobject handle); |
| 17 | + JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFreeBitmapData(JNIEnv * env, jobject obj, jobject handle); |
| 18 | + JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotateBitmapCcw90(JNIEnv * env, jobject obj, jobject handle); |
| 19 | + JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniCropBitmap(JNIEnv * env, jobject obj, jobject handle, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom); |
| 20 | + } |
| 21 | + |
| 22 | +class JniBitmap |
| 23 | + { |
| 24 | + public: |
| 25 | + uint32_t* _storedBitmapPixels; |
| 26 | + AndroidBitmapInfo _bitmapInfo; |
| 27 | + JniBitmap() |
| 28 | + { |
| 29 | + _storedBitmapPixels = NULL; |
| 30 | + } |
| 31 | + }; |
| 32 | + |
| 33 | +/**crops the bitmap within to be smaller. note that no validations are done*/ // |
| 34 | +JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniCropBitmap(JNIEnv * env, jobject obj, jobject handle, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom) |
| 35 | + { |
| 36 | + JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); |
| 37 | + if (jniBitmap->_storedBitmapPixels == NULL) |
| 38 | + return; |
| 39 | + uint32_t* previousData = jniBitmap->_storedBitmapPixels; |
| 40 | + uint32_t oldWidth = jniBitmap->_bitmapInfo.width; |
| 41 | + uint32_t newWidth = right - left, newHeight = bottom - top; |
| 42 | + uint32_t* newBitmapPixels = new uint32_t[newWidth * newHeight]; |
| 43 | + uint32_t* whereToGet = previousData + left + top * oldWidth; |
| 44 | + uint32_t* whereToPut = newBitmapPixels; |
| 45 | + for (int y = top; y < bottom; ++y) |
| 46 | + { |
| 47 | + memcpy(whereToPut, whereToGet, sizeof(uint32_t) * newWidth); |
| 48 | + whereToGet += oldWidth; |
| 49 | + whereToPut += newWidth; |
| 50 | + } |
| 51 | + //done copying , so replace old data with new one |
| 52 | + delete[] previousData; |
| 53 | + jniBitmap->_storedBitmapPixels = newBitmapPixels; |
| 54 | + jniBitmap->_bitmapInfo.width = newWidth; |
| 55 | + jniBitmap->_bitmapInfo.height = newHeight; |
| 56 | + } |
| 57 | + |
| 58 | +/**rotates the inner bitmap data by 90 degress counter clock wise*/ // |
| 59 | +JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotateBitmapCcw90(JNIEnv * env, jobject obj, jobject handle) |
| 60 | + { |
| 61 | + JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); |
| 62 | + if (jniBitmap->_storedBitmapPixels == NULL) |
| 63 | + return; |
| 64 | + uint32_t* previousData = jniBitmap->_storedBitmapPixels; |
| 65 | + AndroidBitmapInfo bitmapInfo = jniBitmap->_bitmapInfo; |
| 66 | + uint32_t* newBitmapPixels = new uint32_t[bitmapInfo.height * bitmapInfo.width]; |
| 67 | + int whereToPut = 0; |
| 68 | + // X.. ... |
| 69 | + // ...>... |
| 70 | + // ... X.. |
| 71 | + for (int x = bitmapInfo.width - 1; x >= 0; --x) |
| 72 | + for (int y = 0; y < bitmapInfo.height; ++y) |
| 73 | + { |
| 74 | + uint32_t pixel = previousData[bitmapInfo.width * y + x]; |
| 75 | + newBitmapPixels[whereToPut++] = pixel; |
| 76 | + } |
| 77 | + delete[] previousData; |
| 78 | + jniBitmap->_storedBitmapPixels = newBitmapPixels; |
| 79 | + uint32_t temp = bitmapInfo.width; |
| 80 | + bitmapInfo.width = bitmapInfo.height; |
| 81 | + bitmapInfo.height = temp; |
| 82 | + } |
| 83 | + |
| 84 | +/**free bitmap*/ // |
| 85 | +JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFreeBitmapData(JNIEnv * env, jobject obj, jobject handle) |
| 86 | + { |
| 87 | + JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); |
| 88 | + if (jniBitmap->_storedBitmapPixels == NULL) |
| 89 | + return; |
| 90 | + delete[] jniBitmap->_storedBitmapPixels; |
| 91 | + jniBitmap->_storedBitmapPixels = NULL; |
| 92 | + delete jniBitmap; |
| 93 | + } |
| 94 | + |
| 95 | +/**restore java bitmap (from JNI data)*/ // |
| 96 | +JNIEXPORT jobject JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniGetBitmapFromStoredBitmapData(JNIEnv * env, jobject obj, jobject handle) |
| 97 | + { |
| 98 | + JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); |
| 99 | + if (jniBitmap->_storedBitmapPixels == NULL) |
| 100 | + { |
| 101 | + LOGD("no bitmap data was stored. returning null..."); |
| 102 | + return NULL; |
| 103 | + } |
| 104 | + // |
| 105 | + //creating a new bitmap to put the pixels into it - using Bitmap Bitmap.createBitmap (int width, int height, Bitmap.Config config) : |
| 106 | + // |
| 107 | + //LOGD("creating new bitmap..."); |
| 108 | + jclass bitmapCls = env->FindClass("android/graphics/Bitmap"); |
| 109 | + jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); |
| 110 | + jstring configName = env->NewStringUTF("ARGB_8888"); |
| 111 | + jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config"); |
| 112 | + jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(bitmapConfigClass, "valueOf", "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); |
| 113 | + jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass, valueOfBitmapConfigFunction, configName); |
| 114 | + jobject newBitmap = env->CallStaticObjectMethod(bitmapCls, createBitmapFunction, jniBitmap->_bitmapInfo.height, jniBitmap->_bitmapInfo.width, bitmapConfig); |
| 115 | + // |
| 116 | + // putting the pixels into the new bitmap: |
| 117 | + // |
| 118 | + int ret; |
| 119 | + void* bitmapPixels; |
| 120 | + if ((ret = AndroidBitmap_lockPixels(env, newBitmap, &bitmapPixels)) < 0) |
| 121 | + { |
| 122 | + LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); |
| 123 | + return NULL; |
| 124 | + } |
| 125 | + uint32_t* newBitmapPixels = (uint32_t*) bitmapPixels; |
| 126 | + int pixelsCount = jniBitmap->_bitmapInfo.height * jniBitmap->_bitmapInfo.width; |
| 127 | + memcpy(newBitmapPixels, jniBitmap->_storedBitmapPixels, sizeof(uint32_t) * pixelsCount); |
| 128 | + AndroidBitmap_unlockPixels(env, newBitmap); |
| 129 | + //LOGD("returning the new bitmap"); |
| 130 | + return newBitmap; |
| 131 | + } |
| 132 | + |
| 133 | +/**store java bitmap as JNI data*/ // |
| 134 | +JNIEXPORT jobject JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniStoreBitmapData(JNIEnv * env, jobject obj, jobject bitmap) |
| 135 | + { |
| 136 | + AndroidBitmapInfo bitmapInfo; |
| 137 | + uint32_t* storedBitmapPixels = NULL; |
| 138 | + //LOGD("reading bitmap info..."); |
| 139 | + int ret; |
| 140 | + if ((ret = AndroidBitmap_getInfo(env, bitmap, &bitmapInfo)) < 0) |
| 141 | + { |
| 142 | + LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); |
| 143 | + return NULL; |
| 144 | + } |
| 145 | + LOGD("width:%d height:%d stride:%d", bitmapInfo.width, bitmapInfo.height, bitmapInfo.stride); |
| 146 | + if (bitmapInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888) |
| 147 | + { |
| 148 | + LOGE("Bitmap format is not RGBA_8888!"); |
| 149 | + return NULL; |
| 150 | + } |
| 151 | + // |
| 152 | + //read pixels of bitmap into native memory : |
| 153 | + // |
| 154 | + //LOGD("reading bitmap pixels..."); |
| 155 | + void* bitmapPixels; |
| 156 | + if ((ret = AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels)) < 0) |
| 157 | + { |
| 158 | + LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); |
| 159 | + return NULL; |
| 160 | + } |
| 161 | + uint32_t* src = (uint32_t*) bitmapPixels; |
| 162 | + storedBitmapPixels = new uint32_t[bitmapInfo.height * bitmapInfo.width]; |
| 163 | + int pixelsCount = bitmapInfo.height * bitmapInfo.width; |
| 164 | + memcpy(storedBitmapPixels, src, sizeof(uint32_t) * pixelsCount); |
| 165 | + AndroidBitmap_unlockPixels(env, bitmap); |
| 166 | + JniBitmap *jniBitmap = new JniBitmap(); |
| 167 | + jniBitmap->_bitmapInfo = bitmapInfo; |
| 168 | + jniBitmap->_storedBitmapPixels = storedBitmapPixels; |
| 169 | + return env->NewDirectByteBuffer(jniBitmap, 0); |
| 170 | + } |
| 171 | + |
0 commit comments