开发者

Native bitmap processing and ALPHA_8

开发者 https://www.devze.com 2023-04-10 15:25 出处:网络
I\'m trying to convert an image to grayscale through a native function, using a piece of code taken from Android in Action (2nd ed.; you can also see it here). Unfortunately, the returned bitmap objec

I'm trying to convert an image to grayscale through a native function, using a piece of code taken from Android in Action (2nd ed.; you can also see it here). Unfortunately, the returned bitmap object, instead of grayscale, ends up empty.

This is how I load the (.png) image:

Bitmap original = BitmapFactory.decodeResource(this.getResources(), R.drawable.sample, options);

There is a number of safety conditions that the bitmap passes (please check below). Here's the native function definition in Java:

public native void convertToGray(Bitmap bitmapIn,Bitmap bitmapOut);

and the call:

// Grayscale bitmap (initially empty)     
Bitmap gray = Bitmap.createBitmap(original.getWidth(),original.getHeight(),Config.ALPHA_8);
// Native function call
convertToGray(original,gray);

And here's the function:

JNIEXPORT void JNICALL Java_com_example_Preprocessor_convertToGray(JNIEnv * env, jobject  obj, jobject bitmapcolor,jobject bitmapgray)
{
    AndroidBitmapInfo infocolor;
    AndroidBitmapInfo infogray; 
    void* pixelscolor;
    void* pixelsgray;
    int ret;
    int y;
    int x;    

    LOGI("convertToGray");
    if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }    

    if ((ret = AndroidBitmap_getInfo(env, bitmapgray, &infogray)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    LOGI("color image :: width is %d; height is %d; stride is %d; format is %d;flags is %d",infocolor.width,infocolor.height,infocolor.stride,infocolor.format,infocolor.flags);
    if (infocolor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888 !");
        return;
    }  

    LOGI("gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d",infogray.width,infogray.height,infogray.stride,infogray.format,infogray.flags);
    if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) {
        LOGE("Bitmap format is not A_8 !");
        return;
    }   

    if ((ret = AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, &pixelsgray)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    // modify pixels with image processing algorithm
    for (y=0;y<infocolor.heigh开发者_运维问答t;y++) {
        argb * line = (argb *) pixelscolor;
        uint8_t * grayline = (uint8_t *) pixelsgray;
        for (x=0;x<infocolor.width;x++) {
            grayline[x] = 0.3 * line[x].red + 0.59 * line[x].green + 0.11*line[x].blue;
        }

        pixelscolor = (char *)pixelscolor + infocolor.stride;
        pixelsgray = (char *) pixelsgray + infogray.stride;
    }

    LOGI("Done! Unlocking pixels...");
    AndroidBitmap_unlockPixels(env, bitmapcolor);
    AndroidBitmap_unlockPixels(env, bitmapgray);
}

The color bitmap gets passed correctly, and the processing part of the code appears to be working fine, but bitmapgray stays empty. I guess I'm missing something crucial here.

Test environment: emulator, v2.2. With this version, the function works when the native code is called from the main thread. On a 2.3 emulator, the function doesn't work regardless of the thread that calls the C code, or the way the bitmap is loaded. Android NDK: 4b & 6b.

UPDATE #1: You'll find the complete source code here.

UPDATE #2: RGB_565 instead of ALPHA_8 gives some results. It appears not even setPixels() in Java works for ALPHA_8, and I'm having problems finding info on this config type. Any kind of help would be much appreciated.


I had similar problem. First of all, I used android RGBA_8888 format for infogray instead of A_8 (the original bitmap was created using ARGB_8888 format). Then if you use argb struct for grayline instead of uint_8, you can fill the pixels like this:

for (y = 0; y < infocolor.height; ++y) {
       argb* line = (argb*) pixelscolor;
       argb* grayline = (argb*) pixelsgray;
       for (x = 0; x < infocolor.width; ++x) {         
          grayline[x].red = grayline[x].green = grayline[x].blue = 0.3 * line[x].red + 0.59 * line[x].green + 0.11 * line[x].blue;
       }
       pixelscolor = (char*)pixelscolor + infocolor.stride;
       pixelsgray = (char*)pixelsgray + infogray.stride;
   }


i had the same problems. I did not try much to make ALPHA_8 work but using ARGB_8888 fixes the problem.

Btw, in reply to @white_pawn's comment (sorry i cannot reply to comments)

The argb struct in IBM's example is in wrong order. in my emulators or phone, converting it to RGBA fixes the issue (this is probably the reason why your image looks blue because you use alpa for blue). Though I'm not sure if this order is hardware dependent.

typedef struct
{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    uint8_t alpha;
} argb;


I had the same problem and found what went wrong! When you use APHA_8 you need to change background to #ffffffff,

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff">
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号