bmp.c 2.12 KB
#include <bmp.h>
#include <stdlib.h>
#include <io.h>

enum read_status validate(struct bmp_header* headers, FILE* source){
    if(fread(headers, sizeof(struct bmp_header), 1, source) != 1 || headers->bfileSize <= HEADER_NORMAL_SIZE) return READ_INVALID_HEADER;

    if(headers->biPlanes != 1 || headers->biBitCount != BITS_PER_PIXEL) return READ_INVALID_BITS;

    if(headers->bfType != BMP) return READ_INVALID_SIGNATURE;

    return READ_OK;
}

enum read_status from_bmp(FILE* source, struct image* img){
    enum read_status status;
    struct bmp_header headers;

    status = validate(&headers, source);

    img->data = malloc(headers.biHeight * headers.biWidth * sizeof(struct pixel));
    if(!img->data) return READ_INVALID_BITS;
    img->height = headers.biHeight;
    img->width = headers.biWidth;

    uint32_t padding_size = (4 - (img->width * 3) % 4) % 4;

    for (size_t i = 0; i < img->height; i++) {
        if(fread(img->data + i * img->width, sizeof(struct pixel), img->width, source) != img->width) return READ_INVALID_BITS;
        fseek(source, padding_size, SEEK_CUR);
    }

    return status;
}

enum write_status to_bmp(FILE* dest, struct image* img){
    struct bmp_header header = {0};
    header.bfType = BMP;
    header.bOffBits = HEADER_NORMAL_SIZE;
    header.biSize = 40;
    header.biHeight = img->height;
    header.biWidth = img->width;
    header.biPlanes = 1;
    header.biBitCount = BITS_PER_PIXEL;

    size_t padding_size = (4 - (header.biWidth * 3) % 4) % 4;
    uint8_t  padding_byte = 0;

    header.biSizeImage = (header.biWidth * sizeof(struct pixel) + padding_size) * header.biHeight;
    header.bfileSize = HEADER_NORMAL_SIZE + header.biSizeImage;

    if(fwrite(&header, HEADER_NORMAL_SIZE, 1, dest) != 1)
        return WRITE_ERROR;

    for (size_t i = 0; i < img->height; i++) {
        if (fwrite(img->data + i * img->width, sizeof(struct pixel), img->width, dest) != img->width)
            return WRITE_ERROR;

        for (size_t j = 0; j < padding_size; j++) {
            if (fwrite(&padding_byte, 1, 1, dest) != 1)
                return WRITE_ERROR;
        }
    }
    free(img->data);

    return WRITE_OK;
}