Tistory View
Bitmap(android.graphics.Bitmap)의 픽셀단위로 처리하고 싶은 경우 getPixel/setPixel/setPixels/getPixels를 이용해야 한다. 하지만 이 처리는 java로 처리하기에는 속도가 너무 느리다. Android NDK에서는 이 처리를 위해 비트맵의 메모리에 직접 접근할 수 있는 방법을 제공하고 있다.
메모리에 직접접근이 가능하기 때문에, C로 미리 만들어진 그래픽라이브러리도 바로 사용이 가능한 장점이 있으며, 무엇보다도 빠른 속도로 처리할 수 있다.
사용법은 다음과 같다.
header파일은 <android/bitmap.h>를 include하고 library는 jnigraphics다. 링커에게 "-lJnigraphics"를 전달해 주면 된다.
다음의 코드는 CMakeLists.txt파일을 이용할 경우 target_link_libraries에 다음과 같이 넣으면 된다.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
-ljnigraphics )
뭐.. 링크하지 않으면 undefined/unresolved function이 나오겠지만......뭐..
여기서 사용되는 함수들은 C-Type의 리턴값을 쓴다. 성공할 경우 0을 리턴하게되고 실패시 0이 아닌 값을 리턴하게 된다. <android/bitmap.h> 파일을 보면 성공값인 0은 ANDROID_BITMAP_RESULT_SUCCESS로 define되어 있으며, 실패는 모두 음수값으로 지정되어 있다. 이 것을 이용한 다른 소스들을 보면 실패를 검사하기 위해 다음과 같이 작성한 코드가 많이 있다.
if( AndroidBitmap_getInfo( env, bmp, &info ) < 0 ) {
//실패 처리
}
하지만 필자는 다음과 같이 사용할 것을 권장한다. 뭐 특별한 이유는 없고 알아보기 쉬우니..
if( ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo( env, bmp, &info ) ) {
//실패 처리
}
지원함수는 꼴랑 3개뿐이지만, 우리는 메모리에 직접 접근하는 것이 목적이니 이것으로 충분하다.
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info);
비트맵정보를 가지고 온다. Bitmap의 크기와 format을 알 수 있다.
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;
지원하는 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,
};
가끔 정상적인 Bitmap도 ANDROID_BITMAP_FORMAT_NONE이 나올 때가 있는 데... 언젠지 기억이 안난다.
(이럴 경우, Java에서 Bitmap을 다시 만들어서 처리했던 기억이 있다. )
픽셀데이터의 pointer를 가지고 오는 함수
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
다 사용 했으면 다시 java에서 쓸 수 있게 lock을 풀어 줘야 한다.
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
따라서 보통 사용할 때는 다음의 구조를 갖는다.
java code
class YourClass {
.
.
.
.
private native boolean func( Bitmap bmp );
}
jni code
#include <android/bitmap.h>
extern "C" JNIEXPORT jboolean JNICALL
Java_com_package_name_YourClass_func( JNIEnv *env, jobject _this, jobject bmp )
{
assert( bmp );
int rcc;
jboolean rc = JNI_FALSE;
AndroidBitmapInfo info;
uint8_t* pBmp = NULL;
try {
rcc = AndroidBitmap_getInfo( env, bmp, &info );
if( rcc != ANDROID_BITMAP_RESULT_SUCCESS ) {
throw "get Bitmap Info failure";
}
if( info.format != ANDROID_BITMAP_FORMAT_RGBA_8888 ) {
throw "only ARGB888 format support";
}
rcc = AndroidBitmap_lockPixels( env, bmp, (void**)&pBmp );
if( rcc != ANDROID_BITMAP_RESULT_SUCCESS ) {
throw "lockPixels failure";
}
for( int y = 0 ; y < info.height ; y++ ) {
uint8_t* px = pBmp + y * info.stride;
for( int x = 0 ; x < info.width ; x++ ) {
px[0] = uint8_t( ( (float)x / info.width ) * 255.0f ); // R
px[1] = uint8_t( ( (float)y / info.height ) * 255.0f ); // G
px[2] = 0x00; // B
px[3] = 0xff; // A
px += 4;
}
}
rc = JNI_TRUE;
}
catch( const char* e ) {
}
// lock이 제대로 처리된 경우 unlock해준다.
if( pBmp ) {
AndroidBitmap_unlockPixels( env, bmp );
}
return rc;
}
픽셀의 순서는 LITTLE ENDIAN기준으로 RGBA순서를 같는다. BIG ENDIAN의 경우는 기기가 없어서 테스트는 못 해봤다.
ENDIAN에 신경쓰지 않으려면 int의 pointer로 처리하면 된다. [0xABGR]로 처리하면 된다.(이 것도 확인 못했다)
'Android Develop > image' 카테고리의 다른 글
안드로이드 ImageView의 ScaleType (0) | 2019.12.04 |
---|---|
Android YV12, stride and RGB conversion (0) | 2019.08.06 |
안드로이드 YV12, stride와 RGB 변환 (4) | 2019.08.06 |
Android NDK Access memory of Bitmap directly (5) | 2019.08.05 |
늘 괴롭히는 이미지의 stride (2) | 2017.10.30 |
- Total
- Today
- Yesterday
- ComputeShader
- 텍스처
- TTS
- 경제보복
- 애드핏
- Android
- 아끼는 법
- 안드로이드
- gpgpu
- 애드센스
- 전기세
- 적금
- choreographer
- 공유 컨텍스트
- 재태크
- 에어콘
- 사용료
- OpenGLes
- OpenGL ES
- 재테크
- 컴퓨트쉐이더
- 블로그
- 티스토리
- 에어컨
- 컴퓨트셰이더
- 전기요금
- 예금
- 전기료
- 금리
- texture
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |