1

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?

Community
  • 1
  • 1
jenovachild
  • 1,671
  • 2
  • 14
  • 12

2 Answers2

5

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.

jenovachild
  • 1,671
  • 2
  • 14
  • 12
0

Did you have a look at this post ? You're stating that every 'value' is 8 bytes, so 1 pixel is 4x8 = 32 bytes? But you are using 32bpp image format, so 32 bits per pixel -> 1 pixel = 4 bytes.

Also pay attention to little/big endian, if you're acquiring the image from another processor/network/...

Community
  • 1
  • 1
RuudSieb
  • 523
  • 5
  • 13
  • I've updated my question, each color value is 1 byte, totalling 32bpp. The other issue with that post you linked is that it allows screen capture for your own app, whereas I require the ability to capture the screen regardless of the apps running. Besides, that I'm already capable of doing this, however it requires me to first save the screencap to the device and then pull it across to PC. I would rather grab the raw byte data and transfer it directly to PC without having to write to the device disk. – jenovachild Oct 07 '16 at 06:51
  • @jenovachild, ok, then i would look into endianess, specially since youre using an IntPtr to read the data, which would reverse the endianess. See also http://stackoverflow.com/questions/580666/why-do-my-images-seem-to-be-in-the-format-of-bgra-instead-of-argb – RuudSieb Oct 07 '16 at 07:12