Mitrescu Catalin
Mitrescu Catalin

Reputation: 131

ALPHA_8 bitmaps and getPixel

I am trying to load a movement map from a PNG image. In order to save memory after I load the bitmap I do something like that.

 
 `Bitmap mapBmp = tempBmp.copy(Bitmap.Config.ALPHA_8, false);` 
 

If I draw the mapBmp I can see the map but when I use getPixel() I get always 0 (zero).

Is there a way to retrieve ALPHA information from a bitmap other than with getPixel() ?

Upvotes: 8

Views: 5205

Answers (4)

Jernej Lavbic
Jernej Lavbic

Reputation: 11

I developed solution with PNGJ library, to read image from assets and then create Bitmap with Config.ALPHA_8.

import ar.com.hjg.pngj.IImageLine;
import ar.com.hjg.pngj.ImageLineHelper;
import ar.com.hjg.pngj.PngReader;

public Bitmap getAlpha8BitmapFromAssets(String file) {

    Bitmap result = null;

    try {

        PngReader pngr = new PngReader(getAssets().open(file));
        int channels = pngr.imgInfo.channels;
        if (channels < 3 || pngr.imgInfo.bitDepth != 8)
            throw new RuntimeException("This method is for RGB8/RGBA8 images");

        int bytes = pngr.imgInfo.cols * pngr.imgInfo.rows;
        ByteBuffer buffer = ByteBuffer.allocate(bytes);

        for (int row = 0; row < pngr.imgInfo.rows; row++) { 

            IImageLine l1 = pngr.readRow();

            for (int j = 0; j < pngr.imgInfo.cols; j++) {

                int original_color = ImageLineHelper.getPixelARGB8(l1, j);

                byte x = (byte) Color.alpha(original_color);

                buffer.put(row * pngr.imgInfo.cols + j, x ^= 0xff);

            }

        }

        pngr.end();

        result = Bitmap.createBitmap(pngr.imgInfo.cols,pngr.imgInfo.rows, Bitmap.Config.ALPHA_8);
        result.copyPixelsFromBuffer(buffer);

    } catch (IOException e) {
        Log.e(LOG_TAG, e.getMessage());
    }

    return result;

}

I also invert alpha values, because of my particular needs. This code is only tested for API 21.

Upvotes: 1

nibarius
nibarius

Reputation: 4117

I found this question from Google and I was able to extract the pixels using the copyPixelsToBuffer() method that Mitrescu Catalin ended up using. This is what my code looks like in case anyone else finds this as well:

public byte[] getPixels(Bitmap b) {
    int bytes = b.getRowBytes() * b.getHeight();
    ByteBuffer buffer = ByteBuffer.allocate(bytes);
    b.copyPixelsToBuffer(buffer);
    return buffer.array();
}

If you are coding for API level 12 or higher you could use getByteCount() instead to get the total number of bytes to allocate. However if you are coding for API level 19 (KitKat) you should probably use getAllocationByteCount() instead.

Upvotes: 2

usethe4ce
usethe4ce

Reputation: 23819

Seems to be an Android bug in handling ALPHA_8. I also tried copyPixelsToBuffer, to no avail. Simplest workaround is to waste lots of memory and use ARGB_8888.

Issue 25690

Upvotes: 5

Mitrescu Catalin
Mitrescu Catalin

Reputation: 131

I was able to find a nice and sort of clean way to create boundary maps. I create an ALPHA_8 bitmap from the start. I paint my boundry map with paths. Then I use the copyPixelsToBuffer() and transfer the bytes into a ByteBuffer. I use the buffer to "getPixels" from. I think is a good solution since you can scale down or up the path() and draw the boundary map at the desired screen resolution scale and no IO + decode operations. Bitmap.getPixel() is useless for ALPHA_8 bitmaps, it always returns 0.

Upvotes: 1

Related Questions