bmp_format.c 2.98 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include "bmp_format.h"

#define BF_TYPE 0x4D42
#define BF_RESERVED 0
#define BMP_COMPRESSION_MAGIC 0
#define BI_PELS_PER_METER 2834
#define BI_PLANES 1
#define BI_COMPRESSION 0
#define BI_CLR_USED 0
#define BI_CLR_IMPORTANT 0
#define BMP_COLORS_MAGIC 0
#define BI_SIZE 40
#define DWORD_SIZE 4
#define BI_BIT_COUNT 24

Ivan Nabiullin's avatar
Ivan Nabiullin committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
struct __attribute__((packed)) bmp_header
{
    uint16_t bfType;
    uint32_t  bfileSize;
    uint32_t bfReserved;
    uint32_t bOffBits;
    uint32_t biSize;
    uint32_t biWidth;
    uint32_t  biHeight;
    uint16_t  biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    uint32_t biXPelsPerMeter;
    uint32_t biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t  biClrImportant;
};

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
size_t get_padding(struct image const* img) {
	return 4 - (img->width * sizeof(struct pixel)) % 4;
}

size_t row_size(struct image const* img) {
    return img->width * sizeof(struct pixel);
}

size_t body_size(struct image const* img) {
	return sizeof(struct pixel) * img->height * (img->width + get_padding(img));
}

size_t image_size(struct image const* img) {
	return sizeof(struct bmp_header) + body_size(img);
}

struct bmp_header prepare_bmp_header(struct image const* img) {
    struct bmp_header header;
	header.bfType = BF_TYPE;
	header.biBitCount = BI_BIT_COUNT;
	header.biXPelsPerMeter = BI_PELS_PER_METER;
	header.biYPelsPerMeter = BI_PELS_PER_METER;
    header.bfileSize = image_size(img) + BF_RESERVED;
    header.bfReserved = BF_RESERVED;
    header.bOffBits = sizeof(struct bmp_header);
    header.biSize = BI_SIZE;
    header.biWidth = img->width;
    header.biHeight = img->height;
    header.biPlanes = BI_PLANES;
    header.biCompression = BI_COMPRESSION;
    header.biSizeImage = body_size(img);
    header.biClrUsed = BI_CLR_IMPORTANT;
    header.biClrImportant = BI_CLR_IMPORTANT;
    return header;
}

Ivan Nabiullin's avatar
Ivan Nabiullin committed
71 72 73
// Проверка на валидность файла и указателя на картинку
// принципиально вынесена в другой уровень абстракции
// См. image_io.c
74 75 76 77 78 79 80
enum read_status from_bmp( FILE* in, struct image* img ) {
    struct bmp_header header;
    if (!fread(&header, sizeof(header), 1, in)) return READ_INVALID_HEADER;
    img->width = header.biWidth;
    img->height = header.biHeight;
    img->data = (struct pixel*) malloc(body_size(img));
	for (size_t i = 0; i < img->height; i++) {
Ivan Nabiullin's avatar
Ivan Nabiullin committed
81
		if (fread(&img->data[i * img->width], sizeof(struct pixel), img->width, in) != img->width) return READ_EOF;
82 83 84 85 86 87 88 89 90
		fseek(in, get_padding(img), SEEK_CUR);
	}
    return READ_OK;
}

enum write_status to_bmp( FILE* out, struct image const* img ) {
    struct bmp_header header = prepare_bmp_header(img);
    fwrite(&header, sizeof(struct bmp_header), 1, out);
    for (size_t i = 0; i < img->height; i++) {
Ivan Nabiullin's avatar
Ivan Nabiullin committed
91 92
		if (fwrite(&img->data[i * img->width], sizeof(struct pixel), img->width, out) != img->width) return WRITE_EOF;
		if (fwrite(&img->data, 1, get_padding(img), out) != get_padding(img)) return WRITE_EOF;
93 94 95
	}
    return WRITE_OK;
}