bmp.h
9.88 KB
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#ifndef STIM_BMP_H
#define STIM_BMP_H
namespace stim {
#pragma pack(1)
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef signed int LONG;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
const unsigned int DIB_BITMAPCOREHEADER = 12;
const unsigned int DIB_OS21XBITMAPHEADER = 16;
const unsigned int DIB_BITMAPINFOHEADER = 40;
const unsigned int DIB_BITMAPV2INFOHEADER = 52;
const unsigned int DIB_BITMAPV3INFOHEADER = 56;
const unsigned int DIB_OS22XBITMAPHEADER = 64;
const unsigned int DIB_BITMAPV4HEADER = 108;
const unsigned int DIB_BITMAPV5HEADER = 124;
typedef struct tagBITMAPCOREHEADER {
DWORD bcSize;
WORD bcWidth;
WORD bcHeight;
WORD bcPlanes;
WORD bcBitCount;
} BITMAPCOREHEADER, *PBITMAPCOREHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; //40 bytes
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
// From FileFormat.info
typedef struct {
DWORD Size; /* Size of this header in bytes */
LONG Width; /* Image width in pixels */
LONG Height; /* Image height in pixels */
WORD Planes; /* Number of color planes */
WORD BitsPerPixel; /* Number of bits per pixel */
DWORD Compression; /* Compression methods used */
DWORD SizeOfBitmap; /* Size of bitmap in bytes */
LONG HorzResolution; /* Horizontal resolution in pixels per meter */
LONG VertResolution; /* Vertical resolution in pixels per meter */
DWORD ColorsUsed; /* Number of colors in the image */
DWORD ColorsImportant; /* Minimum number of important colors */
/* Fields added for Windows 4.x follow this line */
DWORD RedMask; /* Mask identifying bits of red component */
DWORD GreenMask; /* Mask identifying bits of green component */
DWORD BlueMask; /* Mask identifying bits of blue component */
DWORD AlphaMask; /* Mask identifying bits of alpha component */
DWORD CSType; /* Color space type */
LONG RedX; /* X coordinate of red endpoint */
LONG RedY; /* Y coordinate of red endpoint */
LONG RedZ; /* Z coordinate of red endpoint */
LONG GreenX; /* X coordinate of green endpoint */
LONG GreenY; /* Y coordinate of green endpoint */
LONG GreenZ; /* Z coordinate of green endpoint */
LONG BlueX; /* X coordinate of blue endpoint */
LONG BlueY; /* Y coordinate of blue endpoint */
LONG BlueZ; /* Z coordinate of blue endpoint */
DWORD GammaRed; /* Gamma red coordinate scale value */
DWORD GammaGreen; /* Gamma green coordinate scale value */
DWORD GammaBlue; /* Gamma blue coordinate scale value */
} WIN4XBITMAPHEADER;
typedef struct {
DWORD bV5Size;
LONG bV5Width;
LONG bV5Height;
WORD bV5Planes;
WORD bV5BitCount;
DWORD bV5Compression;
DWORD bV5SizeImage;
LONG bV5XPelsPerMeter;
LONG bV5YPelsPerMeter;
DWORD bV5ClrUsed;
DWORD bV5ClrImportant;
DWORD bV5RedMask;
DWORD bV5GreenMask;
DWORD bV5BlueMask;
DWORD bV5AlphaMask;
DWORD bV5CSType;
LONG RedX; /* X coordinate of red endpoint */
LONG RedY; /* Y coordinate of red endpoint */
LONG RedZ; /* Z coordinate of red endpoint */
LONG GreenX; /* X coordinate of green endpoint */
LONG GreenY; /* Y coordinate of green endpoint */
LONG GreenZ; /* Z coordinate of green endpoint */
LONG BlueX; /* X coordinate of blue endpoint */
LONG BlueY; /* Y coordinate of blue endpoint */
LONG BlueZ; /* Z coordinate of blue endpoint */
DWORD bV5GammaRed;
DWORD bV5GammaGreen;
DWORD bV5GammaBlue;
DWORD bV5Intent;
DWORD bV5ProfileData;
DWORD bV5ProfileSize;
DWORD bV5Reserved;
} BITMAPV5HEADER, *PBITMAPV5HEADER;
//compression methods
const unsigned int STIM_BI_RGB = 0;
const unsigned int STIM_BI_BITFIELDS = 3;
class bmp {
std::ifstream file;
public:
unsigned int dib_header_size;
size_t bit_pos; // start position (relative to the beginning of the file) of the bitmap bits
size_t total_size; //total size of the bitmap file (in bytes)
size_t width;
size_t height;
int channels;
int bits_per_pixel;
unsigned int compression;
size_t bytes() {
return width * height * bits_per_pixel / 8;
}
void read_bmpFileHeader() {
BITMAPFILEHEADER file_header;
file.read((char*)&file_header, sizeof(BITMAPFILEHEADER));
bit_pos = file_header.bfOffBits;
total_size = file_header.bfSize;
}
void read_bmpCoreHeader() {
tagBITMAPCOREHEADER header;
file.read((char*)&header, sizeof(tagBITMAPCOREHEADER));
width = header.bcWidth;
height = header.bcHeight;
bits_per_pixel = header.bcBitCount;
compression = 0;
}
void read_bmpInfoHeader() {
tagBITMAPINFOHEADER info_header;
file.read((char*)&info_header, sizeof(tagBITMAPINFOHEADER));
width = info_header.biWidth;
height = info_header.biHeight;
bits_per_pixel = info_header.biBitCount;
compression = info_header.biCompression;
}
void read_bmpV4Header() {
WIN4XBITMAPHEADER header;
file.read((char*)&header, sizeof(WIN4XBITMAPHEADER));
width = header.Width;
height = header.Height;
bits_per_pixel = header.BitsPerPixel;
compression = header.Compression;
}
void read_bmpV5Header() {
BITMAPV5HEADER header;
file.read((char*)&header, sizeof(BITMAPV5HEADER));
width = header.bV5Width;
height = header.bV5Height;
bits_per_pixel = header.bV5BitCount;
compression = header.bV5Compression;
}
void read_dib() { //read the bitmap DIB information header
std::streamoff header_pos = file.tellg();
file.read((char*)&dib_header_size, sizeof(unsigned int));
file.seekg(header_pos);
switch (dib_header_size) {
case DIB_BITMAPCOREHEADER: read_bmpCoreHeader(); break;
case DIB_BITMAPINFOHEADER: read_bmpInfoHeader(); break;
case DIB_BITMAPV4HEADER: read_bmpV4Header(); break;
case DIB_BITMAPV5HEADER: read_bmpV5Header(); break;
default:
std::cout << "stim::bmp ERROR: this bitmap header format isn't supported" << std::endl;
exit(1);
}
}
bool open(std::string filename) { //open the bitmap file and read the header data
file.open(filename, std::ifstream::binary);
if (!file) {
std::cout << "stim::bmp ERROR: error opening file: " << filename.c_str() << std::endl;
return false;
}
read_bmpFileHeader(); //read the file header
read_dib();
if (compression != STIM_BI_RGB) { //check for compression
std::cout << "stim::bmp ERROR: this file is compressed, and compression is not supported" << std::endl;
return false;
}
return true;
}
void close() {
file.close();
}
/// Copy the bitmap data into a pre-allocated array
bool read(char* dst){
file.seekg(bit_pos); //seek to the beginning of the data array
size_t row_bytes = width * bits_per_pixel / 8; //number of bytes in each row
size_t padding = row_bytes % 4; //calculate the padding on disk for each row (rows must be multiples of 4)
if(file){
for (size_t h = 0; h < height; h++) { //for each row in the image
file.read(dst + (height - h - 1) * row_bytes, row_bytes); //read the row of image data
file.seekg(padding, std::ios::cur); //seek to the end of the row on disk
if (file.eof()) std::cout << "stim::bmp ERROR: array size incorrect, end of file reached while reading bitmap." << std::endl;
else if (file.fail()) std::cout << "stim::bmp ERROR: reading bitmap array failed." << std::endl;
else if (file.bad()) std::cout << "stim::bmp ERROR: stream integrity failed while reading bitmap array" << std::endl;
}
return true;
}
else{
std::cout<<"stim::bmp ERROR: could not read array from file."<<std::endl;
return false;
}
}
};
bool save_bmp(std::string filename, char* bits, size_t width, size_t height) {
size_t bits_per_pixel = 24;
size_t row_bytes = width * bits_per_pixel / 8; //number of bytes in each row
size_t padding = row_bytes % 4; //calculate the padding on disk for each row (rows must be multiples of 4)
tagBITMAPFILEHEADER file_header;
memset(&file_header, 0, sizeof(tagBITMAPFILEHEADER)); //initialize the file header structure to zero
file_header.bfOffBits = sizeof(tagBITMAPFILEHEADER) + sizeof(tagBITMAPCOREHEADER); //the offset includes both the file and DIB header
file_header.bfSize = (stim::DWORD)(file_header.bfOffBits + (row_bytes + padding) * height); //calculate the size of the bitmap file
file_header.bfType = (stim::DWORD)0x4D42;
tagBITMAPCOREHEADER info_header;
memset(&info_header, 0, sizeof(tagBITMAPCOREHEADER)); //initialize the info header to zero
info_header.bcBitCount = (stim::DWORD)bits_per_pixel;
info_header.bcHeight = (stim::WORD)height;
info_header.bcWidth = (stim::WORD)width;
info_header.bcSize = sizeof(tagBITMAPCOREHEADER);
info_header.bcPlanes = 1;
std::ofstream outfile(filename, std::ios::binary); //open the output file for binary writing
outfile.write((char*)&file_header, sizeof(tagBITMAPFILEHEADER)); //write the file header
outfile.write((char*)&info_header, sizeof(tagBITMAPCOREHEADER)); //write the information header
char* pad = (char*)malloc(padding); //create a buffer that will be written as padding
memset(pad, 0, padding);
for (size_t h = 0; h < height; h++) {
outfile.write((char*)(bits + (height - h - 1) * row_bytes), row_bytes); //write the bitmap data
outfile.write(pad, padding);
}
free(pad);
return true;
}
}
#endif