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.
100 lines
3.1 KiB
C
100 lines
3.1 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;
|
|
} else {
|
|
printf("predicted size is %lu out of %u possible", size, UINT_MAX);
|
|
}
|
|
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;
|
|
}
|