From 1e4f4e316a24d6009c08d5a13e31481af9d820ad Mon Sep 17 00:00:00 2001 From: Thomas Ballmann Date: Sun, 16 Feb 2020 17:05:44 +0100 Subject: [PATCH] basic png decoder added --- include/display.h | 10 +- include/imagePNG.h | 6 + include/imageWBMP.h | 12 ++ src/cloud.cpp | 7 +- src/display.cpp | 48 +++---- src/image.cpp | 298 -------------------------------------------- src/imagePNG.cpp | 69 ++++++++++ src/imageWBMP.cpp | 49 ++++++++ 8 files changed, 159 insertions(+), 340 deletions(-) create mode 100644 include/imagePNG.h create mode 100644 include/imageWBMP.h delete mode 100644 src/image.cpp create mode 100644 src/imagePNG.cpp create mode 100644 src/imageWBMP.cpp diff --git a/include/display.h b/include/display.h index 12f87f1..9f10396 100644 --- a/include/display.h +++ b/include/display.h @@ -4,13 +4,13 @@ #include #include - - void setupDisplay(); -void displayOpenFramebuffer(); -void displayWriteFramebuffer(int offset, uint8_t buff[], int c); -void displayFlushFramebuffer(); +void displayOpen(); + +void displayWritePixel(int16_t x, int16_t y, uint16_t color); +void displayWriteFramebuffer(uint8_t bitmap[]); +void displayFlush(); #endif \ No newline at end of file diff --git a/include/imagePNG.h b/include/imagePNG.h new file mode 100644 index 0000000..3d55cb1 --- /dev/null +++ b/include/imagePNG.h @@ -0,0 +1,6 @@ +#ifndef IMAGE_PNG_H +#define IMAGE_PNG_H + +void setupImagePNG(); + +#endif \ No newline at end of file diff --git a/include/imageWBMP.h b/include/imageWBMP.h new file mode 100644 index 0000000..14d66df --- /dev/null +++ b/include/imageWBMP.h @@ -0,0 +1,12 @@ +#ifndef IMAGE_WBMP_H +#define IMAGE_WBMP_H + +#include + +void setupImageWBMP(); + +void wbmpOpenFramebuffer(); +void wbmpWriteFramebuffer(int offset, uint8_t bitmap[], int c); +void wbmpFlushFramebuffer(); + +#endif \ No newline at end of file diff --git a/src/cloud.cpp b/src/cloud.cpp index 7e692e7..f4eabe7 100644 --- a/src/cloud.cpp +++ b/src/cloud.cpp @@ -5,6 +5,7 @@ #include "settings.h" #include "display.h" +#include "imageWBMP.h" #include "device.h" // TODO SMART SIGN CONFIG ======== @@ -155,7 +156,7 @@ void requestCloud() // reset image buffer //memset(displayImageBuffer, 0, sizeof(displayImageBuffer)); int imageBufferOffset = 0; - displayOpenFramebuffer(); + wbmpOpenFramebuffer(); // persist image to display File file = SPIFFS.open("/currentImage.bin", FILE_WRITE); @@ -182,7 +183,7 @@ void requestCloud() } // write display frame - displayWriteFramebuffer(imageBufferOffset, buff, c); + wbmpWriteFramebuffer(imageBufferOffset, buff, c); imageBufferOffset += c; /* for (int i = 0; i < c; i++) @@ -224,7 +225,7 @@ void requestCloud() } // done - displayFlushFramebuffer(); + wbmpFlushFramebuffer(); } } } \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 38f112e..3a7b3d0 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -12,9 +12,7 @@ // enable or disable GxEPD2_GFX base class #define ENABLE_GxEPD2_GFX 0 - -GxEPD2_BW display(GxEPD2_750(/*CS=*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); -uint8_t _buffer[(GxEPD2_750::WIDTH / 8) * GxEPD2_750::HEIGHT]; +GxEPD2_BW display(GxEPD2_750(/*CS=*/5, /*DC=*/17, /*RST=*/16, /*BUSY=*/4)); void setupDisplay() { @@ -25,51 +23,33 @@ void setupDisplay() Serial.println("setup done"); } - -void displayOpenFramebuffer() +void displayOpen() { - memset(_buffer, 0, sizeof(_buffer)); - //display.setFullWindow(); - //display.firstPage(); - //display.fillScreen(GxEPD_WHITE); + display.setRotation(0); + display.setFullWindow(); + display.firstPage(); + display.fillScreen(GxEPD_WHITE); } -// TODO -void displayWriteFramebuffer(int offset, uint8_t bitmap[], int c) +void displayWritePixel(int16_t x, int16_t y, uint16_t color) { - for (int i = 0; i < c; i++) - { - _buffer[offset] = bitmap[i]; - offset++; - } + display.drawPixel(x, y, color); +} - /* - //if (offset + sizeof(*bitmap) <= sizeof(_buffer)) - if (true) - { - memcpy((&_buffer) + offset, bitmap, 128); - } - else - { - Serial.println("!!!!! displayWriteFramebuffer overflow"); - } - */ + +void displayWriteFramebuffer(uint8_t bitmap[]) +{ + display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } -void displayFlushFramebuffer() +void displayFlush() { Serial.println("displayFlushFramebuffer"); - display.setRotation(0); - display.setFullWindow(); - display.firstPage(); - display.fillScreen(GxEPD_WHITE); - display.drawInvertedBitmap(0, 0, _buffer, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); display.nextPage(); } - void printSplash() { const char Hello[] = "Hello Paperdash!"; diff --git a/src/image.cpp b/src/image.cpp deleted file mode 100644 index 715faaf..0000000 --- a/src/image.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include -#include - -typedef struct { - uint16_t x1; - uint16_t y1; - uint16_t x2; - uint16_t y2; -} dispWin_t; - -dispWin_t dispWin = { - .x1 = 0, - .y1 = 0, - .x2 = 640, // DEFAULT_TFT_DISPLAY_WIDTH, - .y2 = 384, // DEFAULT_TFT_DISPLAY_HEIGHT, -}; -uint8_t image_debug; - -// @see https://github.com/Bodmer/TJpg_Decoder/blob/master/examples/SPIFFS_Jpg/SPIFFS_Jpg.ino - -// @see https://github.com/loboris/ESP32_TFT_library/blob/aa21772f54a71887ec08b2e8bbaef9e304009891/components/tft/tft.c -void TFT_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size) -{ - FILE *fhndl = NULL; - struct stat sb; - int i, err=0; - int img_xsize, img_ysize, img_xstart, img_xlen, img_ystart, img_ylen; - int img_pos, img_pix_pos, scan_lines, rd_len; - uint8_t tmpc; - uint16_t wtemp; - uint32_t temp; - int disp_xstart, disp_xend, disp_ystart, disp_yend; - uint8_t buf[56]; - char err_buf[64]; - uint8_t *line_buf[2] = {NULL,NULL}; - uint8_t lb_idx = 0; - uint8_t *scale_buf = NULL; - uint8_t scale_pix; - uint16_t co[3] = {0,0,0}; // RGB sum - uint8_t npix; - - if (scale > 7) scale = 7; - scale_pix = scale+1; // scale factor ( 1~8 ) - - if (fname) { - // * File name is given, reading image from file - if (stat(fname, &sb) != 0) { - sprintf(err_buf, "opening file"); - err = -1; - goto exit; - } - size = sb.st_size; - fhndl = fopen(fname, "r"); - if (!fhndl) { - sprintf(err_buf, "opening file"); - err = -2; - goto exit; - } - - i = fread(buf, 1, 54, fhndl); // read header - } - else { - // * Reading image from buffer - if ((imgbuf) && (size > 54)) { - memcpy(buf, imgbuf, 54); - i = 54; - } - else i = 0; - } - - sprintf(err_buf, "reading header"); - if (i != 54) {err = -3; goto exit;} - - // ** Check image header and get image properties - if ((buf[0] != 'B') || (buf[1] != 'M')) {err=-4; goto exit;} // accept only images with 'BM' id - - memcpy(&temp, buf+2, 4); // file size - if (temp != size) {err=-5; goto exit;} - - memcpy(&img_pos, buf+10, 4); // start of pixel data - - memcpy(&temp, buf+14, 4); // BMP header size - if (temp != 40) {err=-6; goto exit;} - - memcpy(&wtemp, buf+26, 2); // the number of color planes - if (wtemp != 1) {err=-7; goto exit;} - - memcpy(&wtemp, buf+28, 2); // the number of bits per pixel - if (wtemp != 24) {err=-8; goto exit;} - - memcpy(&temp, buf+30, 4); // the compression method being used - if (temp != 0) {err=-9; goto exit;} - - memcpy(&img_xsize, buf+18, 4); // the bitmap width in pixels - memcpy(&img_ysize, buf+22, 4); // the bitmap height in pixels - - - // * scale image dimensions -/* - img_xlen = img_xsize / scale_pix; // image display horizontal size - img_ylen = img_ysize / scale_pix; // image display vertical size - - if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - img_xlen) / 2) + dispWin.x1; - else if (x == RIGHT) x = dispWin.x2 + 1 - img_xlen; - - if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - img_ylen) / 2) + dispWin.y1; - else if (y == BOTTOM) y = dispWin.y2 + 1 - img_ylen; -*/ - if ((x < ((dispWin.x2 + 1) * -1)) || (x > (dispWin.x2 + 1)) || (y < ((dispWin.y2 + 1) * -1)) || (y > (dispWin.y2 + 1))) { - sprintf(err_buf, "out of display area (%d,%d", x, y); - err = -10; - goto exit; - } - - // ** set display and image areas - if (x < dispWin.x1) { - disp_xstart = dispWin.x1; - img_xstart = -x; // image pixel line X offset - img_xlen += x; - } - else { - disp_xstart = x; - img_xstart = 0; - } - if (y < dispWin.y1) { - disp_ystart = dispWin.y1; - img_ystart = -y; // image pixel line Y offset - img_ylen += y; - } - else { - disp_ystart = y; - img_ystart = 0; - } - disp_xend = disp_xstart + img_xlen - 1; - disp_yend = disp_ystart + img_ylen - 1; - if (disp_xend > dispWin.x2) { - disp_xend = dispWin.x2; - img_xlen = disp_xend - disp_xstart + 1; - } - if (disp_yend > dispWin.y2) { - disp_yend = dispWin.y2; - img_ylen = disp_yend - disp_ystart + 1; - } - - if ((img_xlen < 8) || (img_ylen < 8) || (img_xstart >= (img_xsize-2)) || ((img_ysize - img_ystart) < 2)) { - sprintf(err_buf, "image too small"); - err = -11; - goto exit; - } - - // ** Allocate memory for 2 lines of image pixels - line_buf[0] = static_cast(heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA)); - if (line_buf[0] == NULL) { - sprintf(err_buf, "allocating line buffer #1"); - err=-12; - goto exit; - } - - line_buf[1] = static_cast(heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA)); - if (line_buf[1] == NULL) { - sprintf(err_buf, "allocating line buffer #2"); - err=-13; - goto exit; - } - - if (scale) { - // Allocate memory for scale buffer - rd_len = img_xlen * 3 * scale_pix; - scale_buf = static_cast(malloc(rd_len*scale_pix)); - if (scale_buf == NULL) { - sprintf(err_buf, "allocating scale buffer"); - err=-14; - goto exit; - } - } - else rd_len = img_xlen * 3; - - // ** ***************************************************** ** - // ** BMP images are stored in file from LAST to FIRST line ** - // ** ***************************************************** ** - - /* Used variables: - img_xsize horizontal image size in pixels - img_ysize number of image lines - img_xlen image display horizontal scaled size in pixels - img_ylen image display vertical scaled size in pixels - img_xstart first pixel in line to be displayed - img_ystart first image line to be displayed - img_xlen number of pixels in image line to be displayed, starting with 'img_xstart' - img_ylen number of lines in image to be displayed, starting with 'img_ystart' - rd_len length of color data which are read from image line in bytes - */ - - // Set position in image to the first color data (beginning of the LAST line) - img_pos += (img_ystart * (img_xsize*3)); - if (fhndl) { - if (fseek(fhndl, img_pos, SEEK_SET) != 0) { - sprintf(err_buf, "file seek at %d", img_pos); - err = -15; - goto exit; - } - } - - if (image_debug) printf("BMP: image size: (%d,%d) scale: %d disp size: (%d,%d) img xofs: %d img yofs: %d at: %d,%d; line buf: 2* %d scale buf: %d\r\n", - img_xsize, img_ysize, scale_pix, img_xlen, img_ylen, img_xstart, img_ystart, disp_xstart, disp_ystart, img_xsize*3, ((scale) ? (rd_len*scale_pix) : 0)); - - // * Select the display - //disp_select(); - - while ((disp_yend >= disp_ystart) && ((img_pos + (img_xsize*3)) <= size)) { - if (img_pos > size) { - sprintf(err_buf, "EOF reached: %d > %d", img_pos, size); - err = -16; - goto exit1; - } - if (scale == 0) { - // Read the line of color data into color buffer - if (fhndl) { - i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file - if (i != (img_xsize*3)) { - sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3); - err = -16; - goto exit1; - } - } - else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3); - - if (img_xstart > 0) memmove(line_buf[lb_idx], line_buf[lb_idx]+(img_xstart*3), rd_len); - // Convert colors BGR-888 (BMP) -> RGB-888 (DISPLAY) === - for (i=0; i < rd_len; i += 3) { - tmpc = line_buf[lb_idx][i+2] & 0xfc; // save R - line_buf[lb_idx][i+2] = line_buf[lb_idx][i] & 0xfc; // B -> R - line_buf[lb_idx][i] = tmpc; // R -> B - line_buf[lb_idx][i+1] &= 0xfc; // G - } - img_pos += (img_xsize*3); - } - else { - // scale image, read 'scale_pix' lines and find the average color - for (scan_lines=0; scan_lines size) break; - if (fhndl) { - i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file - if (i != (img_xsize*3)) { - sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3); - err = -17; - goto exit1; - } - } - else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3); - img_pos += (img_xsize*3); - - // copy only data which are displayed to scale buffer - memcpy(scale_buf + (rd_len * scan_lines), line_buf[lb_idx]+img_xstart, rd_len); - } - - // Populate display line buffer - for (int n=0;n<(img_xlen*3);n += 3) { - memset(co, 0, sizeof(co)); // initialize color sum - npix = 0; // initialize number of pixels in scale rectangle - - // sum all pixels in scale rectangle - for (int sc_line=0; sc_line RGB-888 (DISPLAY) - line_buf[lb_idx][n+2] = (uint8_t)(co[0] / npix); // B - line_buf[lb_idx][n+1] = (uint8_t)(co[1] / npix); // G - line_buf[lb_idx][n] = (uint8_t)(co[2] / npix); // R - } - } - - //wait_trans_finish(1); - //send_data(disp_xstart, disp_yend, disp_xend, disp_yend, img_xlen, (color_t *)line_buf[lb_idx]); - lb_idx = (lb_idx + 1) & 1; // change buffer - - disp_yend--; - } - err = 0; -exit1: - //disp_deselect(); -exit: - if (scale_buf) free(scale_buf); - if (line_buf[0]) free(line_buf[0]); - if (line_buf[1]) free(line_buf[1]); - if (fhndl) fclose(fhndl); - if ((err) && (image_debug)) printf("Error: %d [%s]\r\n", err, err_buf); - - //return err; -} \ No newline at end of file diff --git a/src/imagePNG.cpp b/src/imagePNG.cpp new file mode 100644 index 0000000..23dfc72 --- /dev/null +++ b/src/imagePNG.cpp @@ -0,0 +1,69 @@ +#include +#include "imagePNG.h" +#include "pngle.h" +#include "SPIFFS.h" +#include "display.h" + + +void on_draw(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]); + +void setupImagePNG() +{ + SPIFFS.begin(); + displayOpen(); + + pngle_t *pngle = pngle_new(); + pngle_set_draw_callback(pngle, on_draw); + + File file = SPIFFS.open("/blackPNG.png", "r"); + if (!file) + { + Serial.println(" file not found"); + } + + // get filesize + long size = file.size(); + + // read contents of the file into the vector + char *buffer = (char *)malloc((unsigned long)size); + if (!buffer) + { + file.close(); + Serial.println(" allow failedd"); + } + file.readBytes(buffer, (size_t)size); + file.close(); + + Serial.println(" read png"); + int ret = pngle_feed(pngle, buffer, size); + + //Serial.println(" return: " + ret); + //Serial.println(" width: " + pngle_get_width(pngle)); + //Serial.println(" height: " + pngle_get_height(pngle)); + + Serial.println(" read png done"); + pngle_destroy(pngle); + + displayFlush(); +} + + +void on_draw(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]) +{ + uint8_t r = rgba[0]; // 0 - 255 + uint8_t g = rgba[1]; // 0 - 255 + uint8_t b = rgba[2]; // 0 - 255 + uint8_t a = rgba[3]; // 0: fully transparent, 255: fully opaque + + if (a) + { + // 640 x 384 + if (true) // x == 0 + { + //printf("put pixel at (%d, %d) with color #%02x%02x%02x\n", x, y, r, g, b); + } + + displayWritePixel(x, y, r); + } +} + diff --git a/src/imageWBMP.cpp b/src/imageWBMP.cpp new file mode 100644 index 0000000..7432d9a --- /dev/null +++ b/src/imageWBMP.cpp @@ -0,0 +1,49 @@ +#include "imageWBMP.h" +#include "display.h" + +uint8_t _buffer[(GxEPD2_750::WIDTH / 8) * GxEPD2_750::HEIGHT]; + + +void setupImageWBMP() +{ + Serial.println("setupWBMP"); + + + Serial.println("setupWBMP done"); +} + +void wbmpOpenFramebuffer() +{ + memset(_buffer, 0, sizeof(_buffer)); +} + + +// TODO do it better :-) +void wbmpWriteFramebuffer(int offset, uint8_t bitmap[], int c) +{ + for (int i = 0; i < c; i++) + { + _buffer[offset] = bitmap[i]; + offset++; + } + + /* + if (offset + sizeof(*bitmap) <= sizeof(_buffer)) + if (true) + { + memcpy((&_buffer) + offset, bitmap, 128); + } + else + { + Serial.println("!!!!! displayWriteFramebuffer overflow"); + } + */ +} + + +void wbmpFlushFramebuffer() +{ + Serial.println("wbmpFlushFramebuffer"); + displayWriteFramebuffer(_buffer); + displayFlush(); +} \ No newline at end of file