Tistory View

Android Develop/image

Android NDK Access memory of Bitmap directly

God Dangchy What should I do? 2019. 8. 5. 18:59

To access bitmap(android.graphics.Bitmap) pixels, getPixel/setPixel/setPixels/getPixels of Bitmap can be used. but, this operation is too slow, Android NDK support to access memory of bitmap directly.

By this method can access memory directly, You can use other C graphic library such as gd and so on and This is very fast.

 

Usage

include file is <android/bitmap.h> and send "-ljnigraphics" to linker to link this library.

 

Next code shows how to add this library, if you are using CMakeLists.txt, add "-ljnigraphics" inside of 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 )

 

 

All functions in this library returns C-Style value, On success, returns Zero, Otherwise, returns Non-zero value. In <android/bitmap.h>, Success value, Zero, is defined as ANDROID_BITMAP_RESULT_SUCCESS, Failure return values are defined as negative. Other codes in the world use next snippet to check whether success or not.

if( AndroidBitmap_getInfo( env, bmp, &info ) < 0 ) {
	// process on faiure
}

But, I recommend use next snippet, Just because this code is easy to understand.

if( ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo( env, bmp, &info ) ) {
	// procces on failure
}

 

In this bitmap library has only 3 functions, This is sufficient to use Bitmap memory direclty.

 

Getting Bitmap information of demensions and format.

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

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;

 

Supported formats

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,
};

Sometimes, The format value has ANDROID_BITMAP_FORMAT_NONE even if a valid Bitmap, I can't remember this situations....(In this case, Regenerate bitmap by copying in Java )

 

The function for getting Pixel ptr.

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

 

 

When done, You must unlock bitmap.

int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);

 

Typical code skeleton as next.

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

    }

	// unlock, if locking is processed
    if( pBmp ) {
    	AndroidBitmap_unlockPixels( env, bmp );
    }

    return rc;
}

Pixel Bytes Order has RGBA in LITTLE ENDIAN, I didn't test on BIG ENDIAN devices by absence of those.

If you want not to be care ENDIAN, You can use int. pointer[0xABGR].(Not comfirmed)

 

 

 

Result Bitmap of above code

 

 

 

 

 

Replies
Reply Write