#include "bmp_loader.h" #include #include #include static uint16_t le16(const unsigned char* data) { return (uint16_t)data[0] | ((uint16_t)data[1] << 8); } static uint32_t le32(const unsigned char* data) { return (uint32_t)data[0] | ((uint32_t)data[1] << 8) | ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24); } int load_bmp_rgb(const char* path, unsigned char** output, int* width, int* height) { if (!path || !output || !width || !height) return -1; FILE* file = fopen(path, "rb"); if (!file) return -2; unsigned char header[54]; if (fread(header, 1, sizeof(header), file) != sizeof(header) || header[0] != 'B' || header[1] != 'M') { fclose(file); return -3; } const uint32_t pixel_offset = le32(header + 10); const int32_t source_width = (int32_t)le32(header + 18); const int32_t signed_height = (int32_t)le32(header + 22); const uint16_t planes = le16(header + 26); const uint16_t bits = le16(header + 28); const uint32_t compression = le32(header + 30); if (source_width <= 0 || signed_height == 0 || planes != 1 || (bits != 24 && bits != 32) || compression != 0) { fclose(file); return -4; } const int source_height = signed_height < 0 ? -signed_height : signed_height; const int top_down = signed_height < 0; const size_t source_stride = (((size_t)source_width * bits + 31u) / 32u) * 4u; const size_t source_size = source_stride * (size_t)source_height; const size_t rgb_size = (size_t)source_width * (size_t)source_height * 3u; if (source_size == 0 || rgb_size == 0 || source_size > 1024u * 1024u * 1024u) { fclose(file); return -5; } unsigned char* source = (unsigned char*)malloc(source_size); unsigned char* rgb = (unsigned char*)malloc(rgb_size); if (!source || !rgb) { free(source); free(rgb); fclose(file); return -6; } if (fseek(file, (long)pixel_offset, SEEK_SET) != 0 || fread(source, 1, source_size, file) != source_size) { free(source); free(rgb); fclose(file); return -7; } fclose(file); const int bytes_per_pixel = bits / 8; for (int y = 0; y < source_height; ++y) { const int source_y = top_down ? y : source_height - 1 - y; const unsigned char* row = source + (size_t)source_y * source_stride; unsigned char* target = rgb + (size_t)y * (size_t)source_width * 3u; for (int x = 0; x < source_width; ++x) { const unsigned char* pixel = row + (size_t)x * (size_t)bytes_per_pixel; target[x * 3] = pixel[2]; target[x * 3 + 1] = pixel[1]; target[x * 3 + 2] = pixel[0]; } } free(source); *output = rgb; *width = source_width; *height = source_height; return 0; } void free_bmp_rgb(unsigned char* pixels) { free(pixels); }