shyaway

Image processing > Add a bitmap header to an image buffer. 본문

.NET

Image processing > Add a bitmap header to an image buffer.

shyaway 2018. 8. 14. 00:04

Add a bitmap header to an image buffer


In image processing, converting a raw buffer data from an IP Camera via TCP or RTSP and a web camera via USB interface to BMP, JPG, PNG and such a thing is a common, yet basic job. However if you don't know about the file structures, you might have some difficult time handling with the raw buffer data. This stackoverflow question illustrates that quite well.


I have a buffer from a camera, how can I convert it to BMP?

I've googled on that but only examples I could find was for C++ and in my code, converting results in ParameterException.

What should I do?


The key solution is to look at the BMP file structure. It's well addressed here in Wikipedia. You can see the table below in that page and it is a description of 2x2 24bit bitmap image here.





OffsetSizeHex ValueValueDescription
BMP Header
0h242 4D"BM"ID field (42h, 4Dh)
2h446 00 00 0070 bytes (54+16)Size of the BMP file
6h200 00UnusedApplication specific
8h200 00UnusedApplication specific
Ah436 00 00 0054 bytes (14+40)Offset where the pixel array (bitmap data) can be found
DIB Header
Eh428 00 00 0040 bytesNumber of bytes in the DIB header (from this point)
12h402 00 00 002 pixels (left to right order)Width of the bitmap in pixels
16h402 00 00 002 pixels (bottom to top order)Height of the bitmap in pixels. Positive for bottom to top pixel order.
1Ah201 001 planeNumber of color planes being used
1Ch218 0024 bitsNumber of bits per pixel
1Eh400 00 00 000BI_RGB, no pixel array compression used
22h410 00 00 0016 bytesSize of the raw bitmap data (including padding)
26h413 0B 00 002835 pixels/metre horizontalPrint resolution of the image,
72 DPI × 39.3701 inches per metre yields 2834.6472
2Ah413 0B 00 002835 pixels/metre vertical
2Eh400 00 00 000 colorsNumber of colors in the palette
32h400 00 00 000 important colors0 means all colors are important
Start of pixel array (bitmap data)
36h300 00 FF0 0 255Red, Pixel (0,1)
39h3FF FF FF255 255 255White, Pixel (1,1)
3Ch200 000 0Padding for 4 byte alignment (could be a value other than zero)
3Eh3FF 00 00255 0 0Blue, Pixel (0,0)
41h300 FF 000 255 0Green, Pixel (1,0)
44h200 000 0Padding for 4 byte alignment (could be a value other than zero)


BMP Header

    • Offset 0~1 put 0x42, 0x4D Hex values respectably.
    • Offset 2~6 put BMP file size here. The headers will sum up as 54, and the current sample data size is 16, so it's going to be added up to 70 bytes. Converting 70 decimal value to hex will be 46 00 00 00.
    • Offset 6~8 This is application specific, normally put 0 here
    • Offset 8~10 This is application specific, normally put 0 here
    • Offset 10~14 put the offset of starting bitmap buffer array. I don't want to state the obvious, but it's of course the end of the header, thus it's 54 and the hex value would be 36 00 00 00.

DIB Header

    • Offset 14~18 Set the DIB header size. It's 40 constant from here.
    • Offset 18~22 Set the horizontal size of the BMP image. This sample is 2x2, 2pixel is the horizontal size.
    • Offset 22~26 Set the vertical size of the BMP image. This sample is 2x2, 2pixel is the vertical size.
    • Offset 26~28 Set the number of color planes. ( 1 : Red, 2 : Green, 3 : Blue => RGB )
    • Offset 28~30 Set number of bits per pixel if it's a 24bit bitmap, set 24.
    • Offset 30~34 Set BI_RGB value to compress the buffer data or not.
    • Offset 34~38 Set the size of the buffer, including padding values. It's going to be 16.
    • Offset 38~42 Set print resolution of the horizontal lines
    • Offset 42~46 Set print resolution of the vertical lines
    • Offset 46~50 Set the colors in the palette.
    • Offset 50~54 Set what's important color in this image. 0 means everything is important.

Start of pixel array ( bitmap data )

    • Offset 54~57 Set RGB value backwards. 00 00 FF means the Blue 0, the Green 0, the Red 255, that's why (0,1) position is tinged with the red color.
    • Offset inspect it as right above.
    • Offset It's a padding for keeping 4 bytes array order.
    • ~ going over and over again.

This verbose rule can be written as a code in C# like this below. If you are a developer, this will give you much clearer idea of how to do this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#region Bitmap Making...
 
// BmpBufferSize : a pure length of raw bitmap data without the header.
// the 54 value here is the length of bitmap header.
byte[] BitmapBytes = new byte[BmpBufferSize + 54];
 
#region Bitmap Header
// 0~2 "BM"
BitmapBytes[0] = 0x42;
BitmapBytes[1] = 0x4d;
 
// 2~6 Size of the BMP file - Bit cound + Header 54
Array.Copy(BitConverter.GetBytes(BmpBufferSize + 54), 0, BitmapBytes, 2, 4);
 
// 6~8 Application Specific : normally, set zero
Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 6, 2);
 
// 8~10 Application Specific : normally, set zero
Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 8, 2);
 
// 10~14 Offset where the pixel array can be found - 24bit bitmap data always starts at 54 offset.
Array.Copy(BitConverter.GetBytes(54), 0, BitmapBytes, 10, 4);
#endregion
 
#region DIB Header
// 14~18 Number of bytes in the DIB header. 40 bytes constant.
Array.Copy(BitConverter.GetBytes(40), 0, BitmapBytes, 14, 4);
 
// 18~22 Width of the bitmap.
Array.Copy(BitConverter.GetBytes(image.Width), 0, BitmapBytes, 18, 4);
 
// 22~26 Height of the bitmap.
Array.Copy(BitConverter.GetBytes(image.Height), 0, BitmapBytes, 22, 4);
 
// 26~28 Number of color planes being used
Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 26, 2);
 
// 28~30 Number of bits. If you don't know the pixel format, trying to calculate it with the quality of the video/image source.
if (image.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb)
{                       
    Array.Copy(BitConverter.GetBytes(24), 0, BitmapBytes, 28, 2);
}
 
// 30~34 BI_RGB no pixel array compression used : most of the time, just set zero if it is raw data.
Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 30, 4);
 
// 34~38 Size of the raw bitmap data ( including padding )
Array.Copy(BitConverter.GetBytes(BmpBufferSize), 0, BitmapBytes, 34, 4);
 
// 38~46 Print resolution of the image, 72 DPI x 39.3701 inches per meter yields
if (image.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb)
{
    Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 38, 4);
    Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 42, 4);
}
 
// 46~50 Number of colors in the palette
Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 46, 4);
 
// 50~54 means all colors are important
Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 50, 4);
 
// 54~end : Pixel Data : Finally, time to combine your raw data, BmpBuffer in this code, with a bitmap header you've just created.
Array.Copy(BmpBuffer as Array, 0, BitmapBytes, 54, BmpBufferSize);
 
#endregion - bitmap header process
#endregion - bitmap making process


As the bitmap header is well combined with the raw buffer data, you can now convert it to the Bitmap object in C#. You will always fail to change the raw data to Bitmap object unless you don't give the Bitmap object a proper bitmap header. It's a recipe for a bitmap image, you should always return it.


 



Comments