-
Notifications
You must be signed in to change notification settings - Fork 52
/
bmp_utils.h
233 lines (212 loc) · 7.32 KB
/
bmp_utils.h
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
/**
* @file bmp_utils.h
* @author Late Lee
* @date 2012-7-2 13:21:53
* @brief
* BMP相关工具函数,包括分析BMP图片、读写BMP图片,
* 2色、16色、256色及真彩色图片均测试通过
* 本工具函数要求RGB缓冲区图像是正立的,即缓冲区开始处为图像左上角。
*
* 1、在windows平台VS003编译测试通过;
* 2、解决了BMP图片倒立、偏色、倾斜等问题。
* 3、BMP图像每行数据需要4字节对齐,即一行数据不足4的倍数,以0补。
* 解决此问题方法:设置2个变量:
* width_byte:实际的RGB每一行的字节数
* stride_byte:4字节对齐的每一行的字节数(已对齐时两者相等)
* 保存时,另外开辟一个考虑了4字节对齐的缓冲区,每拷贝一行数据(width_byte),
* 跳过stride_byte个字节,即跳到4字节对齐的下一行。
* 读取时,只读width_byte,并且跳过每行最后补的0。
* 4、图像倒立:读取与保存BMP时,将数据倒过来:
* 读取时,将读到的数据由下往上存放到缓冲区
* 保存时,将数据由下往上拷贝到缓冲区
* 5、偏色:JPEG解压后为RGB数据,但BMP排序为BGR,将G、B调换位置即可。
* 6、倾斜:读取BMP时,未跳过补充的0。
*
* @log
* 2012-07-15
* 添加2色、16色、256色图片读取函数
* 笔记:
BMP图片结构,其中第1、第2部分占54字节,真彩色图没有第三部分
_______________________________
| BITMAPFILEHEADER |
|_______________________________|
| BITMAPINFOHEADER |
|_______________________________|
| n * RGBQUAD |
|_______________________________|
| image data |
|_______________________________|
*
对于2色位图,用1位表示该象素的颜色(一般0表示黑,1表示白),一个字节可以表示8个象素。调色板:2*4=8
对于16色位图,用4位表示一个象素的颜色,以一个字节可以表示2个象素。调色板:16*4=64
对于256色位图,一个字节表示1个象素。调色板:256*4=1024
对于真彩色图,三个字节表示1个象素。无调色板
* 单色BMP图:调色板占8字节,故头部占用54+8=62字节,后面为像素字节,
注意每行字节需要4字节对齐,
举例:16*16像素单色位图,一行占16/8 = 2字节,需要补2字节。
实际像素字节:16*16/2 = 32字节,补齐字节:2*16 = 32,共64字节
头部共62字节,故该图片总大小为64+62=126字节
*/
#ifndef _BMP_UTILS_H
#define _BMP_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef WIN32
#include <Windows.h>
#else
#include <stdint.h>
//typedef unsigned char BYTE;
//typedef unsigned short WORD;
//typedef unsigned long DWORD;
//typedef long LONG;
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint32_t LONG;
#pragma pack(push)
// 2字节对齐,共14
#pragma pack(2)
typedef struct tagBITMAPFILEHEADER {
WORD bfType; // 文件类型, 0x4d42
DWORD bfSize; // 文件总大小
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits; // 实际位图数据偏移
} BITMAPFILEHEADER;// __attribute__ ((packed));
// 40
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 本结构体长度
LONG biWidth; // 宽(单位像素)
LONG biHeight; // 高(单位像素)
WORD biPlanes; // 为1
WORD biBitCount; // 像素占用位数 1(2^1=2黑白二色), 4(2^4=16色),8(2^8=256色),24(真彩色),32
DWORD biCompression; // 压缩类型,不压缩:BI_RGB(0)
DWORD biSizeImage; // 位图数据大小,如果是不压缩类型,可以为0
LONG biXPelsPerMeter; // 水平分辨率,单位是每米的象素个数
LONG biYPelsPerMeter; // 垂直分辨率
DWORD biClrUsed; // 位图实际使用的颜色表中的颜色数
DWORD biClrImportant; // 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;// __attribute__ ((aligned(2)));
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPINFO{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;// __attribute__ ((aligned(2)));
#pragma pack(pop)
#endif
#undef ALIGN
#define ALIGN(x, n) (((x)+(n)-1)&~((n)-1))
/**
* RGB互换R、B顺序
*
* @param[IN] rgb_buffer RGB缓冲区
* @param[IN] len 缓冲区大小
*
* @return none
*
* @note
* 缓冲区数据可以是RGB,也可以是BGR,该函数只是将B、G进行互换
*/
void swap_rgb(unsigned char* rgb_buffer, int len);
/**
* 分析BMP文件
*
* @param[IN] bmp_file BMP图片文件名称
*
* @return
* 0: 成功
* -1: 文件不存在或不是BMP文件
*/
int analyse_bmp_file(const char* bmp_file);
/**
* 读取BMP图片文件
*
* @param[IN] bmp_file BMP图片文件名称
*
* @param[OUT] rgb_buffer RGB数据(实际为BGR)
* @param[OUT] size RGB数据大小
* @param[OUT] width 图片宽
* @param[OUT] height 图片高
*
* @return
* 0:成功
* -1:读取文件失败,或不是BMP文件,或申请内存失败
* @note
* rgb_buffer为二级指针,内存由该函数分配,需要自行释放
* rgb_buffer数据排列顺序为BGR,如果不是BGR,需要转换成BGR排列
*/
int read_bmp_file(const char* bmp_file, unsigned char** rgb_buffer,
int* rgb_size, int* width, int* height);
/**
* 读取BMP图片文件
*
* @param[IN] bmp_file BMP图片文件名称
*
* @param[OUT] rgb_buffer RGB数据(实际为BGR)
* @param[OUT] rgb_size RGB数据大小
* @param[OUT] palette_buf 调色板数据
* @param[OUT] palette_len 调色板数据大小
* @param[OUT] width 图片宽
* @param[OUT] height 图片高
*
* @return
* 0:成功
* -1:读取文件失败,或不是BMP文件,或申请内存失败
* @note
* rgb_buffer为二级指针,内存由该函数分配,需要自行释放
* rgb_buffer数据排列顺序为BGR,因此,处理时可能需要转换成RGB顺序
* 调色板数据指缓冲区中数据,如需要使用其中的颜色值,需自行计算
* 如无调色板,则调色板指针为NULL,调色板长度为0
*/
int read_bmp_file_ex(const char* bmp_file,
unsigned char** rgb_buffer, int* rgb_size,
unsigned char** palette_buf, int* palette_len,
int* width, int* height);
/**
* 保存BMP文件
*
* @param[IN] bmp_file BMP图片文件名称
*
* @param[IN] rgb_buffer RGB数据(实际为BGR)
* @param[IN] width 图片宽
* @param[IN] height 图片高
*
* @return
* 0:成功
* -1:打开文件失败
* @note
* BMP图片颜色分量实际为BGR,如果rgb_buffer数据排列顺序为RGB,则需要转换成BGR。
*/
int write_bmp_file(const char* bmp_file, unsigned char* rgb_buffer, int width, int height);
/**
* 保存BMP文件
*
* @param[IN] bmp_file BMP图片文件名称
*
* @param[IN] rgb_buffer RGB数据(实际为BGR)
* @param[IN] palette_buf 调色板数据
* @param[IN] palette_len 调色板长度
* @param[IN] width 图片宽
* @param[IN] height 图片高
*
* @return
* 0:成功
* -1:打开文件失败,或RGB缓冲区指针为空
* @note
* BMP图片颜色分量实际为BGR,如果rgb_buffer数据排列顺序为RGB,则需要转换成BGR。
*/
int write_bmp_file_ex(const char* bmp_file,
unsigned char* rgb_buffer,
unsigned char* palette_buf, int palette_len,
int width, int height);
void bmp_test();
#ifdef __cplusplus
};
#endif
#endif /* _BMP_UTILS_H */