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
#include "../include/bmp.h"
#include "stdint.h"
#include <stdbool.h>
#define BFTYPE 19778
#define BIPLANES 1
#define BISIZE 40
#define BPC 24
#define COMPR 0
#define X_PPM 0
#define Y_PPM 0
#define IMP_COLORS 0
#define NUM_COLORS 0
#define HEADER_BITS 54
const char *read_status_message[] = {
[READ_OK] = "The read was successful",
[READ_ERROR] = "Read wasn't successful",
[SIGNATURE_INVALID] = "Signature of BMP file is invalid",
[HEADER_INVALID] = "BMP file header is invalid"
};
const char *write_status_message[] = {
[WRITE_OK] = "The write was successful",
[WRITE_ERROR] = "Unable to write BMP"
};
static size_t padding_size(const size_t width) {
return width % 4 == 0 ? 0 : 4 - ((width * sizeof(struct pixel)) % 4);
}
static enum read_status read_head(FILE *file, struct bmp_header *header) {
return fread(header, sizeof(struct bmp_header), 1, file);
}
static size_t picture_size(const struct picture *picture) {
return (picture->width * sizeof(struct pixel) + padding_size(picture->width)) * picture->height;
}
static size_t file_size(const struct picture *picture) {
return picture_size(picture) + sizeof(struct bmp_header);
}
static struct bmp_header create_header(const struct picture *picture) {
return (struct bmp_header) {
.bfType = BFTYPE,
.bfileSize = file_size(picture),
.bOffBits = HEADER_BITS,
.biSize = BISIZE,
.biWidth = picture->width,
.biHeight = picture->height,
.biPlanes = BIPLANES,
.biBitCount = BPC,
.biCompression = COMPR,
.biSizeImage = picture_size(picture),
.biXPelsPerMeter = X_PPM,
.biYPelsPerMeter = Y_PPM,
.biClrUsed = NUM_COLORS,
.biClrImportant = IMP_COLORS
};
}
static enum read_status header_check_valid(struct bmp_header *header) {
return header->bfType == 0x4D42;
}
enum read_status from_bmp(FILE *in, struct picture *picture) {
struct bmp_header header = {0};
if (!read_head(in, &header)) return HEADER_INVALID;
if (!header_check_valid(&header)) return SIGNATURE_INVALID;
*picture = picture_create(header.biWidth, header.biHeight);
const size_t padding = padding_size(picture->width);
for (size_t i = 0; i < picture->height; ++i) {
for (size_t j = 0; j < picture->width; ++j) {
if (!fread(&(picture->data[picture->width * i + j]), sizeof(struct pixel), 1, in))
return READ_ERROR;
}
if (fseek(in, (long) padding, SEEK_CUR))
return READ_ERROR;
}
return READ_OK;
}
enum write_status to_bmp(FILE *out, const struct picture *picture) {
struct bmp_header header = create_header(picture);
if (!fwrite(&header, sizeof(struct bmp_header), 1, out))
return WRITE_ERROR;
fseek(out, header.bOffBits, SEEK_SET);
const int8_t zero = 0;
const size_t padding = padding_size(picture->width);
if (picture->data != NULL) {
for (size_t i = 0; i < picture->height; ++i) {
if (fwrite(picture->data + i * picture->width, sizeof(struct pixel), picture->width, out) != picture->width)
return WRITE_ERROR;
for (size_t j = 0; j < padding; ++j) {
if (fwrite(&zero, 1, 1, out) != 1)
return WRITE_ERROR;
}
}
} else {
return WRITE_ERROR;
}
return WRITE_OK;
}