1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Debug/BsBitmapWriter.h"
4
5namespace bs
6{
7#pragma pack(push, 2) // Align to 2byte boundary so we don't get extra 2 bytes for this struct
8
9 struct BMP_HEADER
10 {
11 UINT16 BM;
12 UINT32 size_of_file;
13 UINT32 reserve;
14 UINT32 offset_of_pixel_data;
15 UINT32 size_of_header;
16 UINT32 width;
17 UINT32 hight;
18 UINT16 num_of_color_plane;
19 UINT16 num_of_bit_per_pix;
20 UINT32 compression;
21 UINT32 size_of_pix_data;
22 UINT32 h_resolution;
23 UINT32 v_resolution;
24 UINT32 num_of_color_in_palette;
25 UINT32 important_colors;
26
27 };
28
29#pragma pack(pop)
30
31 void BitmapWriter::rawPixelsToBMP(const UINT8* input, UINT8* output, UINT32 width, UINT32 height, UINT32 bytesPerPixel)
32 {
33 UINT16 bmpBytesPerPixel = 3;
34 if(bytesPerPixel >= 4)
35 bmpBytesPerPixel = 4;
36
37 UINT32 padding = (width * bmpBytesPerPixel) % 4;
38 if(padding != 0)
39 padding = 4 - padding;
40
41 UINT32 rowPitch = (width * bmpBytesPerPixel) + padding;
42 UINT32 dataSize = height * rowPitch;
43
44 BMP_HEADER header;
45 header.BM = 0x4d42;
46 header.size_of_file = sizeof(header) + dataSize;
47 header.reserve = 0000;
48 header.offset_of_pixel_data = 54;
49 header.size_of_header = 40;
50 header.width = width;
51 header.hight = height;
52 header.num_of_color_plane = 1;
53 header.num_of_bit_per_pix = bmpBytesPerPixel * 8;
54 header.compression = 0;
55 header.size_of_pix_data = dataSize;
56 header.h_resolution = 2835;
57 header.v_resolution = 2835;
58 header.num_of_color_in_palette = 0;
59 header.important_colors = 0;
60
61 // Write header
62 memcpy(output, &header, sizeof(header));
63 output += sizeof(header);
64
65 // Write bytes
66 UINT32 widthBytes = width * bytesPerPixel;
67
68 // BPP matches so we can just copy directly
69 if(bmpBytesPerPixel == bytesPerPixel)
70 {
71 for(INT32 y = height - 1; y >= 0 ; y--)
72 {
73 UINT8* outputPtr = output + y * rowPitch;
74
75 memcpy(outputPtr, input, widthBytes);
76 memset(outputPtr + widthBytes, 0, padding);
77
78 input += widthBytes;
79 }
80 }
81 else if(bmpBytesPerPixel < bytesPerPixel) // More bytes in source than supported in BMP, just truncate excess data
82 {
83 for(INT32 y = height - 1; y >= 0 ; y--)
84 {
85 UINT8* outputPtr = output + y * rowPitch;
86
87 for(UINT32 x = 0; x < width; x++)
88 {
89 memcpy(outputPtr, input, bmpBytesPerPixel);
90 outputPtr += bmpBytesPerPixel;
91 input += bytesPerPixel;
92 }
93
94 memset(outputPtr, 0, padding);
95 }
96 }
97 else // More bytes in BMP than in source (BMP must be 24bit minimum)
98 {
99 for(INT32 y = height - 1; y >= 0 ; y--)
100 {
101 UINT8* outputPtr = output + y * rowPitch;
102
103 for(UINT32 x = 0; x < width; x++)
104 {
105 memcpy(outputPtr, input, bytesPerPixel);
106
107 // Fill the empty bytes with the last available byte from input
108 UINT32 remainingBytes = bmpBytesPerPixel - bytesPerPixel;
109 while(remainingBytes > 0)
110 {
111 memcpy(outputPtr + (bmpBytesPerPixel - remainingBytes), input, 1);
112 remainingBytes--;
113 }
114
115 outputPtr += bmpBytesPerPixel;
116 input += bytesPerPixel;
117 }
118
119 memset(outputPtr, 0, padding);
120 }
121 }
122 }
123
124 UINT32 BitmapWriter::getBMPSize(UINT32 width, UINT32 height, UINT32 bytesPerPixel)
125 {
126 UINT16 bmpBytesPerPixel = 3;
127 if(bytesPerPixel >= 4)
128 bmpBytesPerPixel = 4;
129
130 UINT32 padding = (width * bmpBytesPerPixel) % 4;
131 if(padding != 0)
132 padding = 4 - padding;
133
134 UINT32 rowPitch = (width * bmpBytesPerPixel) + padding;
135 UINT32 dataSize = height * rowPitch;
136
137 return sizeof(BMP_HEADER) + dataSize;
138 }
139}