luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

decoder_BMP.c (6864B)


      1 #include "decoder_BMP.h"
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <lauxlib.h>
      5 
      6 /* Read little-endian values */
      7 static inline uint16_t read_le16(const uint8_t* data) {
      8     return data[0] | (data[1] << 8);
      9 }
     10 
     11 static inline uint32_t read_le32(const uint8_t* data) {
     12     return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
     13 }
     14 
     15 /* Decode BMP from memory */
     16 image_t* bmp_decode(const uint8_t* data, uint32_t data_size) {
     17     if (!data || data_size < 54) return NULL;  // Minimum BMP size
     18 
     19     /* Read file header */
     20     bmp_file_header_t file_header;
     21     file_header.signature = read_le16(data);
     22     file_header.file_size = read_le32(data + 2);
     23     file_header.reserved1 = read_le16(data + 6);
     24     file_header.reserved2 = read_le16(data + 8);
     25     file_header.data_offset = read_le32(data + 10);
     26 
     27     /* Check BMP signature */
     28     if (file_header.signature != 0x4D42) {  // "BM"
     29         return NULL;
     30     }
     31 
     32     /* Read info header */
     33     bmp_info_header_t info_header;
     34     const uint8_t* info_data = data + 14;
     35     info_header.header_size = read_le32(info_data);
     36     info_header.width = (int32_t)read_le32(info_data + 4);
     37     info_header.height = (int32_t)read_le32(info_data + 8);
     38     info_header.planes = read_le16(info_data + 12);
     39     info_header.bpp = read_le16(info_data + 14);
     40     info_header.compression = read_le32(info_data + 16);
     41 
     42     /* Validate */
     43     if (info_header.width <= 0 || info_header.height == 0) return NULL;
     44     if (info_header.compression != BMP_BI_RGB) {
     45         /* Only support uncompressed BMPs for now */
     46         return NULL;
     47     }
     48 
     49     /* Determine if bottom-up or top-down */
     50     int is_top_down = (info_header.height < 0);
     51     uint32_t height = is_top_down ? -info_header.height : info_header.height;
     52     uint32_t width = info_header.width;
     53 
     54     /* Only support 24-bit and 32-bit BMPs */
     55     if (info_header.bpp != 24 && info_header.bpp != 32) {
     56         return NULL;
     57     }
     58 
     59     /* Create image */
     60     image_t* img = image_create(width, height, 24);  // Always output as 24-bit RGB
     61     if (!img) return NULL;
     62 
     63     /* Calculate row size (padded to 4-byte boundary) */
     64     uint32_t bytes_per_pixel = info_header.bpp / 8;
     65     uint32_t row_size = ((width * bytes_per_pixel + 3) / 4) * 4;
     66 
     67     /* Check if we have enough data */
     68     if (file_header.data_offset + row_size * height > data_size) {
     69         image_destroy(img);
     70         return NULL;
     71     }
     72 
     73     /* Read pixel data */
     74     const uint8_t* pixel_data = data + file_header.data_offset;
     75 
     76     for (uint32_t y = 0; y < height; y++) {
     77         /* BMP is stored bottom-up by default */
     78         uint32_t dest_y = is_top_down ? y : (height - 1 - y);
     79         const uint8_t* row = pixel_data + y * row_size;
     80 
     81         for (uint32_t x = 0; x < width; x++) {
     82             const uint8_t* pixel = row + x * bytes_per_pixel;
     83 
     84             /* BMP stores as BGR(A), we need RGB */
     85             uint8_t b = pixel[0];
     86             uint8_t g = pixel[1];
     87             uint8_t r = pixel[2];
     88             uint8_t a = (info_header.bpp == 32) ? pixel[3] : 255;
     89 
     90             image_set_pixel(img, x, dest_y, r, g, b, a);
     91         }
     92     }
     93 
     94     return img;
     95 }
     96 
     97 /* Load BMP from file (stub - would need filesystem) */
     98 image_t* bmp_load_file(const char* filename) {
     99     (void)filename;  /* Unused parameter */
    100     /* TODO: Implement file loading once filesystem is available */
    101     /* For now, this would need to be called with data already loaded into memory */
    102     return NULL;
    103 }
    104 
    105 /* Encode image to BMP format */
    106 int bmp_encode(image_t* img, uint8_t** out_data, uint32_t* out_size) {
    107     if (!img || !out_data || !out_size) return -1;
    108 
    109     /* Calculate sizes */
    110     uint32_t bytes_per_pixel = 3;  // 24-bit output
    111     uint32_t row_size = ((img->width * bytes_per_pixel + 3) / 4) * 4;  // Padded to 4 bytes
    112     uint32_t pixel_data_size = row_size * img->height;
    113     uint32_t file_size = 54 + pixel_data_size;  // Header + pixel data
    114 
    115     /* Allocate output buffer */
    116     uint8_t* buffer = (uint8_t*)malloc(file_size);
    117     if (!buffer) return -1;
    118 
    119     /* Fill file header */
    120     buffer[0] = 'B';
    121     buffer[1] = 'M';
    122     *(uint32_t*)(buffer + 2) = file_size;
    123     *(uint32_t*)(buffer + 6) = 0;  // Reserved
    124     *(uint32_t*)(buffer + 10) = 54;  // Offset to pixel data
    125 
    126     /* Fill info header */
    127     *(uint32_t*)(buffer + 14) = 40;  // Header size
    128     *(int32_t*)(buffer + 18) = img->width;
    129     *(int32_t*)(buffer + 22) = img->height;  // Positive = bottom-up
    130     *(uint16_t*)(buffer + 26) = 1;  // Planes
    131     *(uint16_t*)(buffer + 28) = 24;  // BPP
    132     *(uint32_t*)(buffer + 30) = 0;  // Compression (none)
    133     *(uint32_t*)(buffer + 34) = pixel_data_size;
    134     *(uint32_t*)(buffer + 38) = 2835;  // X pixels/meter
    135     *(uint32_t*)(buffer + 42) = 2835;  // Y pixels/meter
    136     *(uint32_t*)(buffer + 46) = 0;  // Colors used
    137     *(uint32_t*)(buffer + 50) = 0;  // Important colors
    138 
    139     /* Fill pixel data (bottom-up, BGR format) */
    140     uint8_t* pixel_data = buffer + 54;
    141 
    142     for (uint32_t y = 0; y < img->height; y++) {
    143         uint32_t src_y = img->height - 1 - y;  // Flip vertically
    144         uint8_t* row = pixel_data + y * row_size;
    145 
    146         for (uint32_t x = 0; x < img->width; x++) {
    147             uint8_t r, g, b, a;
    148             image_get_pixel(img, x, src_y, &r, &g, &b, &a);
    149 
    150             /* Write as BGR */
    151             row[x * 3 + 0] = b;
    152             row[x * 3 + 1] = g;
    153             row[x * 3 + 2] = r;
    154         }
    155 
    156         /* Pad row to 4-byte boundary */
    157         uint32_t padding = row_size - (img->width * 3);
    158         for (uint32_t i = 0; i < padding; i++) {
    159             row[img->width * 3 + i] = 0;
    160         }
    161     }
    162 
    163     *out_data = buffer;
    164     *out_size = file_size;
    165     return 0;
    166 }
    167 
    168 /* Save BMP to file (stub - would need filesystem) */
    169 int bmp_save_file(image_t* img, const char* filename) {
    170     (void)img;       /* Unused parameter */
    171     (void)filename;  /* Unused parameter */
    172     /* TODO: Implement file saving once filesystem is available */
    173     return -1;
    174 }
    175 
    176 /* Lua binding: Load BMP from memory */
    177 int lua_bmp_load(lua_State* L) {
    178     size_t data_size;
    179     const uint8_t* data = (const uint8_t*)luaL_checklstring(L, 1, &data_size);
    180 
    181     image_t* img = bmp_decode(data, data_size);
    182 
    183     if (img) {
    184         lua_pushlightuserdata(L, img);
    185         return 1;
    186     } else {
    187         lua_pushnil(L);
    188         lua_pushstring(L, "Failed to decode BMP");
    189         return 2;
    190     }
    191 }
    192 
    193 /* Lua binding: Save image as BMP
    194 int lua_bmp_save(lua_State* L) {
    195     image_t* img = (image_t*)lua_touserdata(L, 1);
    196 
    197     if (!img) {
    198         lua_pushnil(L);
    199         lua_pushstring(L, "Invalid image");
    200         return 2;
    201     }
    202 
    203     uint8_t* data;
    204     uint32_t size;
    205 
    206     if (bmp_encode(img, &data, &size) == 0) {
    207         lua_pushlstring(L, (const char*)data, size);
    208         free(data);
    209         return 1;
    210     } else {
    211         lua_pushnil(L);
    212         lua_pushstring(L, "Failed to encode BMP");
    213         return 2;
    214     }
    215 }
    216 */