From c7e0781d2101df085f44ba2ac01684f60f370acd Mon Sep 17 00:00:00 2001 From: nitko12 Date: Thu, 10 Sep 2020 08:04:45 +0200 Subject: [PATCH] Partial speed up. --- .../11-Inkplate_SD_JPEG_pictures.ino | 54 ++++---- src/Inkplate.cpp | 126 +++++++---------- src/Inkplate.h | 5 +- src/include/GFX.cpp | 2 +- src/include/GFX.h | 6 +- src/include/Image.cpp | 2 +- src/include/Image.h | 22 +-- src/include/ImageBMP.cpp | 98 +++++++------ src/include/ImageDither.cpp | 23 +++- src/include/ImageJPEG.cpp | 130 +++++++++++------- src/include/Network.cpp | 39 +++++- src/include/Network.h | 3 +- test/flappyBird/flappyBird.ino | 5 +- test/test.ino | 4 +- 14 files changed, 299 insertions(+), 220 deletions(-) diff --git a/examples/2. Advanced Inkplate Features/11-Inkplate_SD_JPEG_pictures/11-Inkplate_SD_JPEG_pictures.ino b/examples/2. Advanced Inkplate Features/11-Inkplate_SD_JPEG_pictures/11-Inkplate_SD_JPEG_pictures.ino index 60599fb..b1c03d7 100644 --- a/examples/2. Advanced Inkplate Features/11-Inkplate_SD_JPEG_pictures/11-Inkplate_SD_JPEG_pictures.ino +++ b/examples/2. Advanced Inkplate Features/11-Inkplate_SD_JPEG_pictures/11-Inkplate_SD_JPEG_pictures.ino @@ -20,42 +20,50 @@ 31 August 2020 by e-radionica.com */ -#include "Inkplate.h" //Include Inkplate library to the sketch -#include "SdFat.h" //Include library for SD card -Inkplate display(INKPLATE_1BIT); //Create an object on Inkplate library and also set library into 1 Bit mode (Monochrome) -SdFile file; //Create SdFile object used for accessing files on SD card +#include "Inkplate.h" //Include Inkplate library to the sketch +#include "SdFat.h" //Include library for SD card +Inkplate display( + INKPLATE_1BIT); // Create an object on Inkplate library and also set library into 1 Bit mode (Monochrome) +SdFile file; // Create SdFile object used for accessing files on SD card -void setup() { - display.begin(); //Init Inkplate library (you should call this function ONLY ONCE) - display.clearDisplay(); //Clear frame buffer of display - display.display(); //Put clear image on display +void setup() +{ + display.begin(); // Init Inkplate library (you should call this function ONLY ONCE) + display.clearDisplay(); // Clear frame buffer of display + display.display(); // Put clear image on display - //Init SD card. Display if SD card is init propery or not. - if (display.sdCardInit()) { + // Init SD card. Display if SD card is init propery or not. + if (display.sdCardInit()) + { display.println("SD Card OK! Reading image..."); display.partialUpdate(); - //If card is properly init, try to load image and display it on e-paper at position X=100, Y=0 - //NOTE: These methods require you to pass a reference to the display object as first parameter. - //NOTE: Both drawJpegFromSD methods allow for an optional sixth "invert" parameter. Setting this parameter to true - //will flip all colors on the image, making black white and white black. - //fifth parameter will dither the image. - if (!display.drawJpegFromSD(&display, "pyramid.jpg", 100, 0, true, false)) { - //If is something failed (wrong filename or wrong format), write error message on the screen. - //You can turn off dithering for somewhat faster image load by changing the fifth parameter to false, or removing the parameter completely + // If card is properly init, try to load image and display it on e-paper at position X=100, Y=0 + // NOTE: These methods require you to pass a reference to the display object as first parameter. + // NOTE: Both drawJpegFromSd methods allow for an optional sixth "invert" parameter. Setting this parameter to + // true will flip all colors on the image, making black white and white black. fifth parameter will dither the + // image. + if (!display.drawJpegFromSd(&display, "pyramid.jpg", 100, 0, true, false)) + { + // If is something failed (wrong filename or wrong format), write error message on the screen. + // You can turn off dithering for somewhat faster image load by changing the fifth parameter to false, or + // removing the parameter completely display.println("Image open error"); display.display(); } display.display(); } - else { - //If SD card init not success, display error on screen and stop the program (using infinite loop) + else + { + // If SD card init not success, display error on screen and stop the program (using infinite loop) display.println("SD Card error!"); display.partialUpdate(); - while (true); + while (true) + ; } } -void loop() { - //Nothing... +void loop() +{ + // Nothing... } diff --git a/src/Inkplate.cpp b/src/Inkplate.cpp index b795448..209c968 100644 --- a/src/Inkplate.cpp +++ b/src/Inkplate.cpp @@ -98,6 +98,9 @@ Inkplate::Inkplate(uint8_t _mode) : GFX(E_INK_WIDTH, E_INK_HEIGHT) { setDisplayMode(_mode); + for (uint32_t i = 0; i < 256; ++i) + pinLUT[i] = ((i & B00000011) << 4) | (((i & B00001100) >> 2) << 18) | (((i & B00010000) >> 4) << 23) | + (((i & B11100000) >> 5) << 25); } void Inkplate::begin(void) @@ -141,19 +144,19 @@ void Inkplate::begin(void) // Battery voltage Switch MOSFET pinModeMCP(9, OUTPUT); - D_memory_new = (uint8_t *)ps_malloc(600 * 100); + DMemoryNew = (uint8_t *)ps_malloc(600 * 100); _partial = (uint8_t *)ps_malloc(600 * 100); _pBuffer = (uint8_t *)ps_malloc(120000); D_memory4Bit = (uint8_t *)ps_malloc(240000); - if (D_memory_new == NULL || _partial == NULL || _pBuffer == NULL || D_memory4Bit == NULL) + if (DMemoryNew == NULL || _partial == NULL || _pBuffer == NULL || D_memory4Bit == NULL) { do { delay(100); } while (true); } - memset(D_memory_new, 0, 60000); + memset(DMemoryNew, 0, 60000); memset(_partial, 0, 60000); memset(_pBuffer, 0, 120000); memset(D_memory4Bit, 255, 240000); @@ -189,11 +192,8 @@ void Inkplate::display() void Inkplate::display1b() { - for (int i = 0; i < 60000; i++) - { - *(D_memory_new + i) &= *(_partial + i); - *(D_memory_new + i) |= (*(_partial + i)); - } + memcpy(DMemoryNew, _partial, 60000); + uint16_t _pos; uint32_t _send; uint8_t data; @@ -207,34 +207,30 @@ void Inkplate::display1b() cleanFast(1, 12); cleanFast(2, 1); cleanFast(0, 11); - for (int k = 0; k < 3; k++) + for (int k = 0; k < 3; ++k) { _pos = 59999; vscan_start(); - for (int i = 0; i < 600; i++) + for (int i = 0; i < 600; ++i) { - dram = *(D_memory_new + _pos); + dram = *(DMemoryNew + _pos); data = LUTB[(dram >> 4) & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; hscan_start(_send); data = LUTB[dram & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; _pos--; - for (int j = 0; j < 99; j++) + for (int j = 0; j < 99; ++j) { - dram = *(D_memory_new + _pos); + dram = *(DMemoryNew + _pos); data = LUTB[(dram >> 4) & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | - (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; data = LUTB[dram & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | - (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; _pos--; @@ -248,30 +244,26 @@ void Inkplate::display1b() _pos = 59999; vscan_start(); - for (int i = 0; i < 600; i++) + for (int i = 0; i < 600; ++i) { - dram = *(D_memory_new + _pos); + dram = *(DMemoryNew + _pos); data = LUT2[(dram >> 4) & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; hscan_start(_send); data = LUT2[dram & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; _pos--; - for (int j = 0; j < 99; j++) + for (int j = 0; j < 99; ++j) { - dram = *(D_memory_new + _pos); + dram = *(DMemoryNew + _pos); data = LUT2[(dram >> 4) & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; data = LUT2[dram & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; _pos--; @@ -283,18 +275,16 @@ void Inkplate::display1b() delayMicroseconds(230); vscan_start(); - for (int i = 0; i < 600; i++) + for (int i = 0; i < 600; ++i) { - dram = *(D_memory_new + _pos); + dram = *(DMemoryNew + _pos); data = 0b00000000; - ; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; hscan_start(_send); data = 0b00000000; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - for (int j = 0; j < 99; j++) + for (int j = 0; j < 99; ++j) { GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; @@ -338,8 +328,8 @@ void Inkplate::display3b() vscan_start(); for (int i = 0; i < 600; ++i) { - pixel = 0B00000000; - pixel2 = 0B00000000; + pixel = 0; + pixel2 = 0; pix1 = *(dp--); pix2 = *(dp--); pix3 = *(dp--); @@ -349,19 +339,16 @@ void Inkplate::display3b() pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); - _send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | - (((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25); + _send = pinLUT[pixel]; hscan_start(_send); - _send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | - (((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25); + _send = pinLUT[pixel2]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - for (int j = 0; j < 99; j++) + for (int j = 0; j < 99; ++j) { - - pixel = 0B00000000; - pixel2 = 0B00000000; + pixel = 0; + pixel2 = 0; pix1 = *(dp--); pix2 = *(dp--); pix3 = *(dp--); @@ -371,13 +358,11 @@ void Inkplate::display3b() pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); - _send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | - (((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25); + _send = pinLUT[pixel]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - _send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | - (((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25); + _send = pinLUT[pixel2]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; } @@ -399,6 +384,7 @@ void Inkplate::partialUpdate() return; if (_blockPartial == 1) display1b(); + uint16_t _pos = 59999; uint32_t _send; uint8_t data; @@ -410,8 +396,8 @@ void Inkplate::partialUpdate() { for (int j = 0; j < 100; ++j) { - diffw = ((*(D_memory_new + _pos)) ^ (*(_partial + _pos))) & (~(*(_partial + _pos))); - diffb = ((*(D_memory_new + _pos)) ^ (*(_partial + _pos))) & ((*(_partial + _pos))); + diffw = *(DMemoryNew + _pos) & ~*(_partial + _pos); + diffb = ~*(DMemoryNew + _pos) & *(_partial + _pos); _pos--; *(_pBuffer + n) = LUTW[diffw >> 4] & (LUTB[diffb >> 4]); n--; @@ -428,20 +414,18 @@ void Inkplate::partialUpdate() for (int i = 0; i < 600; ++i) { data = *(_pBuffer + n); - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); + _send = pinLUT[data]; hscan_start(_send); n--; - for (int j = 0; j < 199; j++) + for (int j = 0; j < 199; ++j) { data = *(_pBuffer + n); - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | - (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; + _send = pinLUT[data]; + GPIO.out_w1ts = _send | CL; GPIO.out_w1tc = DATA | CL; n--; } - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = _send | CL; GPIO.out_w1tc = DATA | CL; vscan_end(); } @@ -451,12 +435,8 @@ void Inkplate::partialUpdate() cleanFast(3, 1); vscan_start(); einkOff(); - einkOff(); - for (int i = 0; i < 60000; ++i) - { - *(D_memory_new + i) &= *(_partial + i); - *(D_memory_new + i) |= (*(_partial + i)); - } + + memcpy(DMemoryNew, _partial, 60000); } void Inkplate::clean() @@ -489,18 +469,16 @@ void Inkplate::cleanFast(uint8_t c, uint8_t rep) else if (c == 3) data = B11111111; - uint32_t _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | - (((data & B11100000) >> 5) << 25); - ; - for (int k = 0; k < rep; k++) + uint32_t _send = pinLUT[data]; + for (int k = 0; k < rep; ++k) { vscan_start(); - for (int i = 0; i < 600; i++) + for (int i = 0; i < 600; ++i) { hscan_start(_send); GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - for (int j = 0; j < 99; j++) + for (int j = 0; j < 99; ++j) { GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; diff --git a/src/Inkplate.h b/src/Inkplate.h index b08530d..e3a7864 100644 --- a/src/Inkplate.h +++ b/src/Inkplate.h @@ -38,10 +38,6 @@ class Inkplate : public System, public GFX { return Network::isConnected(); }; - uint8_t *downloadFile(const char *url, int32_t defaultLen) - { - return Network::downloadFile(url, defaultLen); - }; private: void precalculateGamma(uint8_t *c, float gamma); @@ -56,6 +52,7 @@ class Inkplate : public System, public GFX void pinsZstate(); void pinsAsOutputs(); + uint32_t pinLUT[256]; uint8_t _beginDone = 0; diff --git a/src/include/GFX.cpp b/src/include/GFX.cpp index 1b0059e..2bc4c85 100644 --- a/src/include/GFX.cpp +++ b/src/include/GFX.cpp @@ -172,7 +172,7 @@ void GFX::selectDisplayMode(uint8_t _mode) if (_mode != _displayMode) { _displayMode = _mode & 1; - memset(D_memory_new, 0, 60000); + memset(DMemoryNew, 0, 60000); memset(_partial, 0, 60000); memset(_pBuffer, 0, 120000); memset(D_memory4Bit, 255, 240000); diff --git a/src/include/GFX.h b/src/include/GFX.h index 22e73d5..5421600 100644 --- a/src/include/GFX.h +++ b/src/include/GFX.h @@ -34,7 +34,7 @@ class GFX : public Shapes, public Image, public Font void setRotation(uint8_t r); uint8_t getRotation(); - void drawPixel(int16_t x, int16_t y, uint16_t color) override; + inline void drawPixel(int16_t x, int16_t y, uint16_t color) override; void selectDisplayMode(uint8_t _mode); @@ -43,7 +43,7 @@ class GFX : public Shapes, public Image, public Font int16_t width() override; int16_t height() override; - uint8_t *D_memory_new; + uint8_t *DMemoryNew; uint8_t *_partial; uint8_t *D_memory4Bit; uint8_t *_pBuffer; @@ -65,7 +65,7 @@ class GFX : public Shapes, public Image, public Font private: void startWrite(void) override; - void writePixel(int16_t x, int16_t y, uint16_t color) override; + inline void writePixel(int16_t x, int16_t y, uint16_t color) override; void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override; void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override; void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override; diff --git a/src/include/Image.cpp b/src/include/Image.cpp index df959c5..59b6de5 100644 --- a/src/include/Image.cpp +++ b/src/include/Image.cpp @@ -31,7 +31,7 @@ bool Image::drawImage(const char *path, int x, int y, bool dither, bool invert) if (strstr(path, ".bmp") != NULL) return drawBitmapFromSd(path, x, y, dither, invert); if (strstr(path, ".jpg") != NULL || strstr(path, ".jpeg") != NULL) - return drawJpegFromSD(path, x, y, dither, invert); + return drawJpegFromSd(path, x, y, dither, invert); } }; diff --git a/src/include/Image.h b/src/include/Image.h index a0a3f6b..0e1b857 100644 --- a/src/include/Image.h +++ b/src/include/Image.h @@ -28,17 +28,21 @@ class Image : virtual public Network uint16_t bg = 0xFFFF); void drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h); - bool drawBitmapFromSd(SdFile *p, int x, int y, bool dither = 0, bool invert = 0); + bool drawBitmapFromBuffer(uint8_t *buf, int x, int y, bool dither, bool invert); + bool drawBitmapFromSd(const char *fileName, int x, int y, bool dither = 0, bool invert = 0); + bool drawBitmapFromSd(SdFile *p, int x, int y, bool dither = 0, bool invert = 0); - bool drawBitmapFromWeb(WiFiClient *s, int x, int y, int len, bool dither = 0, bool invert = 0); bool drawBitmapFromWeb(const char *url, int x, int y, bool dither = 0, bool invert = 0); + bool drawBitmapFromWeb(WiFiClient *s, int x, int y, int32_t len, bool dither = 0, bool invert = 0); - bool drawJpegFromSD(const char *fileName, int x, int y, bool dither = 0, bool invert = 0); - bool drawJpegFromSD(SdFile *p, int x, int y, bool dither = 0, bool invert = 0); + bool drawJpegFromBuffer(uint8_t *buf, int32_t len, int x, int y, bool dither, bool invert); + + bool drawJpegFromSd(const char *fileName, int x, int y, bool dither = 0, bool invert = 0); + bool drawJpegFromSd(SdFile *p, int x, int y, bool dither = 0, bool invert = 0); bool drawJpegFromWeb(const char *url, int x, int y, bool dither = 0, bool invert = 0); - bool drawJpegFromWeb(WiFiClient *s, int x, int y, int len, bool dither = 0, bool invert = 0); + bool drawJpegFromWeb(WiFiClient *s, int x, int y, int32_t len, bool dither = 0, bool invert = 0); private: @@ -50,8 +54,7 @@ class Image : virtual public Network virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) = 0; virtual void endWrite(void) = 0; - static bool drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool _dither, - bool _invert); + static bool drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool dither, bool invert); uint8_t pixelBuffer[800 * 4 + 5]; uint8_t ditherBuffer[2][800 + 5]; @@ -60,9 +63,8 @@ class Image : virtual public Network bool legalBmp(bitmapHeader *bmpHeader); - void ditherStart(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits); - void ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits); - uint8_t ditherGetPixel(uint8_t px, int i, int w, bool paletted); + uint8_t ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted); + uint8_t ditherGetPixelJpeg(uint8_t px, int x, int y, int w); void ditherSwap(int w); void readBmpHeader(uint8_t *buf, bitmapHeader *_h); diff --git a/src/include/ImageBMP.cpp b/src/include/ImageBMP.cpp index 5657de3..c54b918 100644 --- a/src/include/ImageBMP.cpp +++ b/src/include/ImageBMP.cpp @@ -92,14 +92,6 @@ bool Image::drawBitmapFromSd(SdFile *p, int x, int y, bool dither, bool invert) if (!legalBmp(&bmpHeader)) return 0; - if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) - selectDisplayMode(INKPLATE_1BIT); - - if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 16 || bmpHeader.color == 24 || - bmpHeader.color == 32) && - getDisplayMode() != INKPLATE_3BIT) - selectDisplayMode(INKPLATE_3BIT); - int16_t w = bmpHeader.width, h = bmpHeader.height; int8_t c = bmpHeader.color; @@ -117,24 +109,38 @@ bool Image::drawBitmapFromSd(SdFile *p, int x, int y, bool dither, bool invert) bool Image::drawBitmapFromWeb(const char *url, int x, int y, bool dither, bool invert) { - uint8_t *buf = downloadFile(url, 800 * 600 * 4); + bool ret = 0; + int32_t defaultLen = 800 * 600 * 4; + uint8_t *buf = downloadFile(url, &defaultLen); + ret = drawBitmapFromBuffer(buf, x, y, dither, invert); + free(buf); + + return 1; +} + +bool Image::drawBitmapFromWeb(WiFiClient *s, int x, int y, int32_t len, bool dither, bool invert) +{ + bool ret = 0; + uint8_t *buf = downloadFile(s, len); + + ret = drawBitmapFromBuffer(buf, x, y, dither, invert); + free(buf); + + return 1; +} + +bool Image::drawBitmapFromBuffer(uint8_t *buf, int x, int y, bool dither, bool invert) +{ bitmapHeader bmpHeader; readBmpHeader(buf, &bmpHeader); if (!legalBmp(&bmpHeader)) return 0; - if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) - selectDisplayMode(INKPLATE_1BIT); - - if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 16 || bmpHeader.color == 24 || - bmpHeader.color == 32) && - getDisplayMode() != INKPLATE_3BIT) - selectDisplayMode(INKPLATE_3BIT); - if (dither) memset(ditherBuffer, 0, sizeof ditherBuffer); + uint8_t *bufferPtr = buf + bmpHeader.startRAW; for (int i = 0; i < bmpHeader.height; ++i) { @@ -144,7 +150,6 @@ bool Image::drawBitmapFromWeb(const char *url, int x, int y, bool dither, bool i } free(buf); - return 1; } @@ -167,14 +172,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d uint8_t val; if (dither) - val = ditherGetPixel(px, j, w, 1); + val = ditherGetPixelBmp(px, j, w, 1); else val = palette[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4); - if (invert) - writePixel(x + j, y, 7 - val); - else - writePixel(x + j, y, val); + val = 7 - val; + if (getDisplayMode() == INKPLATE_1BIT) + val = (~val >> 2) & 1; + + writePixel(x + j, y, val); break; } case 8: { @@ -182,16 +188,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d uint8_t val; if (dither) - val = ditherGetPixel(px, j, w, 1); + val = ditherGetPixelBmp(px, j, w, 1); else - { val = palette[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4); - } - if (invert) - writePixel(x + j, y, 7 - val); - else - writePixel(x + j, y, val); + val = 7 - val; + if (getDisplayMode() == INKPLATE_1BIT) + val = (~val >> 2) & 1; + + writePixel(x + j, y, val); break; } case 16: { @@ -204,14 +209,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d uint8_t val; if (dither) - val = ditherGetPixel(RGB8BIT(r, g, b), j, w, 0); + val = ditherGetPixelBmp(RGB8BIT(r, g, b), j, w, 0); else val = RGB3BIT(r, g, b); - if (invert) - writePixel(x + j, y, 7 - val); - else - writePixel(x + j, y, val); + val = 7 - val; + if (getDisplayMode() == INKPLATE_1BIT) + val = (~val >> 2) & 1; + + writePixel(x + j, y, val); break; } case 24: { @@ -222,14 +228,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d uint8_t val; if (dither) - val = ditherGetPixel(RGB8BIT(r, g, b), j, w, 0); + val = ditherGetPixelBmp(RGB8BIT(r, g, b), j, w, 0); else val = RGB3BIT(r, g, b); - if (invert) - writePixel(x + j, y, 7 - val); - else - writePixel(x + j, y, val); + val = 7 - val; + if (getDisplayMode() == INKPLATE_1BIT) + val = (~val >> 2) & 1; + + writePixel(x + j, y, val); break; } case 32: @@ -240,14 +247,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d uint8_t val; if (dither) - val = ditherGetPixel(RGB8BIT(r, g, b), j, w, 0); + val = ditherGetPixelBmp(RGB8BIT(r, g, b), j, w, 0); else val = RGB3BIT(r, g, b); - if (invert) - writePixel(x + j, y, 7 - RGB3BIT(r, g, b)); - else - writePixel(x + j, y, RGB3BIT(r, g, b)); + val = 7 - val; + if (getDisplayMode() == INKPLATE_1BIT) + val = (~val >> 2) & 1; + + writePixel(x + j, y, val); break; } } diff --git a/src/include/ImageDither.cpp b/src/include/ImageDither.cpp index d8bbd1f..f5447ef 100644 --- a/src/include/ImageDither.cpp +++ b/src/include/ImageDither.cpp @@ -1,13 +1,13 @@ #include "Image.h" -uint8_t Image::ditherGetPixel(uint8_t px, int i, int w, bool paletted) +uint8_t Image::ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted) { if (paletted) px = ditherPalette[px]; uint8_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)ditherBuffer[0][i] + px)); - uint8_t newPixel = oldPixel & B11100000; + uint8_t newPixel = oldPixel & (getDisplayMode() == INKPLATE_1BIT ? B10000000 : B11100000); uint8_t quantError = oldPixel - newPixel; ditherBuffer[1][i + 0] += (quantError * 5) >> 4; @@ -22,6 +22,25 @@ uint8_t Image::ditherGetPixel(uint8_t px, int i, int w, bool paletted) return newPixel >> 5; } +uint8_t Image::ditherGetPixelJpeg(uint8_t px, int x, int y, int w) +{ + uint8_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)ditherBuffer[0][x] + px)); + + uint8_t newPixel = oldPixel & (getDisplayMode() == INKPLATE_1BIT ? B10000000 : B11100000); + uint8_t quantError = oldPixel - newPixel; + + ditherBuffer[1][x + 0] += (quantError * 5) >> 4; + if (x != w - 1) + { + ditherBuffer[0][x + 1] += (quantError * 7) >> 4; + ditherBuffer[1][x + 1] += (quantError * 1) >> 4; + } + if (x != 0) + ditherBuffer[1][x - 1] += (quantError * 3) >> 4; + + return newPixel >> 5; +} + void Image::ditherSwap(int w) { for (int i = 0; i < w; ++i) diff --git a/src/include/ImageJPEG.cpp b/src/include/ImageJPEG.cpp index 21d47be..a54f4ba 100644 --- a/src/include/ImageJPEG.cpp +++ b/src/include/ImageJPEG.cpp @@ -8,7 +8,81 @@ extern Image *_imagePtrJpeg; -bool Image::drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool _dither, bool _invert) +bool Image::drawJpegFromSd(const char *fileName, int x, int y, bool dither, bool invert) +{ + SdFile dat; + if (dat.open(fileName, O_RDONLY)) + return drawJpegFromSd(&dat, x, y, dither, invert); + return 0; +} + +bool Image::drawJpegFromSd(SdFile *p, int x, int y, bool dither, bool invert) +{ + uint8_t ret = 0; + + TJpgDec.setJpgScale(1); + TJpgDec.setCallback(drawJpegChunk); + + uint32_t pnt = 0; + uint32_t total = p->fileSize(); + uint8_t *buff = (uint8_t *)ps_malloc(total); + + if (buff == NULL) + return 0; + + while (pnt < total) + { + uint32_t toread = p->available(); + if (toread > 0) + { + int read = p->read(buff + pnt, toread); + if (read > 0) + pnt += read; + } + } + p->close(); + + if (TJpgDec.drawJpg(x, y, buff, total, dither, invert) == 0) + ret = 1; + + free(buff); + + return ret; +} + +bool Image::drawJpegFromWeb(const char *url, int x, int y, bool dither, bool invert) +{ + bool ret = 0; + + int32_t defaultLen = 800 * 600 * 4; + uint8_t *buff = downloadFile(url, &defaultLen); + ret = drawJpegFromBuffer(buff, x, y, defaultLen, dither, invert); + free(buff); + + return ret; +} + +bool Image::drawJpegFromWeb(WiFiClient *s, int x, int y, int32_t len, bool dither, bool invert) +{ + bool ret = 0; + uint8_t *buff = downloadFile(s, len); + ret = drawJpegFromBuffer(buff, x, y, len, dither, invert); + free(buff); + + return ret; +} + +bool Image::drawJpegFromBuffer(uint8_t *buff, int32_t len, int x, int y, bool dither, bool invert) +{ + bool ret = 0; + + if (TJpgDec.drawJpg(x, y, buff, len, dither, invert) == 0) + ret = 1; + + return ret; +}; + +bool Image::drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool dither, bool invert) { if (!_imagePtrJpeg) return 0; @@ -19,57 +93,15 @@ bool Image::drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t for (int i = 0; i < w; ++i) { uint16_t rgb = bitmap[j * w + i]; - if (_invert) - _imagePtrJpeg->drawPixel(i + x, j + y, 7 - RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb))); - else - _imagePtrJpeg->drawPixel(i + x, j + y, RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb))); + uint8_t val = RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb)); + + if (invert) + val = 7 - val; + + _imagePtrJpeg->writePixel(x + i, y + j, val); } } _imagePtrJpeg->endWrite(); return 1; -} - -bool Image::drawJpegFromSD(const char *fileName, int x, int y, bool dither, bool invert) -{ - SdFile dat; - if (dat.open(fileName, O_RDONLY)) - return drawJpegFromSD(&dat, x, y, dither, invert); - return 0; -} - -bool Image::drawJpegFromSD(SdFile *p, int x, int y, bool dither, bool invert) -{ - uint8_t ret = 0; - - TJpgDec.setJpgScale(1); - TJpgDec.setCallback(drawJpegChunk); - - uint32_t pnt = 0; - uint32_t total = p->fileSize(); - uint8_t *buf = (uint8_t *)ps_malloc(total); - - if (buf == NULL) - return 0; - - while (pnt < total) - { - uint32_t toread = p->available(); - if (toread > 0) - { - int read = p->read(buf + pnt, toread); - if (read > 0) - pnt += read; - } - } - p->close(); - - selectDisplayMode(INKPLATE_3BIT); - - if (TJpgDec.drawJpg(x, y, buf, total, dither, invert) == 0) - ret = 1; - - free(buf); - - return ret; } \ No newline at end of file diff --git a/src/include/Network.cpp b/src/include/Network.cpp index 9cc6510..c1f38ed 100644 --- a/src/include/Network.cpp +++ b/src/include/Network.cpp @@ -28,7 +28,7 @@ bool Network::isConnected() } -uint8_t *Network::downloadFile(const char *url, int32_t defaultLen) +uint8_t *Network::downloadFile(const char *url, int32_t *defaultLen) { if (!isConnected()) return NULL; @@ -45,7 +45,9 @@ uint8_t *Network::downloadFile(const char *url, int32_t defaultLen) int32_t size = http.getSize(); if (size == -1) - size = defaultLen; + size = *defaultLen; + else + *defaultLen = size; uint8_t *buffer = (uint8_t *)ps_malloc(size); uint8_t *buffPtr = buffer; @@ -79,3 +81,36 @@ uint8_t *Network::downloadFile(const char *url, int32_t defaultLen) return buffer; } + +uint8_t *Network::downloadFile(WiFiClient *s, int32_t len) +{ + if (!isConnected()) + return NULL; + + bool sleep = WiFi.getSleep(); + WiFi.setSleep(false); + + uint8_t *buffer = (uint8_t *)ps_malloc(len); + uint8_t *buffPtr = buffer; + + uint8_t buff[128] = {0}; + + while (len > 0) + { + size_t size = s->available(); + if (size) + { + int c = s->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + memcpy(buffPtr, buff, c); + + if (len > 0) + len -= c; + buffPtr += c; + } + yield(); + } + + WiFi.setSleep(sleep); + + return buffer; +} \ No newline at end of file diff --git a/src/include/Network.h b/src/include/Network.h index 4536204..7f7e6c6 100644 --- a/src/include/Network.h +++ b/src/include/Network.h @@ -25,7 +25,8 @@ class Network void disconnect(); bool isConnected(); - uint8_t *downloadFile(const char *url, int32_t defaultLen); + uint8_t *downloadFile(const char *url, int32_t *defaultLen); + uint8_t *downloadFile(WiFiClient *url, int32_t len); private: }; diff --git a/test/flappyBird/flappyBird.ino b/test/flappyBird/flappyBird.ino index a6004a1..f50e1e0 100644 --- a/test/flappyBird/flappyBird.ino +++ b/test/flappyBird/flappyBird.ino @@ -14,11 +14,12 @@ void setup() void loop() { - int32_t t = millis(); + display.drawBitmap(offSet, 0, (uint8_t *)bck_day, bck_day_w, bck_day_h, BLACK); + int32_t t = millis(); display.partialUpdate(); - display.clearDisplay(); Serial.println(millis() - t); + display.clearDisplay(); offSet += 70; offSet %= 300; } \ No newline at end of file diff --git a/test/test.ino b/test/test.ino index 00f1ebf..1cf5cfe 100644 --- a/test/test.ino +++ b/test/test.ino @@ -1,6 +1,6 @@ #include "Inkplate.h" #include "SdFat.h" -Inkplate display(INKPLATE_3BIT); +Inkplate display(INKPLATE_1BIT); void setup() { @@ -30,9 +30,7 @@ void loop() if (display.sdCardInit()) { - int16_t t = millis(); Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 1, 0)); - Serial.println(millis() - t); } display.display();