Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Native bitmap processing and ALPHA_8

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.height;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.

like image 541
white_pawn Avatar asked Oct 01 '11 22:10

white_pawn


People also ask

What are bitmaps in Android?

A bitmap is simply a rectangle of pixels. Each pixel can be set to a given color but exactly what color depends on the type of the pixel. The first two parameters give the width and the height in pixels. The third parameter specifies the type of pixel you want to use.

What is ARGB_8888?

public static final Bitmap.Config ARGB_8888. Each pixel is stored on 4 bytes. Each channel (RGB and alpha for translucency) is stored with 8 bits of precision (256 possible values.) This configuration is very flexible and offers the best quality. It should be used whenever possible.

How do I know if my Android BMP is empty?

You can do a check when you want to return the BitMap look to see if the ArrayList of Paths is bigger than 0 and return the BitMap if so, or else return null.

What is bitmap Java?

A bitmap is a mapping from one system such as integers to bits. It is also known as bitmap index or a bit array. The memory is divided into units for bitmap. These units may range from a few bytes to several kilobytes. Each memory unit is associated with a bit in the bitmap.


2 Answers

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;
   }
like image 179
dianull Avatar answered Oct 14 '22 13:10

dianull


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;
like image 28
yigit Avatar answered Oct 14 '22 12:10

yigit