Partial speed up.

This commit is contained in:
nitko12 2020-09-10 08:04:45 +02:00
parent 82a082003a
commit c7e0781d21
14 changed files with 299 additions and 220 deletions

View File

@ -20,42 +20,50 @@
31 August 2020 by e-radionica.com 31 August 2020 by e-radionica.com
*/ */
#include "Inkplate.h" //Include Inkplate library to the sketch #include "Inkplate.h" //Include Inkplate library to the sketch
#include "SdFat.h" //Include library for SD card #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) Inkplate display(
SdFile file; //Create SdFile object used for accessing files on SD card 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() { void setup()
display.begin(); //Init Inkplate library (you should call this function ONLY ONCE) {
display.clearDisplay(); //Clear frame buffer of display display.begin(); // Init Inkplate library (you should call this function ONLY ONCE)
display.display(); //Put clear image on display 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. // Init SD card. Display if SD card is init propery or not.
if (display.sdCardInit()) { if (display.sdCardInit())
{
display.println("SD Card OK! Reading image..."); display.println("SD Card OK! Reading image...");
display.partialUpdate(); display.partialUpdate();
//If card is properly init, try to load image and display it on e-paper at position X=100, Y=0 // 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: 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 // NOTE: Both drawJpegFromSd methods allow for an optional sixth "invert" parameter. Setting this parameter to
//will flip all colors on the image, making black white and white black. // true will flip all colors on the image, making black white and white black. fifth parameter will dither the
//fifth parameter will dither the image. // image.
if (!display.drawJpegFromSD(&display, "pyramid.jpg", 100, 0, true, false)) { 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 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.println("Image open error");
display.display(); display.display();
} }
display.display(); display.display();
} }
else { else
//If SD card init not success, display error on screen and stop the program (using infinite loop) {
// If SD card init not success, display error on screen and stop the program (using infinite loop)
display.println("SD Card error!"); display.println("SD Card error!");
display.partialUpdate(); display.partialUpdate();
while (true); while (true)
;
} }
} }
void loop() { void loop()
//Nothing... {
// Nothing...
} }

View File

@ -98,6 +98,9 @@
Inkplate::Inkplate(uint8_t _mode) : GFX(E_INK_WIDTH, E_INK_HEIGHT) Inkplate::Inkplate(uint8_t _mode) : GFX(E_INK_WIDTH, E_INK_HEIGHT)
{ {
setDisplayMode(_mode); 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) void Inkplate::begin(void)
@ -141,19 +144,19 @@ void Inkplate::begin(void)
// Battery voltage Switch MOSFET // Battery voltage Switch MOSFET
pinModeMCP(9, OUTPUT); 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); _partial = (uint8_t *)ps_malloc(600 * 100);
_pBuffer = (uint8_t *)ps_malloc(120000); _pBuffer = (uint8_t *)ps_malloc(120000);
D_memory4Bit = (uint8_t *)ps_malloc(240000); 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 do
{ {
delay(100); delay(100);
} while (true); } while (true);
} }
memset(D_memory_new, 0, 60000); memset(DMemoryNew, 0, 60000);
memset(_partial, 0, 60000); memset(_partial, 0, 60000);
memset(_pBuffer, 0, 120000); memset(_pBuffer, 0, 120000);
memset(D_memory4Bit, 255, 240000); memset(D_memory4Bit, 255, 240000);
@ -189,11 +192,8 @@ void Inkplate::display()
void Inkplate::display1b() void Inkplate::display1b()
{ {
for (int i = 0; i < 60000; i++) memcpy(DMemoryNew, _partial, 60000);
{
*(D_memory_new + i) &= *(_partial + i);
*(D_memory_new + i) |= (*(_partial + i));
}
uint16_t _pos; uint16_t _pos;
uint32_t _send; uint32_t _send;
uint8_t data; uint8_t data;
@ -207,34 +207,30 @@ void Inkplate::display1b()
cleanFast(1, 12); cleanFast(1, 12);
cleanFast(2, 1); cleanFast(2, 1);
cleanFast(0, 11); cleanFast(0, 11);
for (int k = 0; k < 3; k++) for (int k = 0; k < 3; ++k)
{ {
_pos = 59999; _pos = 59999;
vscan_start(); 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]; data = LUTB[(dram >> 4) & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
hscan_start(_send); hscan_start(_send);
data = LUTB[dram & 0x0F]; data = LUTB[dram & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
_pos--; _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]; data = LUTB[(dram >> 4) & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | _send = pinLUT[data];
(((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
data = LUTB[dram & 0x0F]; data = LUTB[dram & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | _send = pinLUT[data];
(((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
_pos--; _pos--;
@ -248,30 +244,26 @@ void Inkplate::display1b()
_pos = 59999; _pos = 59999;
vscan_start(); 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]; data = LUT2[(dram >> 4) & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
hscan_start(_send); hscan_start(_send);
data = LUT2[dram & 0x0F]; data = LUT2[dram & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
_pos--; _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]; data = LUT2[(dram >> 4) & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
data = LUT2[dram & 0x0F]; data = LUT2[dram & 0x0F];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
_pos--; _pos--;
@ -283,18 +275,16 @@ void Inkplate::display1b()
delayMicroseconds(230); delayMicroseconds(230);
vscan_start(); 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; data = 0b00000000;
; _send = pinLUT[data];
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
hscan_start(_send); hscan_start(_send);
data = 0b00000000; data = 0b00000000;
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | 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_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
@ -338,8 +328,8 @@ void Inkplate::display3b()
vscan_start(); vscan_start();
for (int i = 0; i < 600; ++i) for (int i = 0; i < 600; ++i)
{ {
pixel = 0B00000000; pixel = 0;
pixel2 = 0B00000000; pixel2 = 0;
pix1 = *(dp--); pix1 = *(dp--);
pix2 = *(dp--); pix2 = *(dp--);
pix3 = *(dp--); pix3 = *(dp--);
@ -349,19 +339,16 @@ void Inkplate::display3b()
pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) |
(waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0);
_send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | _send = pinLUT[pixel];
(((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25);
hscan_start(_send); hscan_start(_send);
_send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | _send = pinLUT[pixel2];
(((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
for (int j = 0; j < 99; j++) for (int j = 0; j < 99; ++j)
{ {
pixel = 0;
pixel = 0B00000000; pixel2 = 0;
pixel2 = 0B00000000;
pix1 = *(dp--); pix1 = *(dp--);
pix2 = *(dp--); pix2 = *(dp--);
pix3 = *(dp--); pix3 = *(dp--);
@ -371,13 +358,11 @@ void Inkplate::display3b()
pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) |
(waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0);
_send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | _send = pinLUT[pixel];
(((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
_send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | _send = pinLUT[pixel2];
(((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
} }
@ -399,6 +384,7 @@ void Inkplate::partialUpdate()
return; return;
if (_blockPartial == 1) if (_blockPartial == 1)
display1b(); display1b();
uint16_t _pos = 59999; uint16_t _pos = 59999;
uint32_t _send; uint32_t _send;
uint8_t data; uint8_t data;
@ -410,8 +396,8 @@ void Inkplate::partialUpdate()
{ {
for (int j = 0; j < 100; ++j) for (int j = 0; j < 100; ++j)
{ {
diffw = ((*(D_memory_new + _pos)) ^ (*(_partial + _pos))) & (~(*(_partial + _pos))); diffw = *(DMemoryNew + _pos) & ~*(_partial + _pos);
diffb = ((*(D_memory_new + _pos)) ^ (*(_partial + _pos))) & ((*(_partial + _pos))); diffb = ~*(DMemoryNew + _pos) & *(_partial + _pos);
_pos--; _pos--;
*(_pBuffer + n) = LUTW[diffw >> 4] & (LUTB[diffb >> 4]); *(_pBuffer + n) = LUTW[diffw >> 4] & (LUTB[diffb >> 4]);
n--; n--;
@ -428,20 +414,18 @@ void Inkplate::partialUpdate()
for (int i = 0; i < 600; ++i) for (int i = 0; i < 600; ++i)
{ {
data = *(_pBuffer + n); data = *(_pBuffer + n);
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | _send = pinLUT[data];
(((data & B11100000) >> 5) << 25);
hscan_start(_send); hscan_start(_send);
n--; n--;
for (int j = 0; j < 199; j++) for (int j = 0; j < 199; ++j)
{ {
data = *(_pBuffer + n); data = *(_pBuffer + n);
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | _send = pinLUT[data];
(((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); GPIO.out_w1ts = _send | CL;
GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
n--; n--;
} }
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = _send | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;
vscan_end(); vscan_end();
} }
@ -451,12 +435,8 @@ void Inkplate::partialUpdate()
cleanFast(3, 1); cleanFast(3, 1);
vscan_start(); vscan_start();
einkOff(); einkOff();
einkOff();
for (int i = 0; i < 60000; ++i) memcpy(DMemoryNew, _partial, 60000);
{
*(D_memory_new + i) &= *(_partial + i);
*(D_memory_new + i) |= (*(_partial + i));
}
} }
void Inkplate::clean() void Inkplate::clean()
@ -489,18 +469,16 @@ void Inkplate::cleanFast(uint8_t c, uint8_t rep)
else if (c == 3) else if (c == 3)
data = B11111111; data = B11111111;
uint32_t _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | uint32_t _send = pinLUT[data];
(((data & B11100000) >> 5) << 25); for (int k = 0; k < rep; ++k)
;
for (int k = 0; k < rep; k++)
{ {
vscan_start(); vscan_start();
for (int i = 0; i < 600; i++) for (int i = 0; i < 600; ++i)
{ {
hscan_start(_send); hscan_start(_send);
GPIO.out_w1ts = (_send) | CL; GPIO.out_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | 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_w1ts = (_send) | CL;
GPIO.out_w1tc = DATA | CL; GPIO.out_w1tc = DATA | CL;

View File

@ -38,10 +38,6 @@ class Inkplate : public System, public GFX
{ {
return Network::isConnected(); return Network::isConnected();
}; };
uint8_t *downloadFile(const char *url, int32_t defaultLen)
{
return Network::downloadFile(url, defaultLen);
};
private: private:
void precalculateGamma(uint8_t *c, float gamma); void precalculateGamma(uint8_t *c, float gamma);
@ -56,6 +52,7 @@ class Inkplate : public System, public GFX
void pinsZstate(); void pinsZstate();
void pinsAsOutputs(); void pinsAsOutputs();
uint32_t pinLUT[256];
uint8_t _beginDone = 0; uint8_t _beginDone = 0;

View File

@ -172,7 +172,7 @@ void GFX::selectDisplayMode(uint8_t _mode)
if (_mode != _displayMode) if (_mode != _displayMode)
{ {
_displayMode = _mode & 1; _displayMode = _mode & 1;
memset(D_memory_new, 0, 60000); memset(DMemoryNew, 0, 60000);
memset(_partial, 0, 60000); memset(_partial, 0, 60000);
memset(_pBuffer, 0, 120000); memset(_pBuffer, 0, 120000);
memset(D_memory4Bit, 255, 240000); memset(D_memory4Bit, 255, 240000);

View File

@ -34,7 +34,7 @@ class GFX : public Shapes, public Image, public Font
void setRotation(uint8_t r); void setRotation(uint8_t r);
uint8_t getRotation(); 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); void selectDisplayMode(uint8_t _mode);
@ -43,7 +43,7 @@ class GFX : public Shapes, public Image, public Font
int16_t width() override; int16_t width() override;
int16_t height() override; int16_t height() override;
uint8_t *D_memory_new; uint8_t *DMemoryNew;
uint8_t *_partial; uint8_t *_partial;
uint8_t *D_memory4Bit; uint8_t *D_memory4Bit;
uint8_t *_pBuffer; uint8_t *_pBuffer;
@ -65,7 +65,7 @@ class GFX : public Shapes, public Image, public Font
private: private:
void startWrite(void) override; 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 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 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; void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;

View File

@ -31,7 +31,7 @@ bool Image::drawImage(const char *path, int x, int y, bool dither, bool invert)
if (strstr(path, ".bmp") != NULL) if (strstr(path, ".bmp") != NULL)
return drawBitmapFromSd(path, x, y, dither, invert); return drawBitmapFromSd(path, x, y, dither, invert);
if (strstr(path, ".jpg") != NULL || strstr(path, ".jpeg") != NULL) if (strstr(path, ".jpg") != NULL || strstr(path, ".jpeg") != NULL)
return drawJpegFromSD(path, x, y, dither, invert); return drawJpegFromSd(path, x, y, dither, invert);
} }
}; };

View File

@ -28,17 +28,21 @@ class Image : virtual public Network
uint16_t bg = 0xFFFF); uint16_t bg = 0xFFFF);
void drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h); 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(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(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 drawJpegFromBuffer(uint8_t *buf, int32_t len, int x, int y, bool dither, bool invert);
bool drawJpegFromSD(SdFile *p, int x, int y, 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 drawJpegFromWeb(const char *url, 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: 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 writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) = 0;
virtual void endWrite(void) = 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, static bool drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool dither, bool invert);
bool _invert);
uint8_t pixelBuffer[800 * 4 + 5]; uint8_t pixelBuffer[800 * 4 + 5];
uint8_t ditherBuffer[2][800 + 5]; uint8_t ditherBuffer[2][800 + 5];
@ -60,9 +63,8 @@ class Image : virtual public Network
bool legalBmp(bitmapHeader *bmpHeader); bool legalBmp(bitmapHeader *bmpHeader);
void ditherStart(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits); uint8_t ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted);
void ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits); uint8_t ditherGetPixelJpeg(uint8_t px, int x, int y, int w);
uint8_t ditherGetPixel(uint8_t px, int i, int w, bool paletted);
void ditherSwap(int w); void ditherSwap(int w);
void readBmpHeader(uint8_t *buf, bitmapHeader *_h); void readBmpHeader(uint8_t *buf, bitmapHeader *_h);

View File

@ -92,14 +92,6 @@ bool Image::drawBitmapFromSd(SdFile *p, int x, int y, bool dither, bool invert)
if (!legalBmp(&bmpHeader)) if (!legalBmp(&bmpHeader))
return 0; 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; int16_t w = bmpHeader.width, h = bmpHeader.height;
int8_t c = bmpHeader.color; 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) 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; bitmapHeader bmpHeader;
readBmpHeader(buf, &bmpHeader); readBmpHeader(buf, &bmpHeader);
if (!legalBmp(&bmpHeader)) if (!legalBmp(&bmpHeader))
return 0; 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) if (dither)
memset(ditherBuffer, 0, sizeof ditherBuffer); memset(ditherBuffer, 0, sizeof ditherBuffer);
uint8_t *bufferPtr = buf + bmpHeader.startRAW; uint8_t *bufferPtr = buf + bmpHeader.startRAW;
for (int i = 0; i < bmpHeader.height; ++i) 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); free(buf);
return 1; return 1;
} }
@ -167,14 +172,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d
uint8_t val; uint8_t val;
if (dither) if (dither)
val = ditherGetPixel(px, j, w, 1); val = ditherGetPixelBmp(px, j, w, 1);
else else
val = palette[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4); val = palette[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4);
if (invert) if (invert)
writePixel(x + j, y, 7 - val); val = 7 - val;
else if (getDisplayMode() == INKPLATE_1BIT)
writePixel(x + j, y, val); val = (~val >> 2) & 1;
writePixel(x + j, y, val);
break; break;
} }
case 8: { case 8: {
@ -182,16 +188,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d
uint8_t val; uint8_t val;
if (dither) if (dither)
val = ditherGetPixel(px, j, w, 1); val = ditherGetPixelBmp(px, j, w, 1);
else else
{
val = palette[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4); val = palette[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4);
}
if (invert) if (invert)
writePixel(x + j, y, 7 - val); val = 7 - val;
else if (getDisplayMode() == INKPLATE_1BIT)
writePixel(x + j, y, val); val = (~val >> 2) & 1;
writePixel(x + j, y, val);
break; break;
} }
case 16: { case 16: {
@ -204,14 +209,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d
uint8_t val; uint8_t val;
if (dither) if (dither)
val = ditherGetPixel(RGB8BIT(r, g, b), j, w, 0); val = ditherGetPixelBmp(RGB8BIT(r, g, b), j, w, 0);
else else
val = RGB3BIT(r, g, b); val = RGB3BIT(r, g, b);
if (invert) if (invert)
writePixel(x + j, y, 7 - val); val = 7 - val;
else if (getDisplayMode() == INKPLATE_1BIT)
writePixel(x + j, y, val); val = (~val >> 2) & 1;
writePixel(x + j, y, val);
break; break;
} }
case 24: { case 24: {
@ -222,14 +228,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d
uint8_t val; uint8_t val;
if (dither) if (dither)
val = ditherGetPixel(RGB8BIT(r, g, b), j, w, 0); val = ditherGetPixelBmp(RGB8BIT(r, g, b), j, w, 0);
else else
val = RGB3BIT(r, g, b); val = RGB3BIT(r, g, b);
if (invert) if (invert)
writePixel(x + j, y, 7 - val); val = 7 - val;
else if (getDisplayMode() == INKPLATE_1BIT)
writePixel(x + j, y, val); val = (~val >> 2) & 1;
writePixel(x + j, y, val);
break; break;
} }
case 32: case 32:
@ -240,14 +247,15 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d
uint8_t val; uint8_t val;
if (dither) if (dither)
val = ditherGetPixel(RGB8BIT(r, g, b), j, w, 0); val = ditherGetPixelBmp(RGB8BIT(r, g, b), j, w, 0);
else else
val = RGB3BIT(r, g, b); val = RGB3BIT(r, g, b);
if (invert) if (invert)
writePixel(x + j, y, 7 - RGB3BIT(r, g, b)); val = 7 - val;
else if (getDisplayMode() == INKPLATE_1BIT)
writePixel(x + j, y, RGB3BIT(r, g, b)); val = (~val >> 2) & 1;
writePixel(x + j, y, val);
break; break;
} }
} }

View File

@ -1,13 +1,13 @@
#include "Image.h" #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) if (paletted)
px = ditherPalette[px]; px = ditherPalette[px];
uint8_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)ditherBuffer[0][i] + 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; uint8_t quantError = oldPixel - newPixel;
ditherBuffer[1][i + 0] += (quantError * 5) >> 4; 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; 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) void Image::ditherSwap(int w)
{ {
for (int i = 0; i < w; ++i) for (int i = 0; i < w; ++i)

View File

@ -8,7 +8,81 @@
extern Image *_imagePtrJpeg; 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) if (!_imagePtrJpeg)
return 0; 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) for (int i = 0; i < w; ++i)
{ {
uint16_t rgb = bitmap[j * w + i]; uint16_t rgb = bitmap[j * w + i];
if (_invert) uint8_t val = RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb));
_imagePtrJpeg->drawPixel(i + x, j + y, 7 - RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb)));
else if (invert)
_imagePtrJpeg->drawPixel(i + x, j + y, RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb))); val = 7 - val;
_imagePtrJpeg->writePixel(x + i, y + j, val);
} }
} }
_imagePtrJpeg->endWrite(); _imagePtrJpeg->endWrite();
return 1; 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;
} }

View File

@ -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()) if (!isConnected())
return NULL; return NULL;
@ -45,7 +45,9 @@ uint8_t *Network::downloadFile(const char *url, int32_t defaultLen)
int32_t size = http.getSize(); int32_t size = http.getSize();
if (size == -1) if (size == -1)
size = defaultLen; size = *defaultLen;
else
*defaultLen = size;
uint8_t *buffer = (uint8_t *)ps_malloc(size); uint8_t *buffer = (uint8_t *)ps_malloc(size);
uint8_t *buffPtr = buffer; uint8_t *buffPtr = buffer;
@ -79,3 +81,36 @@ uint8_t *Network::downloadFile(const char *url, int32_t defaultLen)
return buffer; 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;
}

View File

@ -25,7 +25,8 @@ class Network
void disconnect(); void disconnect();
bool isConnected(); 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: private:
}; };

View File

@ -14,11 +14,12 @@ void setup()
void loop() void loop()
{ {
int32_t t = millis();
display.drawBitmap(offSet, 0, (uint8_t *)bck_day, bck_day_w, bck_day_h, BLACK); display.drawBitmap(offSet, 0, (uint8_t *)bck_day, bck_day_w, bck_day_h, BLACK);
int32_t t = millis();
display.partialUpdate(); display.partialUpdate();
display.clearDisplay();
Serial.println(millis() - t); Serial.println(millis() - t);
display.clearDisplay();
offSet += 70; offSet += 70;
offSet %= 300; offSet %= 300;
} }

View File

@ -1,6 +1,6 @@
#include "Inkplate.h" #include "Inkplate.h"
#include "SdFat.h" #include "SdFat.h"
Inkplate display(INKPLATE_3BIT); Inkplate display(INKPLATE_1BIT);
void setup() void setup()
{ {
@ -30,9 +30,7 @@ void loop()
if (display.sdCardInit()) if (display.sdCardInit())
{ {
int16_t t = millis();
Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 1, 0)); Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 1, 0));
Serial.println(millis() - t);
} }
display.display(); display.display();