Вращение растрового изображения с использованием JNI & NDK

Справочная информация: Я

Мы решили, что поскольку растровые изображения занимают много памяти, что может легко вызвать ошибки нехватки памяти, я возьму на себя трудоемкую работу над кодом C / C ++.

Шаги, которые я использую для вращения растрового изображения:читать растровую информацию (ширина, высота)сохранить растровые пиксели в массив.переработать растровое изображение.создать новое растровое изображение противоположного размера.поместите пиксели в новое растровое изображение.освободите пиксели и верните растровое изображение.Эта проблема:

Хотя кажется, что все работает без ошибок, выходное изображение не является поворотом оригинала. Фактически, это разрушает это полностью.

Вращение должно быть против часовой стрелки, 90 градусов.

Пример (скриншот увеличен) того, что я получаю:

Так что, как видите, не только цвета стали более странными, но и размер нене соответствует тому, что яМы настроены на это. Здесь что-то действительно странное.

Может я неправильно читать / поставить данные?

Конечно, это всего лишь пример. Код должен нормально работать на любом растровом изображении, если на устройстве достаточно памяти для его хранения. Кроме того, я мог бы хотеть сделать другие операции над растровым изображением кроме вращения его.

Код I 'мы создали:

Файл Android.mk:

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:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#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-файл:

  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);

РЕДАКТИРОВАТЬ: после того, как я получил свой ответ, я хочу поделиться этим кодом и примечаниями к нему для всех:

для того, чтобы это сработало, язаменил в коде каждый экземпляр "uint16_t» с "uint32_t» (тот'ошибка в моем коде ямы спрашивали о).

битовый массив ввода и вывода должен быть с конфигурацией 8888 (которая является ARGB)

входной битовый массив будет переработан во время процесса.

код поворачивает изображение на 90 градусов против часовой стрелки. Конечно, вы можете изменить его в зависимости от ваших потребностей.

лучшее решение

мы сделали хороший пост с этой и другими функциями,Вот .

Ответы на вопрос(1)

Ваш ответ на вопрос