jenovachild jenovachild - 1 month ago 18
Android Question

Converting RAW byte data to Bitmap

I am taking a screenshot of an android device using ADB and receiving the screenshot as raw byte data.

I know the raw byte data coming through is in the format rgba

Red is offset 0, Green offset 8, Blue offset 16, Alpha offset 24, each value is 1 byte. This makes up the entire byte array.

I am trying to convert this byte array to a Bitmap in C# and it is working for the most part, the image looks correct in every way apart from the fact that it is coming through with a 'blue hue' -- the coloring is off.

The following is the code I'm using to convert my raw byte data:

int WriteBitmapFile(string filename, int width, int height, byte[] imageData)
{
using (var stream = new MemoryStream(imageData))
using (var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
bmp.Width,
bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);
IntPtr pNative = bmpData.Scan0;

Marshal.Copy(imageData, 0, pNative, imageData.Length);

bmp.UnlockBits(bmpData);

bmp.Save(filename);
}

return 1;
}


I've read in this post that it could be to do with the byte order of the actual rgba values. As you can see in the code above, I tried casting my bmpData.Scan0 to int* and it is still coming through with a blue hue.

I'm wracking my brain as to what I can do now to get this image to come through with the correct colors. I'm assuming it's reading red as blue and blue as red or vice versa.

I thought I could manipulate the raw byte data so that it is in the correct byte order when converting it to a bitmap, however I'm not sure how I can go about doing that.

Any suggestions?

Answer

So, in the end my solution was simple.

int WriteBitmapFile(string filename, int width, int height, byte[] imageData)
    {
        byte[] newData = new byte[imageData.Length];

        for(int x = 0; x < imageData.Length; x+= 4)
        {
            byte[] pixel = new byte[4];
            Array.Copy(imageData, x, pixel, 0, 4);

            byte r = pixel[0];
            byte g = pixel[1];
            byte b = pixel[2];
            byte a = pixel[3];

            byte[] newPixel = new byte[] { b, g, r, a };

            Array.Copy(newPixel, 0, newData, x, 4);
        }

        imageData = newData;

        using (var stream = new MemoryStream(imageData))
        using (var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb))
        {
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
                                                            bmp.Width,
                                                            bmp.Height),
                                              ImageLockMode.WriteOnly,
                                              bmp.PixelFormat);

            IntPtr pNative = bmpData.Scan0;
            Marshal.Copy(imageData, 0, pNative, imageData.Length);

            bmp.UnlockBits(bmpData);

            bmp.Save(filename);
        }

        return 1;
    }

All I had to do was loop through the imageData and adjust the bytes that made up the pixels and re-order them so that they would suit the expected format for windows bitmap which is BGRA.

Obviously, I can still make some small optimisations in the for loop that shifts the bytes around, but it's working.