#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; }