diff --git a/tasmota/support_jpeg.ino b/tasmota/support_jpeg.ino
new file mode 100644
index 000000000..7e811cd76
--- /dev/null
+++ b/tasmota/support_jpeg.ino
@@ -0,0 +1,157 @@
+/*
+ jpeg_utils.c - Version header file for Tasmota
+
+ Copyright (C) 2020 Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+#ifdef ESP32
+#ifdef JPEG_PICTS
+
+#include "img_converters.h"
+#include "esp_jpg_decode.h"
+
+void rgb888_to_565(uint8_t *in, uint16_t *out, uint32_t len) {
+uint8_t red, grn, blu;
+uint16_t b , g, r;
+
+ for (uint32_t cnt=0; cnt> 3) & 0x1f;
+ g = ((grn >> 2) & 0x3f) << 5;
+ r = ((red >> 3) & 0x1f) << 11;
+ *out++ = (r | g | b);
+ }
+}
+
+typedef struct {
+ uint16_t width;
+ uint16_t height;
+ uint16_t data_offset;
+ const uint8_t *input;
+ uint8_t *output;
+} rgb_jpg_decoder;
+
+//input buffer
+static uint32_t _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
+{
+ rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
+ if(buf) {
+ memcpy(buf, jpeg->input + index, len);
+ }
+ return len;
+}
+
+//output buffer and image width
+static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
+{
+ rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
+ if(!data){
+ if(x == 0 && y == 0){
+ //write start
+ jpeg->width = w;
+ jpeg->height = h;
+ //if output is null, this is BMP
+ if(!jpeg->output){
+ jpeg->output = (uint8_t *)malloc((w*h*3)+jpeg->data_offset);
+ if(!jpeg->output){
+ return false;
+ }
+ }
+ } else {
+ //write end
+ }
+ return true;
+ }
+
+ size_t jw = jpeg->width*3;
+ size_t t = y * jw;
+ size_t b = t + (h * jw);
+ size_t l = x * 3;
+ uint8_t *out = jpeg->output+jpeg->data_offset;
+ uint8_t *o = out;
+ size_t iy, ix;
+
+ w = w * 3;
+
+ for(iy=t; iy= data_size) return false; //Check to protect against segmentation faults
+ if(data[i] != 0xFF) return false; //Check that we are truly at the start of another block
+ if(data[i+1] == 0xC0) { //0xFFC0 is the "Start of frame" marker which contains the file size
+ //The structure of the 0xFFC0 block is quite simple [0xFFC0][ushort length][uchar precision][ushort x][ushort y]
+ *height = data[i+5]*256 + data[i+6];
+ *width = data[i+7]*256 + data[i+8];
+ return true;
+ }
+ else
+ {
+ i+=2; //Skip the block marker
+ block_length = data[i] * 256 + data[i+1]; //Go to the next block
+ }
+ }
+ return false; //If this point is reached then no size was found
+ }else{ return false; } //Not a valid JFIF string
+
+ }else{ return false; } //Not a valid SOI header
+}
+
+#endif // JPEG_PICTS
+#endif //ESP32
diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino
index e490d0bd1..2d0ef4f0f 100644
--- a/tasmota/xdrv_13_display.ino
+++ b/tasmota/xdrv_13_display.ino
@@ -1500,47 +1500,109 @@ void CmndDisplayRows(void)
/*********************************************************************************************\
* optional drivers
\*********************************************************************************************/
+#ifdef ESP32
+#ifdef JPEG_PICTS
+#include "img_converters.h"
+#include "esp_jpg_decode.h"
+bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale);
+char get_jpeg_size(unsigned char* data, unsigned int data_size, unsigned short *width, unsigned short *height);
+void rgb888_to_565(uint8_t *in, uint16_t *out, uint32_t len);
+#endif
+#endif
+
#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT)
+#define XBUFF_LEN 128
void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp) {
if (!renderer) return;
-
- //if (!strstr(file,".RGB")) return;
File fp;
- fp=SD.open(file,FILE_READ);
- if (!fp) return;
- uint16_t xsize;
- fp.read((uint8_t*)&xsize,2);
- uint16_t ysize;
- fp.read((uint8_t*)&ysize,2);
+ char *ending = strrchr(file,'.');
+ if (!ending) return;
+ ending++;
+ char estr[8];
+ memset(estr,0,sizeof(estr));
+ for (uint32_t cnt=0; cntsetAddrWindow(xp,yp,xp+xsize,yp+ysize);
- for(int16_t j=0; j=2) renderer->pushColors(rgb,len/2,true);
+ uint16_t xdiv=xsize/XBUFF_LEN;
+ renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize);
+ for(int16_t j=0; j=2) renderer->pushColors(rgb,len/2,true);
+ }
+ OsWatchLoop();
}
- OsWatchLoop();
- }
- renderer->setAddrWindow(0,0,0,0);
+ renderer->setAddrWindow(0,0,0,0);
#else
- for(int16_t j=0; jwritePixel(xp+i,yp,rgb);
+ for(int16_t j=0; jwritePixel(xp+i,yp,rgb);
+ }
+ delay(0);
+ OsWatchLoop();
+ yp++;
}
- delay(0);
- OsWatchLoop();
- yp++;
- }
#endif
- fp.close();
+ fp.close();
+ } else if (!strcmp(estr,"jpg")) {
+ // jpeg files on ESP32 with more memory
+#ifdef ESP32
+#ifdef JPEG_PICTS
+ if (psramFound()) {
+ fp=SD.open(file,FILE_READ);
+ if (!fp) return;
+ uint32_t size = fp.size();
+ uint8_t *mem = (uint8_t *)heap_caps_malloc(size+4, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
+ if (mem) {
+ uint8_t res=fp.read(mem, size);
+ if (res) {
+ uint16_t xsize;
+ uint16_t ysize;
+ if (mem[0]==0xff && mem[1]==0xd8) {
+ get_jpeg_size(mem, size, &xsize, &ysize);
+ Serial.printf(" x,y %d - %d\n",xsize, ysize );
+ if (xsize && ysize) {
+ uint8_t *out_buf = (uint8_t *)heap_caps_malloc((xsize*ysize*3)+4, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
+ if (out_buf) {
+ uint8_t *ob=out_buf;
+ jpg2rgb888(mem, size, out_buf, (jpg_scale_t)JPG_SCALE_NONE);
+ uint16_t pixels=xsize*ysize/XBUFF_LEN;
+ renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize);
+ for(int32_t j=0; jpushColors(rbuff,XBUFF_LEN,true);
+ OsWatchLoop();
+ }
+ renderer->setAddrWindow(0,0,0,0);
+ free(out_buf);
+ }
+ }
+ }
+ }
+ free(mem);
+ }
+ fp.close();
+ }
+#endif // JPEG_PICTS
+#endif // ESP32
+ }
}
#endif