--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "esp_log.h"
+#include "goldeloxSerial.h"
+
+#include "bmp_reader.h"
+
+#define BMP_BLIT_CHUNK_SIZE 64
+
+
+static const char *TAG = "bmp_reader";
+
+int blit_chunk_size = BMP_BLIT_CHUNK_SIZE;
+
+/* Private functions */
+
+void _read_bgr_data(FILE *, int, int, int *);
+void _read_bgr_data_reverse(FILE *, int, int, int *);
+void _read_bgr_data_reverse_flip(FILE *, int, int, int, int *);
+void _read_bgr_data_reverse_flip_16bcol(FILE *, int, int, int, uint16_t *);
+uint16_t convert_24b_to_16b(uint32_t c);
+
+void _read_bgr_data(FILE *fp, int data_offset, int size, int *result) {
+ if (!fp)
+ return;
+ if (data_offset)
+ fseek(fp, data_offset, SEEK_SET);
+ // printf("all good!\n");
+ int i;
+ for (i = 0; i < size; i += 1) {
+ // printf("i=%d\n", i);
+ // result[i] = 0xFFFFFF;
+ if(!fread(&result[i], 3, 1, fp)) {
+ break;
+ }
+ }
+}
+
+void _read_bgr_data_reverse(FILE *fp, int data_offset, int size, int *result) {
+ if (!fp)
+ return;
+ if (data_offset)
+ fseek(fp, data_offset, SEEK_SET);
+ // printf("all good!\n");
+ int i;
+ for (i = 0; i < size; i += 1) {
+ // printf("i=%d\n", i);
+ // result[i] = 0xFFFFFF;
+ if(!fread(&result[size - i - 1], 3, 1, fp)) {
+ break;
+ }
+ }
+}
+
+void _read_bgr_data_reverse_flip(FILE *fp, int data_offset, int w, int h, int *result) {
+ if (!fp)
+ return;
+ if (data_offset)
+ fseek(fp, data_offset, SEEK_SET);
+ // printf("all good!\n");
+ int i, j;
+ for (i = h - 1; i >= 0; i -= 1) {
+ // printf("i=%d\n", i);
+ // result[i] = 0xFFFFFF;
+ for (j = 0; j < w; ++j) {
+ if(!fread(&result[i * w + j], 3, 1, fp)) {
+ fprintf(stderr, "bmp_reader: Ran out of bytes to read :(\n");
+ break;
+ }
+ }
+
+ }
+ // printf("read: %d, %d (%d) given h=%d w=%d\n", i, j, i*j, h, w);
+}
+
+void _read_bgr_data_reverse_flip_16bcol(FILE *fp, int data_offset, int w, int h,
+ uint16_t *result) {
+ if (!fp)
+ return;
+ if (data_offset)
+ fseek(fp, data_offset, SEEK_SET);
+ // printf("all good!\n");
+ int i, j;
+ for (i = h - 1; i >= 0; i -= 1) {
+ // printf("i=%d\n", i);
+ // result[i] = 0xFFFFFF;
+ for (j = 0; j < w; ++j) {
+ uint32_t rgb;
+ if(!fread(&rgb, 3, 1, fp)) {
+ fprintf(stderr, "bmp_reader: Ran out of bytes to read :(\n");
+ break;
+ }
+ result[i * w + j] = convert_24b_to_16b(rgb);
+ }
+
+ }
+ // printf("read: %d, %d (%d) given h=%d w=%d\n", i, j, i*j, h, w);
+}
+
+/* end private functions */
+
+void bmp_read_header(FILE *fp, struct bmp_header_t *header) {
+ if (!fp)
+ return;
+ // fseek(fp, 0, SEEK_SET);
+ // (void)fread(header, sizeof(bmp_header_t), 1, fp);
+ fread(&header->signature, sizeof(header->signature), 1, fp);
+ fread(&header->size, sizeof(header->size), 1, fp);
+ fread(&header->_slack, sizeof(header->_slack), 1, fp);
+ fread(&header->offset, sizeof(header->offset), 1, fp);
+}
+
+void bmp_read_info_header(FILE *fp, struct bmp_info_header_t *header) {
+ if (!fp)
+ return;
+ (void)fread(header, sizeof(struct bmp_info_header_t), 1, fp);
+}
+
+int bmp_procure_info(FILE * fp, struct bmp_header_t *head,
+ struct bmp_info_header_t *ih) {
+ if (!fp) {
+ ESP_LOGE(TAG, "file is NULL!");
+ return 1;
+ }
+
+ if (!head || !ih) {
+ ESP_LOGE(TAG, "head or ih is null!");
+ return 1;
+ }
+ bmp_read_header(fp, head);
+ if (head->signature[0] != 'B' || head->signature[1] != 'M') {
+ ESP_LOGE(TAG, "File is not a BMP! (%#2x%#2x)\n", head->signature[0],
+ head->signature[1]);
+ return 1;
+ }
+ bmp_read_info_header(fp, ih);
+ if (ih->width > 128 || ih->height > 128) {
+ ESP_LOGE(TAG,
+ "image too wide or long. ULCD is 128x128 (target is "
+ "%dx%d)",
+ ih->width, ih->height);
+ return 1;
+ }
+ return 0;
+}
+/*
+ int blit_bmp(char *file, int x, int y) {
+ FILE *fd = fopen(file, "rb");
+ if (errno)
+ return errno;
+ bmp_header_t h;
+ bmp_info_header_t ih;
+ if (bmp_procure_info(fd, &h, &ih))
+ return 1;
+
+ int *image_data = (int *) malloc(sizeof(int) * ih.width * 10);
+
+ int total = ih.width * ih.height;
+ for (int i = 0; i < ih.height; i += 10) {
+ _read_bgr_data(fd, 0, ih.width * 10, image_data);
+ int ht = 10;
+ if (i + 10 > ih.height) {
+ ht = ih.height - i;
+ }
+ uLCD.BLIT(x, y + i, ih.width, ht, image_data);
+ }
+ return 0;
+ } */
+
+int bmp_blit(char *file, gl_display_t *disp, uint16_t x, uint16_t y) {
+ ESP_LOGI(TAG, "file name: %s", file);
+ FILE *fd = fopen(file, "r");
+ if (!fd) {
+ perror("fopen");
+ return errno;
+ }
+ struct bmp_header_t h;
+ struct bmp_info_header_t ih;
+ if (bmp_procure_info(fd, &h, &ih))
+ return 1;
+
+ ESP_LOGI(TAG, "Image of size: %dx%d", ih.width, ih.height);
+
+alloc_int:
+ uint16_t *image_data = malloc(sizeof(uint16_t) * ih.width * blit_chunk_size);
+
+ if (!image_data) {
+ ESP_LOGE(TAG, "not enough memory for chunk of size %d, halving",
+ blit_chunk_size);
+ if (blit_chunk_size < 4) {
+ ESP_LOGE(TAG, "ran out of memory");
+ return 1;
+ }
+ blit_chunk_size /= 2;
+ goto alloc_int;
+ }
+
+ int total = ih.width * ih.height;
+ for (int i = 0; i < ih.height; i += blit_chunk_size) {
+ int ht = blit_chunk_size;
+ int off = y + ih.height - i - blit_chunk_size;
+ if (i + blit_chunk_size > ih.height) {
+ ht = ih.height - i;
+ off = y;
+ }
+ _read_bgr_data_reverse_flip_16bcol(fd, 0, ih.width, ht, image_data);
+
+ // printf("with y-offset %d\n", off);
+ gl_blitComtoDisplay(disp, x, y + i, ih.width, ht,
+ (uint8_t *) image_data);
+ }
+ fclose(fd);
+ free(image_data);
+ return 0;
+}
+
+void bmp_read_bgr_data(FILE *fp, int *data) {
+ if (!fp) {
+ ESP_LOGE(TAG, "file is NULL!");
+ return;
+ }
+
+ struct bmp_header_t head;
+ struct bmp_info_header_t ih;
+ bmp_read_header(fp, &head);
+ if (head.signature[0] != 'B' || head.signature[1] != 'M') {
+ ESP_LOGE(TAG, "File is not a BMP! (%#2x%#2x)",
+ head.signature[0], head.signature[1]);
+ return;
+ }
+ bmp_read_info_header(fp, &ih);
+ if (ih.width > 128 || ih.height > 128) {
+ ESP_LOGE(TAG,
+ "image too wide or long. ULCD is 128x128 (target is "
+ "%dx%d",
+ ih.width, ih.height);
+ return;
+ }
+
+ if (ih.compression) {
+ ESP_LOGE(TAG, "compressed images not supported :(");
+ return;
+ }
+
+ if (ih.bits_per_pixel != 24) {
+ ESP_LOGE(TAG, "only 24 bit color supported");
+ return;
+ }
+
+ _read_bgr_data(fp, head.offset, ih.width * ih.height, data);
+}
+
+
+uint16_t convert_24b_to_16b(uint32_t color) {
+ uint8_t blue = color & 0xFF;
+ uint8_t green = (color >> 8) & 0xFF;
+ uint8_t red = (color >> 16) & 0xFF;
+
+ uint8_t new_blue = (blue >> 3) & 0x1F;
+ uint8_t new_red = (red >> 3) & 0x1F;
+ uint8_t new_green = (green >> 2) & 0x3F;
+
+ return (new_red << 11) | (new_green << 5) | new_blue;
+}