You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
3.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "images.h"
// write an int to a byte array
void bmp__write_int(FILE *fp, int num) {
for (int i = 0; i < 4; i++) {
putc(num >> (i * 8), fp);
}
}
void bmp__write_16bit(FILE *fp, int num) {
for (int i = 0; i < 2; i++) {
putc(num >> (i * 8), fp);
}
}
unsigned long int bmp__align_to_four_bytes(unsigned long int row_length) {
unsigned long int os =row_length % 4;
return os == 0 ?row_length : row_length + (4 - os);
}
unsigned long int bmp__image_byte_size(Image image) {
// calculate size:
// bitmap file header = 14
// BITMAPCOREHEADER = 12 bytes
unsigned long int size = 14 + 12;
// width must be padded to align to 4 bytes
unsigned long int row_bytes = bmp__align_to_four_bytes(image.width * 3); // 3 bytes per pixel
// add row_bytes * height to total size
size += row_bytes * image.height;
return size;
}
// header format:
// BMP header (14 bytes)
// 0x42 0x4D "BM"
// 0xAA 0xBB 0xCC 0xDD bmp file size (int)
// 0x00 0x00 0x00 0x00 nulls
// 0x1A 0x00 0x00 0x00 pixel array offset (int) (= 14 + 12);
// DIB Header (BITMAPCOREHEADER) (12 bytes)
// 0x0C 0x00 0x00 0x00 header size (int) (= 12)
// 0xAA 0xBB width (unsigned 16 bit int)
// 0xCC 0xDD height (unsigned 16 bit int)
// 0x01 0x00 number of color planes (must be 1)
// 0x18 0x00 number of bits per pixel (3 * 8 = 24)
// char* bytes;
// bytes + 2 => zeigt auf offset 2 (ist char*)
// bytes[2] => wert an offset 2 (ist char)
int image_save_bmp(Image image, const char* path) {
unsigned long int size = bmp__image_byte_size(image);
if ((unsigned long int) size > (unsigned long int) UINT_MAX) {
printf("bitmap is too big!\n");
return 0;
}
FILE *fp = fopen(path, "w");
//unsigned char* bytes = calloc(sizeof(char), size);
// magic bytes, signature "BM"
// bmp header:
fputs("BM", fp); // offset 0
// write size to header
bmp__write_int(fp, size); // offset 2
bmp__write_int(fp, 0); // offset 6 - the next 4 byte are zeros
// pixel array offset
bmp__write_int(fp, 14 + 12); // offset 10
// DIB header:
bmp__write_int(fp, 12); // header size
bmp__write_16bit(fp, image.width); // width
bmp__write_16bit(fp, image.height); // height
bmp__write_16bit(fp, 1); // color planes
bmp__write_16bit(fp, 3 * 8); // bits per pixel
int line, px;
for (line = 0; line < image.height; line++) {
for (px = 0; px < image.width * 3; px += 3) {
putc(image.bitmap[line][px + 2], fp);
putc(image.bitmap[line][px + 1], fp);
putc(image.bitmap[line][px + 0], fp);
}
int mod = px % 4;
if (mod != 0) {
for (int i = 0; i < 4-mod; i++) {
putc(0, fp);
}
}
}
printf("wrote %li bytes...\n", size);
fclose(fp);
return 1;
}