0
votes

I'm a bit puzzled with internal representation of Bitmap's pixels in ByteBuffer (testing on ARM/little endian):

1) In the Java layer I create an ARGB bitmap and fill it with 0xff112233 color:

Bitmap sampleBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(sampleBitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);

paint.setColor(Color.rgb(0x11,0x22, 0x33));
canvas.drawRect(0,0, sampleBitmap.getWidth(), sampleBitmap.getHeight(), paint);

To test, sampleBitmap.getPixel(0,0) indeed returns 0xff112233 that matches ARGB pixel format.

2) The bitmap is packed into direct ByteBuffer before passing to the native layer:

 final int byteSize = sampleBitmap.getAllocationByteCount();
 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(byteSize);
 //byteBuffer.order(ByteOrder.LITTLE_ENDIAN);// See below
 sampleBitmap.copyPixelsToBuffer(byteBuffer);

To test, regardless of the buffer's order setting, in the debugger I see the byte layout which doesn't quite match ARGB but more like a big endian RGBA (or little endian ABGR!?)

  byteBuffer.rewind();
  final byte [] out = new byte[4];
  byteBuffer.get(out, 0, out.length);
out = {byte[4]@12852} 
 0 = (0x11)
 1 = (0x22)
 2 = (0x33)
 3 = (0xFF)

Now, I'm passing this bitmap to the native layer where I must extract pixels and I would expect Bitmap.Config.ARGB_8888 to be represented, depending on buffer's byte order as:

a) byteBuffer.order(ByteOrder.LITTLE_ENDIAN):

out = {byte[4]@12852} 
 0 = (0x33)
 1 = (0x22)
 2 = (0x11)
 3 = (0xFF)

or

b) byteBuffer.order(ByteOrder.BIG_ENDIAN):

out = {byte[4]@12852} 
 0 = (0xFF)
 1 = (0x11)
 2 = (0x22)
 3 = (0x33)

I can make the code which extracts the pixels work based on above output but I don't like it since I can't explain the behaviour which I hope someone will do :)

Thanks!

1
I'm not sure I understand. The little-endian layout looks entirely correct to me. What were you expecting? - Michael
I'm expecting either a) or b). What I've got doesn't look like any ARGB layout but some variation of RGBA. - sinek
Ok. The documentation for Bitmap.Config.ARGB_8888 says "Use this formula to pack into 32 bits: int color = (A & 0xff) << 24 | (B & 0xff) << 16 | (G & 0xff) << 8 | (R & 0xff);" - Michael
Yah, that's apparently an issue: stackoverflow.com/questions/56832572/… - sinek
Also, that can be validated by bitmap.getPixel() which returns 0xff112233 (ARGB) as expected. - sinek

1 Answers

1
votes

Let's take a look at the implementation. Both getPixel and copyPixelsToBuffer just call their native counterparts. Bitmap_getPixels specifies an output format:

SkImageInfo dstInfo = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);

It effectively asks the bitmap to give the pixel value converted to BGRA_8888 (which becomes ARGB because of different native and java endianness).

Bitmap_copyPixelsToBuffer in its turn just copies raw data:

memcpy(abp.pointer(), src, bitmap.computeByteSize());

And does not have any conversion. It basically returns the data in the same format it uses to store it. Let's find out what this inner format is.

Bitmap_creator is used to create a new bitmap and it gets the format from the config passed by calling

SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);

Looking at the legacyBitmapConfigToColorType implementation, ARGB_8888 (which has index 5) becomes kN32_SkColorType.

kN32_SkColorType is from skia library, so looking at the definitions find the comment

kN32_SkColorType is an alias for whichever 32bit ARGB format is the 
"native" form for skia's blitters. Use this if you don't have a swizzle 
preference for 32bit pixels.

and below is the definition:

#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
    kN32_SkColorType = kBGRA_8888_SkColorType,
#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
    kN32_SkColorType = kRGBA_8888_SkColorType,

SK_PMCOLOR_BYTE_ORDER is defined here and it says SK_PMCOLOR_BYTE_ORDER(R,G,B,A) will be true on a little endian machine, which is our case. So it means the bitmap is stored in kRGBA_8888_SkColorType format internally.