embox

Форк
0
/
bmp.c 
258 строк · 6.7 Кб
1
/**
2
 * @file
3
 * @brief lib for read and draw BMP
4
 *
5
 * @date Apr 18, 2019
6
 * @author Filipp Chubukov
7
 */
8

9
#include <stdlib.h>
10
#include <stdio.h>
11
#include <string.h>
12
#include <unistd.h>
13
#include <fcntl.h>
14
#include <sys/mman.h>
15
#include <sys/ioctl.h>
16
#include <fs/file_format.h>
17

18
#include <lib/bmp.h>
19

20
#define HEADER_SIZE 54 /* size of header */
21
#define COLOR_SIZE 4 /* num of colors for one 32 pixel */
22
#define PALLETE_SIZE 256 /* default and max num of colors in pallete */
23

24
/**
25
 * in each bmp format, in some cases, when the width is not a multiple of four,
26
 * the garbage is appended, this macro helps to calculate the garbage size
27
 */
28
#define FIND_SKIP(a) ( ( 4 - ( (a) % 4 ) ) & 0x03)
29

30
void bmp_unload(struct bmp *bmp_data) {
31
	free(bmp_data->image);
32
}
33

34
struct bmp_header {
35
	uint32_t bfSize;	      /* Size of file */
36
	uint32_t bfReserved;      /* == "00" */
37
	uint32_t bfOffBits;	      /* Indicate to start of image bytes */
38
	uint32_t biSize;	      /* Size of header */
39
	uint32_t biWidth;		      /* Width of image in pixels */
40
	uint32_t biHeight;		      /*Height of image in pixels */
41
	uint16_t biPlanes;	      /* == 1 */
42
	uint16_t biBitCount;		      /* bits per pixel */
43
	uint32_t biCompression;	      /* type of compression(we are not using) */
44
	uint32_t biSizeImage;     /* size of image, == 0 if no compression */
45
	uint32_t biXPelsPerMeter; /* X resolution */
46
	uint32_t biYPelsPerMeter; /* Y resolution */
47
	uint32_t biClrUsed;	      /* Number of used from color table colors */
48
	uint32_t biClrImportant;  /* Number of important colors - min for drawing */
49
};
50

51
struct color {
52
	uint8_t red;
53
	uint8_t green;
54
	uint8_t blue;
55
};
56

57
static void read_pallete(int fd, struct color pallete[], int colors) {
58
	uint8_t tmp[4];
59
	int i;
60

61
	lseek(fd, HEADER_SIZE - 1, SEEK_SET); /* switch pos in fd to the end of head */
62
	for (i = 0; i < colors; i++) {
63
		read(fd, tmp, 4);
64
		pallete[i].red = tmp[1];
65
		pallete[i].green = tmp[2];
66
		pallete[i].blue = tmp[3];
67
	}
68
}
69

70
int bmp_load(char *file_name, struct bmp *bmp_data) {
71
	int j, i , k, tmp, skip, pos = 0;
72
	int height, width;
73
	struct color pallete[PALLETE_SIZE];
74
	struct bmp_header bmp_head;
75
	uint8_t signature[2], buff[4];
76

77
	int fd = open(file_name, O_RDONLY);
78
	if (fd == -1) {
79
		printf("Error : can't open file.\n");
80
		return -1;
81
	}
82

83
	if (read(fd, signature, sizeof(signature)) != sizeof(signature)) {
84
		printf("Error : can't read signature of file.\n");
85
		close(fd);
86
		return -1;
87
	}
88

89
	if (raw_get_file_format(signature) != BMP_FILE) {
90
		printf("Error : it's not BMP file\n");
91
		close(fd);
92
		return -1;
93
	}
94

95
	if (read(fd, &bmp_head, sizeof(struct bmp_header)) != sizeof(struct bmp_header)) {
96
		printf("Error : can't read header of bmp file\n");
97
		close(fd);
98
		return -1;
99
	}
100

101
	bmp_data->bits_per_pixel = bmp_head.biBitCount;
102
	bmp_data->width = (width = bmp_head.biWidth);
103
	bmp_data->height = (height = bmp_head.biHeight);
104
	bmp_data->image_size = width * height * 3;
105

106
	bmp_data->image = (uint8_t*)malloc(bmp_data->image_size * sizeof(uint8_t));
107

108
	switch (bmp_head.biBitCount) {
109
		case 32:
110
			lseek(fd, bmp_head.bfOffBits, SEEK_SET);
111
			for (i = 0; i < height; i++) {
112
				for (j = 0; j < width; j++) {
113
					read(fd, buff, 4);
114
					bmp_data->image[pos] = buff[2];
115
					bmp_data->image[pos + 1] = buff[1];
116
					bmp_data->image[pos + 2] = buff[0];
117
					pos += 3;
118
				}
119
			}
120
			break;
121

122
		case 24:
123
			lseek(fd, bmp_head.bfOffBits, SEEK_SET);
124
			skip = FIND_SKIP(width * 3);
125
			for (i = 0; i < height; i++) {
126
				for (j = 0; j < width; j++) {
127
					read(fd, buff, 3);
128
					bmp_data->image[pos] = buff[2];
129
					bmp_data->image[pos + 1] = buff[1];
130
					bmp_data->image[pos + 2] = buff[0];
131
					pos += 3;
132
				}
133
				if (skip) {
134
					read(fd, buff, skip);
135
				}
136
			}
137
			break;
138

139
		/* 16bpp very unusual format and is not supported in most parsers */
140
		case 16:
141
			printf("Error : 16bit bmp not supported\n");
142
			close(fd);
143
			return -1;
144

145
		case 8:
146
			read_pallete(fd, pallete, (bmp_head.bfOffBits - HEADER_SIZE) / COLOR_SIZE);
147
			lseek(fd, bmp_head.bfOffBits, SEEK_SET);
148
			skip = FIND_SKIP(width);
149
			for (i = 0; i < height; i++) {
150
				for (j = 0; j < width; j++) {
151
					read(fd, buff, 1);
152
					bmp_data->image[pos] = pallete[buff[0]].blue;
153
					bmp_data->image[pos + 1] = pallete[buff[0]].green;
154
					bmp_data->image[pos + 2] = pallete[buff[0]].red;
155
					pos += 3;
156
				}
157
				if (skip) {
158
					read(fd, buff, skip);
159
				}
160
			}
161
			break;
162

163
		case 4:
164
			read_pallete(fd, pallete, (bmp_head.bfOffBits - HEADER_SIZE) / COLOR_SIZE);
165
			lseek(fd, bmp_head.bfOffBits, SEEK_SET);
166
			skip = FIND_SKIP(width / 2 + width % 2);
167
			for (i = 0; i < height; i++) {
168
				for (j = 0; j < width / 2; j++) {
169
					read(fd, buff, 1);
170
					buff[1] = buff[0]>>4;
171
					buff[2] = buff[0] & 0x0f;
172
					bmp_data->image[pos + 5] = pallete[buff[1]].red;
173
					bmp_data->image[pos + 4] = pallete[buff[1]].green;
174
					bmp_data->image[pos + 3] = pallete[buff[1]].blue;
175
					bmp_data->image[pos + 2] = pallete[buff[2]].red;
176
					bmp_data->image[pos + 1] = pallete[buff[2]].green;
177
					bmp_data->image[pos] = pallete[buff[2]].blue;
178
					pos += 6;
179
				}
180
				if (width % 2) {
181
					read(fd, buff, 1);
182
					buff[1] = buff[0]>>4;
183
					bmp_data->image[pos + 2] = pallete[buff[1]].red;
184
					bmp_data->image[pos + 1] = pallete[buff[1]].green;
185
					bmp_data->image[pos] = pallete[buff[1]].blue;
186
					pos += 3;
187
				}
188
				if (skip) {
189
					read(fd, buff, skip);
190
				}
191
			}
192
			break;
193

194
		case 1:
195
			lseek(fd, bmp_head.bfOffBits, SEEK_SET);
196
			skip = FIND_SKIP(width / 8 + (width % 8 ? 1 : 0));
197
			for (i = 0; i < height; i++) {
198
				for (j = 0; j < width / 8; j++) {
199
					read(fd, buff, 1);
200
					for (k = 0; k < 8; k++) {
201
						if (buff[0] & 0x80) {
202
							bmp_data->image[pos] = 255;
203
							bmp_data->image[pos + 1] = 255;
204
							bmp_data->image[pos + 2] = 255;
205
							bmp_data->image[pos + 3] = 255;
206
							pos += 3;
207
						} else {
208
							bmp_data->image[pos] = 0;
209
							bmp_data->image[pos + 1] = 0;
210
							bmp_data->image[pos + 2] = 0;
211
							pos += 3;
212
						}
213
						buff[0] = buff[0]<<1;
214
					}
215
				}
216

217
				if (width % 8) {
218
					read(fd, buff, 1);
219
					for (k = 0; k < width % 8; k++) {
220
						if (buff[0] & 0x80) {
221
							bmp_data->image[pos] = 255;
222
							bmp_data->image[pos + 1] = 255;
223
							bmp_data->image[pos + 2] = 255;
224
							pos += 3;
225
						} else {
226
							bmp_data->image[pos] = 0;
227
							bmp_data->image[pos + 1] = 0;
228
							bmp_data->image[pos + 2] = 0;
229
							pos += 3;
230
						}
231
						buff[0] = buff[0]<<1;
232
					}
233
				}
234

235
				if (skip) {
236
					read(fd, buff, skip);
237
				}
238
			}
239
			break;
240

241
		default:
242
			printf("invalid bitcount\n");
243
			close(fd);
244
			return -1;
245
	}
246

247
	/* reverse pixels in image */
248
	for (i = 0; i < height / 2; i++) {
249
		for (j = 0; j < width * 3; j++) {
250
			tmp = bmp_data->image[width * 3 * (height - 1 - i) + j];
251
			bmp_data->image[width * 3 * (height - 1 - i) + j] = bmp_data->image[width * 3 * i + j];
252
			bmp_data->image[width * 3 * i + j] = tmp;
253
		}
254
	}
255

256
	close(fd);
257
	return 0;
258
}
259

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.