basic png decoder added

pull/1/head
Thomas Ballmann 4 years ago
parent ee784749df
commit 1e4f4e316a

@ -4,13 +4,13 @@
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
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

@ -0,0 +1,6 @@
#ifndef IMAGE_PNG_H
#define IMAGE_PNG_H
void setupImagePNG();
#endif

@ -0,0 +1,12 @@
#ifndef IMAGE_WBMP_H
#define IMAGE_WBMP_H
#include <Arduino.h>
void setupImageWBMP();
void wbmpOpenFramebuffer();
void wbmpWriteFramebuffer(int offset, uint8_t bitmap[], int c);
void wbmpFlushFramebuffer();
#endif

@ -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();
}
}
}

@ -12,9 +12,7 @@
// enable or disable GxEPD2_GFX base class
#define ENABLE_GxEPD2_GFX 0
GxEPD2_BW<GxEPD2_750, GxEPD2_750::HEIGHT> display(GxEPD2_750(/*CS=*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
uint8_t _buffer[(GxEPD2_750::WIDTH / 8) * GxEPD2_750::HEIGHT];
GxEPD2_BW<GxEPD2_750, GxEPD2_750::HEIGHT> 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!";

@ -1,298 +0,0 @@
#include <Arduino.h>
#include <sys/stat.h>
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<uint8_t *>(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<uint8_t *>(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<uint8_t *>(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<scale_pix; scan_lines++) {
if (img_pos > 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<scan_lines; sc_line++) {
// Get colors position in scale buffer
img_pix_pos = (rd_len * sc_line) + (n * scale_pix);
for (int sc_col=0; sc_col<scale_pix; sc_col++) {
co[0] += scale_buf[img_pix_pos];
co[1] += scale_buf[img_pix_pos + 1];
co[2] += scale_buf[img_pix_pos + 2];
npix++;
}
}
// Place the average in display buffer, convert BGR-888 (BMP) -> 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;
}

@ -0,0 +1,69 @@
#include <Arduino.h>
#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);
}
}

@ -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();
}
Loading…
Cancel
Save