NDK를 이용한 네이티브 코드 사용에는 다음과 같은 구조를 가진다. 예를 들어,
public native boolean nativeString(Bitmap bitmap); |
우선 이렇게 간단한 메소드를 별도로 구현했다. 이 메소드가 속한 클래스는 안드로이드 스튜디오의 [New Module>Android Library]를 이용해서 새로운 모듈로 만들어 별도로 만들어 두었다.
전문은 다음과 같다
package com.example.ndklib; import android.graphics.Bitmap; public class NativeCode { static { System.loadLibrary("ndklib"); } public native boolean nativeString(Bitmap bitmap); } |
여기서 ndklib가 이 모듈의 이름, NativeCode가 자바 클래스 파일 이름이다.
해당 클래스를 사용하기 위해 Android.mk 파일은 다음과 같다.
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ndklib FILES := NativeCode.cpp LOCAL_SRC_FILES := $(FILES) LOCAL_LDLIBS := -llog -ljnigraphics include $(BUILD_SHARED_LIBRARY) |
위에서도 볼 수 있듯이, 그래픽 처리를 이용하므로, 로드 라이브러리에 –ljnigraphics를 포함시킨 것을 알 수 있다.
해당 되는 함수의 구현은 C++코드로 구현한다.
#include "com_example_ndklib_NativeCode.h" . . . |
코드를 하나씩 살펴보도록 하자.
int bmpData = AndroidBitmap_getInfo(env, bmp, &info); |
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info);
함수를 이용해서 Bitmap의 info를 호출하였다. Java의 Bitmap이 Object로 넘어오고, 이를 인자로 활용한다. 이때 리턴값은 성공 시0, 실패 시 음수이다.
/** AndroidBitmap functions result code. */ |
정확한 리턴값은 위와 같은데, 여기서 이 값들이 각각 문자열로 define 되어있으므로, 가독성을 위해 이를 사용한다.
if (bmpData != ANDROID_BITMAP_RESULT_SUCCESS) { |
성공하지 않으면 로그를 띄우고 리턴.
성공했다면 이 bitmap의 호출이 성공한 것이므로 Argument로 쓴 AndroidBitmapInfo의 구조가 다음과 같게 된다.
typedef struct { |
이후 픽셀데이터의 포인터를 가져오는 함수인
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
이것을 이용해 작업을 하고, 이를 자바에서 다시 쓸 수 있도록 해제함수인
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
이 함수를 이용해서 작업을 끝내면 된다. 전체 함수의 구조는 이런 식으로 이루어진다.
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr); |
AndroidBitmap_lockPixels은 호출에 성공하면 addrPtr에 픽셀 주소가 set된다.
AndroidBitmap_getInfo와 AndroidBitmap_lockPixels의 호출이 끝나면 이제, 각 픽셀에 접근할 수 있다.
AndroidBitmap_lockPixels의 addrPtr 부분에 (void**)&pBmp를 사용했으므로, pBmp에는 픽셀 주소가 위치할 것이다. 구조는 다음과 같다.
Pixel |
(0,0) |
(0,1) |
(0,2) |
… |
|||||||||
uint8_t |
R |
G |
B |
A |
R |
G |
B |
A |
R |
G |
B |
A |
*R=Red, G=Green, B=Blue, A=Alpha(투명도)
특정 픽셀에 접근하기 위해 다음과 같은 형태로 uint8_t의 포인터 변수를 선언하고 이 변수가 특정 픽셀을 가리키도록 만들면 된다.
우리가 찾고 싶은 좌표가 (X, Y) 일 때, 해당 픽셀의 R값의 포인터는
pBmp + (Y) * info.stride + (X) * 4;
여기서 info.stride는 열 당 바이트 개수이다. 폰을 실행했을 때 해상도가 1080X2340라면,
info.stride는 1080*4, 즉 4320이다.
uint8_t *checkPixel = pBmp + (X) * info.stride + (Y)*4; |
이제 원하는 픽셀 위치를 checkPixel이 가리키고 있으니, 하고 싶은 연산을 하고 마지막으로 unlockPixels을 호출해주면 된다.
AndroidBitmap_unlockPixels(env, bmp); |
Object인 bmp는 자바에서 할 연산이 남아있으므로 lock을 풀고, 리턴을 하면 된다.
'안드로이드' 카테고리의 다른 글
Android SDK 설정 이후 사용예시 (0) | 2020.04.14 |
---|---|
Android NDK 사용법 (0) | 2020.04.14 |