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
|
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include "color.h"
#include "bmp.h"
#define BYTES_PER_PIXEL 3
#define OFFSET_bfSize 2
#define OFFSET_biWidth 18
#define OFFSET_biHeight 22
#define HEADERSIZE 54
static size_t
bmp_calc_padding(int32_t width) {
return (4 - (width % 4)) % 4;
}
static const char* header_template = "BM \0\0\0\0\x36\0\0\0\x28\0\0\0 \x01\0\x18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static int
bmp_write_header(bmp_write_handle_t* bmph) {
char* header;
uint32_t filesize;
int32_t height;
if(!(header = malloc(HEADERSIZE))) {
fputs("Could not allocate memory for BMP header.\n", stderr);
return 0;
}
filesize = HEADERSIZE + (bmph->width * BYTES_PER_PIXEL + bmph->line_padding) * bmph->height;
height = -(bmph->height);
memcpy(header, header_template, HEADERSIZE);
memcpy(header + OFFSET_bfSize, &filesize, 4);
memcpy(header + OFFSET_biWidth, &(bmph->width), 4);
memcpy(header + OFFSET_biHeight, &height, 4);
if(fwrite(header, HEADERSIZE, 1, bmph->fh) != 1) {
fprintf(stderr, "Could not write BMP header: %s\n", strerror(errno));
free(header);
return 0;
}
free(header);
return 1;
}
bmp_write_handle_t*
bmp_create(const char* fn, int32_t width, int32_t height) {
FILE* fh = NULL;
bmp_write_handle_t* rv;
if(!(fh = fopen(fn, "wb"))) {
return NULL;
}
if(!(rv = malloc(sizeof(bmp_write_handle_t)))) {
fclose(fh);
return NULL;
}
rv->fh = fh;
rv->width = width;
rv->height = height;
rv->line_left = width;
rv->line_padding = bmp_calc_padding(width);
if(!bmp_write_header(rv)) {
fclose(fh);
free(rv);
return NULL;
}
return rv;
}
static const char* padding = "\0\0\0\0";
int
bmp_write_pixel(bmp_write_handle_t* bmph, color_t col) {
uint8_t pixel[3];
pixel[0] = col.b;
pixel[1] = col.g;
pixel[2] = col.r;
if(fwrite(pixel, 3, 1, bmph->fh) != 1) {
return 0;
}
if(bmph->line_padding != 0) {
if(--(bmph->line_left) == 0) {
bmph->line_left = bmph->width;
return (fwrite(padding, bmph->line_padding, 1, bmph->fh) == 1);
}
}
return 1;
}
void
bmp_destroy(bmp_write_handle_t* bmph) {
if(bmph->fh) {
fclose(bmph->fh);
}
free(bmph);
}
|