title: Rotating a bitmap using JNI & NDK
body: <h2>Background:</h2>
  
  <p>I've decided that since bitmaps take a lot of memory which can cause out-of-memory errors easily, I will put the hard, memory consuming work on C/C++ code . </p>
  
  <h2>The steps I use for rotating a bitmap are:</h2>
  
  <ol>
  <li>read bitmap info (width,height)</li>
  <li>store bitmap pixels into an array.</li>
  <li>recycle the bitmap.</li>
  <li>create a new bitmap of opposite size.</li>
  <li>put the pixels into the new bitmap. </li>
  <li>free the pixels and return the bitmap.</li>
  </ol>
  
  <h2>The problem:</h2>
  
  <p>Even though everything seems to run without any errors, the output image is not a rotation of the original. In fact, it ruins it completely. </p>
  
  <p>The rotation should be counter clock wise, 90 degrees. </p>
  
  <h2>Example (screenshot is zoomed in) of what I get:</h2>
  
  <p><img src="https://i.stack.imgur.com/Sd4oj.png" alt="enter image description here"></p>
  
  <p>So as you can see, not only the colors became weirder, but the size doesn't match what I've set to it. Something is really weird here. </p>
  
  <p>Maybe I don't read/put the data correctly? </p>
  
  <p>Of course this is just an example. The code should work fine on any bitmap, as long as the device has enough memory to hold it. Also, I might want to do other operations on the bitmap other than rotating it. </p>
  
  <h2>Code I've created :</h2>
  
  <p>Android.mk file:</p>
  
  <pre><code>LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_MODULE    := JniTest
  LOCAL_SRC_FILES := JniTest.cpp
  LOCAL_LDLIBS := -llog
  LOCAL_LDFLAGS += -ljnigraphics
  include $(BUILD_SHARED_LIBRARY)
  APP_OPTIM := debug
  LOCAL_CFLAGS := -g
  </code></pre>
  
  <p>cpp file:</p>
  
  <pre><code>#include &lt;jni.h&gt;
  #include &lt;jni.h&gt;
  #include &lt;android/log.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;android/bitmap.h&gt;
  #include &lt;cstring&gt;
  #include &lt;unistd.h&gt;
  
  #define  LOG_TAG    "DEBUG"
  #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
  #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
  
  extern "C"
    {
    JNIEXPORT jobject JNICALL Java_com_example_jnitest_MainActivity_rotateBitmapCcw90(JNIEnv * env, jobject obj, jobject bitmap);
    }
  
  JNIEXPORT jobject JNICALL Java_com_example_jnitest_MainActivity_rotateBitmapCcw90(JNIEnv * env, jobject obj, jobject bitmap)
    {
    //
    //getting bitmap info:
    //
    LOGD("reading bitmap info...");
    AndroidBitmapInfo info;
    int ret;
    if ((ret = AndroidBitmap_getInfo(env, bitmap, &amp;info)) &lt; 0)
      {
      LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
      return NULL;
      }
    LOGD("width:%d height:%d stride:%d", info.width, info.height, info.stride);
    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
      {
      LOGE("Bitmap format is not RGBA_8888!");
      return NULL;
      }
    //
    //read pixels of bitmap into native memory :
    //
    LOGD("reading bitmap pixels...");
    void* bitmapPixels;
    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &amp;bitmapPixels)) &lt; 0)
      {
      LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
      return NULL;
      }
    uint32_t* src = (uint32_t*) bitmapPixels;
    uint32_t* tempPixels = new uint32_t[info.height * info.width];
    int stride = info.stride;
    int pixelsCount = info.height * info.width;
    memcpy(tempPixels, src, sizeof(uint32_t) * pixelsCount);
    AndroidBitmap_unlockPixels(env, bitmap);
    //
    //recycle bitmap - using bitmap.recycle()
    //
    LOGD("recycling bitmap...");
    jclass bitmapCls = env-&gt;GetObjectClass(bitmap);
    jmethodID recycleFunction = env-&gt;GetMethodID(bitmapCls, "recycle", "()V");
    if (recycleFunction == 0)
      {
      LOGE("error recycling!");
      return NULL;
      }
    env-&gt;CallVoidMethod(bitmap, recycleFunction);
    //
    //creating a new bitmap to put the pixels into it - using Bitmap Bitmap.createBitmap (int width, int height, Bitmap.Config config) :
    //
    LOGD("creating new bitmap...");
    jmethodID createBitmapFunction = env-&gt;GetStaticMethodID(bitmapCls, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
    jstring configName = env-&gt;NewStringUTF("ARGB_8888");
    jclass bitmapConfigClass = env-&gt;FindClass("android/graphics/Bitmap$Config");
    jmethodID valueOfBitmapConfigFunction = env-&gt;GetStaticMethodID(bitmapConfigClass, "valueOf", "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
    jobject bitmapConfig = env-&gt;CallStaticObjectMethod(bitmapConfigClass, valueOfBitmapConfigFunction, configName);
    jobject newBitmap = env-&gt;CallStaticObjectMethod(bitmapCls, createBitmapFunction, info.height, info.width, bitmapConfig);
    //
    // putting the pixels into the new bitmap:
    //
    if ((ret = AndroidBitmap_lockPixels(env, newBitmap, &amp;bitmapPixels)) &lt; 0)
      {
      LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
      return NULL;
      }
    uint32_t* newBitmapPixels = (uint32_t*) bitmapPixels;
    int whereToPut = 0;    
    for (int x = info.width - 1; x &gt;= 0; --x)
      for (int y = 0; y &lt; info.height; ++y)
        {
        uint32_t pixel = tempPixels[info.width * y + x];
        newBitmapPixels[whereToPut++] = pixel;
        }
    AndroidBitmap_unlockPixels(env, newBitmap);
    //
    // freeing the native memory used to store the pixels
    //
    delete[] tempPixels;
    return newBitmap;
    }
  </code></pre>
  
  <p>java file:</p>
  
  <pre><code>  static
      {
      System.loadLibrary("JniTest");
      }
  
    /**
     * rotates a bitmap by 90 degrees counter-clockwise . &lt;br/&gt;
     * notes:&lt;br/&gt;
     * -the input bitmap will be recycled and shouldn't be used anymore &lt;br/&gt;
     * -returns the rotated bitmap . &lt;br/&gt;
     * -could take some time , so do the operation in a new thread
     */
    public native Bitmap rotateBitmapCcw90(Bitmap bitmap);
  
  ...
    Bitmap rotatedImage=rotateBitmapCcw90(bitmapToRotate);
  </code></pre>
  
  <hr>
  
  <p>EDIT: after I got my answer, I wish to share this code and notes about it to everyone:</p>
  
  <ul>
  <li><p>in order for it to work, i've replaced in the code every instance of "uint16_t" with "uint32_t" (that's the bug on my code I've asked about).</p></li>
  <li><p>input and output bitmap must be with 8888 config (which is ARGB )</p></li>
  <li><p>input bitmap will be recycled during the process. </p></li>
  <li><p>the code rotates the image 90 degrees counter clock wise. Of course you can change it depending on your needs.</p></li>
  </ul>
  
  <hr>
  
  <h2>better solution</h2>
  
  <p>i've made a nice post having this functionality and others, <a href="https://stackoverflow.com/questions/18250951/jni-bitmap-operations-for-helping-to-avoid-oom"><strong>here</strong></a> .</p>