In C # of Visual Studio 2019, output Bitmap object by hitting binary directly to Windows Bitmap file under Android environment. This is a sample code.

5 minute read

As the title says
Following the old Windows version
https://qiita.com/oyk3865b/items/58abd56c5c1edcc84118

This time
In C # of Visual Studio 2019
Under Android environment
Output the Bitmap object by hitting the binary directly into the Windows Bitmap file.
This is a code sample.

Especially with other plugins such as NuGet
It does not require a separate external dll.

In short, I’m hitting the binary directly as follows.
1. Write Bitmap pixel information to a binary array.
2. Write Bitmap header.
3. Write the Bitmap binary to a file according to the rules of multiples of 4.

In Android development environment
bitmap.Compress (Bitmap.CompressFormat.Png, 100, fos);
The image saving method called bitmap.Compress (Bitmap.CompressFormat.Bmp, 100, fos);
Because it cannot be used

With Android app
When you want to output in RGB888 / Bitmap format
Because I decided to write the Bitmap to a file by myself
I created it.

  • I am an amateur
    The code this time is dirty because it is limited to the minimum working part.
    There are many points that cannot be reached such as exception handling and release. Please note.
    If you actually refer to it, be sure to correct or add the necessary parts.

  • The operation is heavy because it uses a lot of memory.
    I don’t care about that.

The image below is an example of creating with the code this time.
参考画像
● Originally, the image in Bitmap format was imported (before conversion),
With the result (after conversion) output by this code
Binary comparison image

[Reference site]
Report 1 examining Bitmap data when touching it at the binary level

  • The link is to my blog. Please be careful.

clsBMPF.cs


using System;
using System.Collections.Generic;
using Android.Graphics;

    class clsBMPF
    {
        //Images are handled by ARGB8888
        Android.Graphics.Bitmap.Config bitmapConfig = Android.Graphics.Bitmap.Config.Argb8888;

        //■ Header information
        //http://oyk3865b.blog13.fc2.com/blog-entry-1394.html
        //△ Opening syntax=BfType(File type)------------------------------------------------------------------------------------------------------------
        readonly byte[] bmp_header_start = new byte[] { 0x42, 0x4D };


        //△ Object for header spacing------------------------------------------------------
        readonly byte[] bmp_1st_obj = new byte[] { 0, 0, 0, 0 };


        //△BfOffBits------------------------------------------------------
        readonly byte[] bmp_2nd_obj = new byte[] { 0x36, 0, 0, 0 };


        //△BiSize------------------------------------------------------
        readonly byte[] bmp_3rd_obj = new byte[] { 0x28, 0, 0, 0 };


        //△BiPlanes_BiBitCount------------------------------------------------------
        readonly byte[] bmp_4th_obj = new byte[] { 0x1, 0, 0x18, 0 };

        public void Output_Bitmap_Image(Bitmap bitmap, string Output_Path)
        {

            //Make your own Windows Bitmap
            //bitmap → Original data of the output image
            //Output_Path → Output path (overwrite in case of duplication)
            //https://qiita.com/oyk3865b/items/58abd56c5c1edcc84118

            //Unify the color settings to ARGB8888.
            //https://stackoverflow.com/questions/7320392/how-to-draw-text-on-image
            bitmap = bitmap.Copy(bitmapConfig, true);

            //Preparing for binary replacement of Bitmap
            //https://qiita.com/aymikmts/items/7139fa6c4da3b57cb4fc
            string err_str = "byteBuffer";
            Java.Nio.ByteBuffer byteBuffer = Java.Nio.ByteBuffer.Allocate(bitmap.ByteCount);
            err_str = "CopyPixelsToBuffer";
            bitmap.CopyPixelsToBuffer(byteBuffer);
            err_str = "Flip";
            byteBuffer.Flip();
            err_str = "bmparr";

            //Replacement of basic Bitmap with binary
            byte[] bmparr = new byte[byteBuffer.Capacity()];
            err_str = "Get";
            byteBuffer.Duplicate().Get(bmparr);
            err_str = "Clear";
            byteBuffer.Clear();


            //File size calculation(The width must be a multiple of 4)
            int width_size = bitmap.Width * 3; //Calculate the binary size of one line wide(Width px*3 colours)
                                           //After converting the width binary value to a multiple of 4, multiply the height px to calculate the main body size.
            Int32 bitmap_filesize = ((((width_size + 3) / 4) * 4) * bitmap.Height);
            //Stores all Bitmap file sizes that can be created
            Int32 bitmap_all_filesize = bitmap_filesize + 54; //Consume 54 bytes other than the main body such as the header


            //■ Initialization of output bmp binary
            //For binary storage of output bmp.
            List<byte> ary_bmp_file = new List<byte>();
            //Output bmp binary For storing the byte start position of each object.
            List<byte> ary_bmp_byte_head = new List<byte>();


            //■ Create and write a file
            //If the file exists, erase it before writing
            if (System.IO.File.Exists(Output_Path)) { System.IO.File.Delete(Output_Path); }

            using (System.IO.FileStream fs = new System.IO.FileStream(Output_Path,
                System.IO.FileMode.Create,
                System.IO.FileAccess.Write))
            {
                //◎ Writing at the beginning
                ary_bmp_file.AddRange(bmp_header_start);

                //◎ Storage of all file sizes(BfSize)
                //Convert file size value to byte array
                ary_bmp_byte_head.AddRange(BitConverter.GetBytes(bitmap_all_filesize));
                if (ary_bmp_byte_head.Count < 4)
                { //Be sure to make it 4 bytes.
                  //Fill the void with 0.
                    for (int i = ary_bmp_byte_head.Count + 1; i <= 4; i++)
                    {
                        ary_bmp_byte_head.Add(0);
                    }
                }
                ary_bmp_file.AddRange(ary_bmp_byte_head.ToArray()); //Add.
                ary_bmp_byte_head.Clear(); //Clear unnecessary information.

                //◎ Write 4 blank bytes
                ary_bmp_file.AddRange(bmp_1st_obj);

                //◎ Writing BfOffBits
                ary_bmp_file.AddRange(bmp_2nd_obj);

                //◎ Writing BiSize
                ary_bmp_file.AddRange(bmp_3rd_obj);


                //◎ Specify image width(BiWidth)
                //Convert width values to byte arrays
                ary_bmp_byte_head.AddRange(BitConverter.GetBytes(bitmap.Width));
                if (ary_bmp_byte_head.Count < 4)
                { //Be sure to make it 4 bytes.
                    for (int i = ary_bmp_byte_head.Count + 1; i <= 4; i++)
                    {
                        ary_bmp_byte_head.Add(0);
                    }
                }
                ary_bmp_file.AddRange(ary_bmp_byte_head); //Add.
                ary_bmp_byte_head.Clear(); //Clear unnecessary information.


                //◎ Specifying the image height(BiHeight)
                //Convert height value to byte array
                ary_bmp_byte_head.AddRange(BitConverter.GetBytes(bitmap.Height));
                if (ary_bmp_byte_head.Count < 4)
                {    //Be sure to make it 4 bytes.
                    for (int i = ary_bmp_byte_head.Count + 1; i <= 4; i++)
                    {
                        ary_bmp_byte_head.Add(0);
                    }
                }
                ary_bmp_file.AddRange(ary_bmp_byte_head); //Add.
                ary_bmp_byte_head.Clear(); //Clear unnecessary information.

                //◎BiPlanes_Writing BiBitCount
                ary_bmp_file.AddRange(bmp_4th_obj);

                //◎ Write 4 blank bytes
                ary_bmp_file.AddRange(bmp_1st_obj);

                //◎ Storage of image file size(BiSizeImage)
                //Convert file size value to byte array
                ary_bmp_byte_head.AddRange(BitConverter.GetBytes(bitmap_filesize));
                for (int i = ary_bmp_byte_head.Count + 1; i <= 4; i++)
                {
                    ary_bmp_byte_head.Add(0);
                }
                ary_bmp_file.AddRange(ary_bmp_byte_head); //Add.
                ary_bmp_byte_head.Clear(); //Clear unnecessary information.

                //◎ Write 4 blank bytes x 4
                for (int i = 0; i < 4; i++)
                {
                    ary_bmp_file.AddRange(bmp_1st_obj);
                }

                //Write the contents of the byte array to a file once
                fs.Write(ary_bmp_file.ToArray(), 0, ary_bmp_file.Count);

                //Clear the array once.
                ary_bmp_file.Clear();
                //■ Creating headers------------So far-----------------

                //Bitmap writes from the bottom left
                for (int bmp_y = bitmap.Height - 1; bmp_y >= 0; bmp_y--)
                { //Longitudinal loop(From below)

                    //Copy the width to the array.
                    //This copy part may be a copy of the array instead of a loop.
                    for (int bmp_x = 0; bmp_x <= (bitmap.Width - 1); bmp_x++)
                    {   //Loop for the horizontal axis(From the left)
                        //Gets the color of the pixel (dot) at that coordinate point.
                        long pos = bmp_y * (bitmap.Width * 4) + bmp_x * 4;
                        //ary_bmp_file.Add(bmparr[pos + 3]); //A is output in RGB888 format, so it cannot be entered.
                        ary_bmp_file.Add(bmparr[pos + 2]); //R
                        ary_bmp_file.Add(bmparr[pos + 1]); //G
                        ary_bmp_file.Add(bmparr[pos + 0]); //B
                    }

                    //If not a multiple of 4
                    if (ary_bmp_file.Count % 4 != 0)
                    {
                        //The horizontal direction shall be a multiple of 4.
                        while ((ary_bmp_file.Count % 4) != 0)
                        {
                            ary_bmp_file.Add(0); //Fill with 0
                        }
                    }


                    //Write the contents of the byte array to a file once
                    fs.Write(ary_bmp_file.ToArray(), 0, ary_bmp_file.Count);


                    //Clear the array once.
                    ary_bmp_file.Clear();
                }


                //■ Post-processing of writing
                fs.Close(); //Close file
            }

            //Free up occupancy of binary memory.
            ary_bmp_file.Clear();
            ary_bmp_file = null;

            ary_bmp_byte_head.Clear();
            ary_bmp_byte_head = null;


            //Image release
            Array.Clear(bmparr,0, bmparr.Length);
            bmparr = null;
            if (bitmap != null) { bitmap.Dispose(); }
            bitmap  = null;

            
        }
    }