旋转使用JNI和放大器的位图; NDK [英] Rotating a bitmap using JNI & NDK

查看:365
本文介绍了旋转使用JNI和放大器的位图; NDK的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经决定,由于位图需要大量的内存,并且可以很容易造成内存不足的错误,我会把硬盘,内存占用工作C / C ++ code。

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 .

  1. 在读的位图信息(宽,高)
  2. 在店内位图的像素到一个数组中。
  3. 循环使用位图。
  4. 创建相对大小的新位图。
  5. 把像素到新位图。
  6. 释放像素,并返回该位图。

尽管一切都似乎没有任何错误运行,输出的图像就不是原来的旋转。事实上,它完全毁掉它。

The problem:

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.

的转动应是反时针,90度。

The rotation should be counter clock wise, 90 degrees.

因此​​,大家可以看到,不仅颜色变得怪异,但大小不匹配什么我已经设置它。有些事情很奇怪在这里。

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.

也许我不读/把正确的数据?

Maybe I don't read/put the data correctly?

当然,这仅仅是一个例子。在code应该能正常运行的任何位图,只要设备有足够的内存来容纳它。另外,我可能要进行其他操作的位图比它旋转等。

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.

Android.mk文件:

Android.mk file:

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

CPP文件:

cpp file:

#include <jni.h>
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <android/bitmap.h>
#include <cstring>
#include <unistd.h>

#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, &info)) < 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, &bitmapPixels)) < 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->GetObjectClass(bitmap);
  jmethodID recycleFunction = env->GetMethodID(bitmapCls, "recycle", "()V");
  if (recycleFunction == 0)
    {
    LOGE("error recycling!");
    return NULL;
    }
  env->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->GetStaticMethodID(bitmapCls, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
  jstring configName = env->NewStringUTF("ARGB_8888");
  jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
  jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(bitmapConfigClass, "valueOf", "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
  jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass, valueOfBitmapConfigFunction, configName);
  jobject newBitmap = env->CallStaticObjectMethod(bitmapCls, createBitmapFunction, info.height, info.width, bitmapConfig);
  //
  // putting the pixels into the new bitmap:
  //
  if ((ret = AndroidBitmap_lockPixels(env, newBitmap, &bitmapPixels)) < 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 >= 0; --x)
    for (int y = 0; y < 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;
  }

Java文件中:

java file:

  static
    {
    System.loadLibrary("JniTest");
    }

  /**
   * rotates a bitmap by 90 degrees counter-clockwise . <br/>
   * notes:<br/>
   * -the input bitmap will be recycled and shouldn't be used anymore <br/>
   * -returns the rotated bitmap . <br/>
   * -could take some time , so do the operation in a new thread
   */
  public native Bitmap rotateBitmapCcw90(Bitmap bitmap);

...
  Bitmap rotatedImage=rotateBitmapCcw90(bitmapToRotate);


编辑:在我得到我的回答,我想分享这个code及注意事项给大家:


after I got my answer, I wish to share this code and notes about it to everyone:

  • 为了为它工作,我把它换成了codeuint16_t与uint32_t的(这是我问了一下我的code中的错误)的每个实例。

  • 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).

输入和输出位图必须与8888配置(这是ARGB)

input and output bitmap must be with 8888 config (which is ARGB )

输入位图将在此过程中被回收。

input bitmap will be recycled during the process.

在code将图像旋转90度计数器的时钟明智的。当然,你可以根据自己的需要改变它。

the code rotates the image 90 degrees counter clock wise. Of course you can change it depending on your needs.

我做了有这个功能和其他人,<一个好贴href="http://stackoverflow.com/questions/18250951/jni-bitmap-operations-for-helping-to-avoid-oom">here

i've made a nice post having this functionality and others, here .

推荐答案

由于您使用 ARGB_8888 格式的每个像素是 uint32_t的不是 uint16_t 。试着改变你的旋转位图的创建使用 uint32_t的源和目标阵列,它应该更好地工作。

Since you're using ARGB_8888 format every pixel is an uint32_t not uint16_t. Try changing your rotated Bitmap creation to use uint32_t for source and destination arrays and it should work better.

这篇关于旋转使用JNI和放大器的位图; NDK的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆