NDK 开发之 Bitmap 的使用

字节流动

共 5417字,需浏览 11分钟

 · 2022-01-22

一、前言

Bitmap 是 Android 中经常使用到的图片操作的一个类,它包含了图片的宽、高、格式、像素等信息。那么我们怎么在 NDK 中使用它呢。

二、bitmap.h

1. 介绍

NDK 已经为我们准备好了在 NDK 中操作 Bitmap 的相关头文件了,它就是 。我们先来看看这个头文件里面都包含哪些重要的信息吧。

2. AndroidBitmapInfo

一个包含 Bitmap 常用信息的结构体,定义如下:

/** Bitmap info, see AndroidBitmap_getInfo(). */
typedef struct {
/** The bitmap width in pixels. */
uint32_t width;
/** The bitmap height in pixels. */
uint32_t height;
/** The number of byte per row. */
uint32_t stride;
/** The bitmap pixel format. See {@link AndroidBitmapFormat} */
int32_t format;
/** Unused. */
uint32_t flags; // 0 for now
} AndroidBitmapInfo;

3. AndroidBitmapFormat

Bitmap 的图片格式枚举,和 Java 端所对应

/** Bitmap pixel format. */
enum AndroidBitmapFormat {
/** No format. */
ANDROID_BITMAP_FORMAT_NONE = 0,
/** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
/** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
ANDROID_BITMAP_FORMAT_RGB_565 = 4,
/** Deprecated in API level 13. Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead. **/
ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
/** Alpha: 8 bits. */
ANDROID_BITMAP_FORMAT_A_8 = 8,
};

4. 接口返回码

/** AndroidBitmap functions result code. */
enum {
/** Operation was successful. */
ANDROID_BITMAP_RESULT_SUCCESS = 0,
/** Bad parameter. */
ANDROID_BITMAP_RESULT_BAD_PARAMETER = -1,
/** JNI exception occured. */
ANDROID_BITMAP_RESULT_JNI_EXCEPTION = -2,
/** Allocation failed. */
ANDROID_BITMAP_RESULT_ALLOCATION_FAILED = -3,
};

5. 方法

/**
* 给定一个 java 的 bitmap 对象,获取到对应的 AndroidBitmapInfo 结构体
*/

int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info)
;

/**
* 将 addrPtr 指向图片的像素地址。这个方法会锁定图片的所有像素不能改变,直到调用AndroidBitmap_unlockPixels 方法
*/

int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);

/**
* 解除对图片像素的锁定
*/

int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);

三、实例操作

1. MainActivity

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;

import java.nio.Buffer;
import java.nio.ByteBuffer;

public class MainActivity extends Activity {

static {
System.loadLibrary("native-lib");
}

private static final String TAG = "MainActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
bitmap.eraseColor(0xff336699); // AARRGGBB
byte[] bytes = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
Buffer dst = ByteBuffer.wrap(bytes);
bitmap.copyPixelsToBuffer(dst);
// ARGB_8888 真实的存储顺序是 R-G-B-A
Log.d(TAG, "R: " + Integer.toHexString(bytes[0] & 0xff));
Log.d(TAG, "G: " + Integer.toHexString(bytes[1] & 0xff));
Log.d(TAG, "B: " + Integer.toHexString(bytes[2] & 0xff));
Log.d(TAG, "A: " + Integer.toHexString(bytes[3] & 0xff));
passBitmap(bitmap);
}

public native void passBitmap(Bitmap bitmap); // 传递一个 Bitmap 给 NDK

}

主要是创建一个 Bitmap 调用 passBitmap() 方法传递给 NDK。

2. native-lib.cpp

#include 
#include
#include "log.hpp"

extern "C" {

JNIEXPORT void JNICALL
Java_com_afei_myapplication_MainActivity_passBitmap(JNIEnv *env, jobject instance, jobject bitmap)
{
if (NULL == bitmap) {
LOGE("bitmap is null!");
return;
}
AndroidBitmapInfo info; // create a AndroidBitmapInfo
int result;
// 获取图片信息
result = AndroidBitmap_getInfo(env, bitmap, &info);
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
LOGE("AndroidBitmap_getInfo failed, result: %d", result);
return;
}
LOGD("bitmap width: %d, height: %d, format: %d, stride: %d", info.width, info.height,
info.format, info.stride);
// 获取像素信息
unsigned char *addrPtr;
result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void **>(&addrPtr));
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
LOGE("AndroidBitmap_lockPixels failed, result: %d", result);
return;
}
// 执行图片操作的逻辑
int length = info.stride * info.height;
for (int i = 0; i < length; ++i) {
LOGD("value: %x", addrPtr[i]);
}
// 像素信息不再使用后需要解除锁定
result = AndroidBitmap_unlockPixels(env, bitmap);
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
LOGE("AndroidBitmap_unlockPixels failed, result: %d", result);
}
}

}

主要是接收到 Bitmap 对象,并且打印出一些信息。

3. 运行结果

通过 JNI_LOG 我们可以看到,NDK 层的图片信息输出和 Java 层的是一致的。

四、编译的问题

注意,要使用 的话,必须要链接 jnigraphics 库,否则会报类似 undefined reference to ‘AndroidBitmap_getInfo’ 这样的错误。

1. CMakeLists.txt 中

target_link_libraries( # Specifies the target library.
native-lib

# 加上下面这一行
jnigraphics
# Links the target library to the log library
# included in the NDK.
${log-lib} )

2. Android.mk 中

LOCAL_LDLIBS += -ljnigraphics

————————————————

版权声明:本文为CSDN博主「阿飞__」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/afei__/article/details/81429417


推荐:

Android FFmpeg 实现带滤镜的微信小视频录制功能

全网最全的 Android 音视频和 OpenGL ES 干货,都在这了

抖音传送带特效是怎么实现的?

所有你想要的图片转场效果,都在这了

我用 OpenGL ES 给小姐姐做了几个抖音滤镜

浏览 83
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报