Ответ 1
Поскольку вы используете формат ARGB_8888
, каждый пиксель является uint32_t
not uint16_t
. Попробуйте изменить созданное растровое изображение, чтобы использовать uint32_t
для исходных и целевых массивов, и он должен работать лучше.
Я решил, что, поскольку растровые изображения занимают много памяти, что может привести к ошибкам без учета объема памяти, я положу тяжелую работу по потреблению памяти на код C/С++.
Несмотря на то, что все, кажется, работает без ошибок, выходное изображение не является поворотным оригиналом. Фактически, он полностью разрушает его.
Вращение должно быть против часовой стрелки, 90 градусов.
Итак, как вы можете видеть, не только цвета стали более странными, но размер не соответствует тому, что я ему задал. Здесь что-то действительно странно.
Может быть, я не читаю/не помещаю данные правильно?
Конечно, это всего лишь пример. Код должен работать нормально на любом растровом изображении, если у устройства достаточно памяти для его хранения. Кроме того, я мог бы делать другие операции над растровым рисунком, кроме вращения.
Файл 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 <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 файл:
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);
EDIT: после того, как я получил свой ответ, я хочу поделиться этим кодом и отметить его всем:
чтобы он работал, я заменил в коде каждый экземпляр "uint16_t" на "uint32_t" (что ошибка в моем коде, о котором я просил).
битовая карта ввода и вывода должна быть с конфигурацией 8888 (которая является ARGB)
входной битмап будет возвращен во время процесса.
код поворачивает изображение на 90 градусов против часовой стрелки. Конечно, вы можете изменить его в зависимости от ваших потребностей.
Я сделал хороший пост с этой функциональностью и другими, здесь.
Поскольку вы используете формат ARGB_8888
, каждый пиксель является uint32_t
not uint16_t
. Попробуйте изменить созданное растровое изображение, чтобы использовать uint32_t
для исходных и целевых массивов, и он должен работать лучше.