Added bmp dither.

This commit is contained in:
nitko12 2020-09-09 14:18:37 +02:00
parent e5ca63391a
commit 82a082003a
10 changed files with 656 additions and 640 deletions

View File

@ -2,11 +2,11 @@
1_Inkplate_WiFi_HTTP example for e-radionica.com Inkplate 6
For this example you will need USB cable, Inkplate 6 and stable WiFi Internet connection
Select "Inkplate 6(ESP32)" from Tools -> Board menu.
Don't have "Inkplate 6(ESP32)" option? Follow our tutorial and add it:
Don't have "Inkplate 6(ESP32)" option? Follow our tutorial and add it:
https://e-radionica.com/en/blog/add-inkplate-6-to-arduino-ide/
This example will show you how to connect to WiFi network, get data from Internet and display that data on epaper.
This example is NOT on to how to parse HTML data from Internet - it will just print HTML on the screen.
This example is NOT on to how to parse HTML data from Internet - it will just print HTML on the screen.
In quotation marks you will need write your WiFi SSID and WiFi password in order to connect to your WiFi network.
@ -15,68 +15,82 @@
15 July 2020 by e-radionica.com
*/
#include "Inkplate.h" //Include Inkplate library to the sketch
#include <WiFi.h> //Include ESP32 WiFi library to our sketch
#include <HTTPClient.h> //Include HTTP library to this sketch
#include "Inkplate.h" //Include Inkplate library to the sketch
#include <HTTPClient.h> //Include HTTP library to this sketch
#include <WiFi.h> //Include ESP32 WiFi library to our sketch
#define ssid "" //Name of the WiFi network (SSID) that you want to connect Inkplate to
#define pass "" //Password of that WiFi network
#define ssid "" // Name of the WiFi network (SSID) that you want to connect Inkplate to
#define pass "" // Password of that WiFi network
Inkplate display(INKPLATE_1BIT); //Create an object on Inkplate library and also set library into 1 Bit mode (Monochrome)
Inkplate display(
INKPLATE_1BIT); // Create an object on Inkplate library and also set library into 1 Bit mode (Monochrome)
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
display.setTextSize(2); //Set text scaling to two (text will be two times bigger)
display.setCursor(0, 0); //Set print position
display.setTextColor(BLACK, WHITE); //Set text color to black and background color to white
display.println("Scanning for WiFi networks..."); //Write text
display.display(); //Send everything to display (refresh 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
display.setTextSize(2); // Set text scaling to two (text will be two times bigger)
display.setCursor(0, 0); // Set print position
display.setTextColor(BLACK, WHITE); // Set text color to black and background color to white
display.println("Scanning for WiFi networks..."); // Write text
display.display(); // Send everything to display (refresh display)
int n = WiFi.scanNetworks(); //Start searching WiFi networks and put the nubmer of found WiFi networks in variable n
if (n == 0) { //If you did not find any network, show the message and stop the program.
display.print("No WiFi networks found!");
display.partialUpdate();
while (true);
} else {
if (n > 10) n = 0; //If you did find, print name (SSID), encryption and signal strength of first 10 networks
for (int i = 0; i < n; i++) {
display.print(WiFi.SSID(i));
display.print((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? 'O' : '*');
display.print('\n');
display.print(WiFi.RSSI(i), DEC);
int n = WiFi.scanNetworks(); // Start searching WiFi networks and put the nubmer of found WiFi networks in variable
// n
if (n == 0)
{ // If you did not find any network, show the message and stop the program.
display.print("No WiFi networks found!");
display.partialUpdate();
while (true)
;
}
display.partialUpdate(); //(Partial) refresh thescreen
}
display.clearDisplay(); //Clear everything in frame buffer
display.setCursor(0,0); //Set print cursor to new position
display.print("Connecting to "); //Print the name of WiFi network
display.print(ssid);
WiFi.begin(ssid, pass); //Try to connect to WiFi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000); //While it is connecting to network, display dot every second, just to know that Inkplate is alive.
display.print('.');
display.partialUpdate();
}
display.print("connected"); //If it's connected, notify user
display.partialUpdate();
HTTPClient http;
if(http.begin("http://example.com/index.html")) { //Now try to connect to some web page (in this example www.example.com. And yes, this is a valid Web page :))
if(http.GET()>0) { //If connection was successful, try to read content of the Web page and display it on screen
String htmlText;
htmlText = http.getString();
display.setTextSize(1); //Set smaller text size, so everything can fit on screen
display.clearDisplay();
display.setCursor(0, 0);
display.print(htmlText);
display.display();
else
{
if (n > 10)
n = 0; // If you did find, print name (SSID), encryption and signal strength of first 10 networks
for (int i = 0; i < n; i++)
{
display.print(WiFi.SSID(i));
display.print((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? 'O' : '*');
display.print('\n');
display.print(WiFi.RSSI(i), DEC);
}
display.partialUpdate(); //(Partial) refresh thescreen
}
display.clearDisplay(); // Clear everything in frame buffer
display.setCursor(0, 0); // Set print cursor to new position
display.print("Connecting to "); // Print the name of WiFi network
display.print(ssid);
WiFi.begin(ssid, pass); // Try to connect to WiFi network
while (WiFi.status() != WL_CONNECTED)
{
delay(1000); // While it is connecting to network, display dot every second, just to know that Inkplate is
// alive.
display.print('.');
display.partialUpdate();
}
display.print("connected"); // If it's connected, notify user
display.partialUpdate();
HTTPClient http;
if (http.begin("http://example.com/index.html"))
{ // Now try to connect to some web page (in this example www.example.com. And yes, this is a valid Web page :))
if (http.GET() > 0)
{ // If connection was successful, try to read content of the Web page and display it on screen
String htmlText;
htmlText = http.getString();
display.setTextSize(1); // Set smaller text size, so everything can fit on screen
display.clearDisplay();
display.setCursor(0, 0);
display.print(htmlText);
display.display();
}
}
}
}
void loop() {
//Nothing
void loop()
{
// Nothing
}

View File

@ -21,52 +21,60 @@
15 July 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() {
void setup()
{
Serial.begin(115200);
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
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=0, Y=0
//NOTE: Both drawBitmapFromSD methods allow for an optional fourth "invert" parameter. Setting this parameter to true
//will flip all colors on the image, making black white and white black. This may be necessary when exporting bitmaps from
//certain softwares.
if (!display.drawBitmapFromSD("image1.bmp", 0, 0, 1)) {
//If is something failed (wrong filename or wrong bitmap format), write error message on the screen.
//REMEMBER! You can only use Windows Bitmap file with color depth of 1, 4, 8 or 24 bits with no compression!
//You can turn of dithering for somewhat faster image load by changing the last 1 to 0, or removing the 1 argument completely
// If card is properly init, try to load image and display it on e-paper at position X=0, Y=0
// NOTE: Both drawBitmapFromSd methods allow for an optional fourth "invert" parameter. Setting this parameter
// to true will flip all colors on the image, making black white and white black. This may be necessary when
// exporting bitmaps from certain softwares.
if (!display.drawBitmapFromSd("image1.bmp", 0, 0, 1))
{
// If is something failed (wrong filename or wrong bitmap format), write error message on the screen.
// REMEMBER! You can only use Windows Bitmap file with color depth of 1, 4, 8 or 24 bits with no
// compression! You can turn of dithering for somewhat faster image load by changing the last 1 to 0, or
// removing the 1 argument 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)
;
}
delay(5000);
//Now try to load image using SdFat library class (for more advanced users) and display image on epaper.
if (file.open("image2.bmp", O_RDONLY)) {
display.drawBitmapFromSD(&file, 0, 0);
// Now try to load image using SdFat library class (for more advanced users) and display image on epaper.
if (file.open("image2.bmp", O_RDONLY))
{
display.drawBitmapFromSd(&file, 0, 0);
display.display();
}
}
void loop() {
//Nothing...
void loop()
{
// Nothing...
}

View File

@ -1,24 +1,25 @@
/*
Inkplate_Slave_Mode sketch for e-radionica.com Inkplate 6
Select "Inkplate 6(ESP32)" from Tools -> Board menu.
Don't have "Inkplate 6(ESP32)" option? Follow our tutorial and add it:
Don't have "Inkplate 6(ESP32)" option? Follow our tutorial and add it:
https://e-radionica.com/en/blog/add-inkplate-6-to-arduino-ide/
Using this sketch, you don't have to program and control e-paper using Arduino code.
Using this sketch, you don't have to program and control e-paper using Arduino code.
Instead, you can send UART command (explained in documentation that can be found inside folder of this sketch).
This give you flexibility that you can use this Inkplate 6 on any platform!
Because it uses UART, it's little bit slower and it's not recommended to send bunch of
Because it uses UART, it's little bit slower and it's not recommended to send bunch of
drawPixel command to draw some image. Instead, load bitmaps and pictures on SD card and load image from SD.
If we missed some function, you can modify this and make yor own.
Also, every Inkplate comes with this slave mode right from the factory.
Learn more about Slave Mode in this update: https://www.crowdsupply.com/e-radionica/inkplate-6/updates/successfully-funded-also-third-party-master-controllers-and-partial-updates
Learn more about Slave Mode in this update:
https://www.crowdsupply.com/e-radionica/inkplate-6/updates/successfully-funded-also-third-party-master-controllers-and-partial-updates
UART settings are: 115200 baud, standard parity, ending with "\n\r" (both)
You can send commands via USB port or by directly connecting to ESP32 TX and RX pins.
Don't forget you need to send #L(1)* after each command to show it on the display
(equal to display.display()).
Don't forget you need to send #L(1)* after each command to show it on the display
(equal to display.display()).
Want to learn more about Inkplate? Visit www.inkplate.io
Looking to get support? Write on our forums: http://forum.e-radionica.com/en/
@ -31,308 +32,342 @@ Inkplate display(INKPLATE_1BIT);
#define BUFFER_SIZE 1000
char commandBuffer[BUFFER_SIZE + 1];
char strTemp[2001];
void setup() {
display.begin();
Serial.begin(115200);
memset(commandBuffer, 0, BUFFER_SIZE);
void setup()
{
display.begin();
Serial.begin(115200);
memset(commandBuffer, 0, BUFFER_SIZE);
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available()) {
while (Serial.available()) {
for (int i = 0; i < (BUFFER_SIZE - 1); i++) {
commandBuffer[i] = commandBuffer[i + 1];
}
commandBuffer[BUFFER_SIZE - 1] = Serial.read();
}
}
char *s = NULL;
char *e = NULL;
for (int i = 0; i < BUFFER_SIZE; i++) {
if (commandBuffer[i] == '#' && s == NULL) s = &commandBuffer[i];
if (commandBuffer[i] == '*' && e == NULL) e = &commandBuffer[i];
}
if (s != NULL && e != NULL) {
if ((e - s) > 0) {
int x, x1, x2, y, y1, y2, x3, y3, l, c, w, h, r, n;
char b;
char temp[150];
switch (*(s + 1)) {
case '?':
Serial.print("OK");
break;
case '0':
sscanf(s + 3, "%d,%d,%d", &x, &y, &c);
//sprintf(temp, "display.drawPixel(%d, %d, %d)\n\r", x, y, c);
//Serial.print(temp);
display.drawPixel(x, y, c);
break;
case '1':
sscanf(s + 3, "%d,%d,%d,%d,%d", &x1, &y1, &x2, &y2, &c);
//sprintf(temp, "display.drawLine(%d, %d, %d, %d, %d)\n\r", x1, y1, x2, y2, c);
//Serial.print(temp);
display.drawLine(x1, y1, x2, y2, c);
break;
case '2':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &l, &c);
//sprintf(temp, "display.drawFastVLine(%d, %d, %d, %d)\n\r", x, y, l, c);
//Serial.print(temp);
display.drawFastVLine(x, y, l, c);
break;
case '3':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &l, &c);
//sprintf(temp, "display.drawFastHLine(%d, %d, %d, %d)\n\r", x, y, l, c);
//Serial.print(temp);
display.drawFastHLine(x, y, l, c);
break;
case '4':
sscanf(s + 3, "%d,%d,%d,%d,%d", &x, &y, &w, &h, &c);
//sprintf(temp, "display.drawRect(%d, %d, %d, %d, %d)\n\r", x, y, w, h, c);
//Serial.print(temp);
display.drawRect(x, y, w, h, c);
break;
case '5':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &r, &c);
//sprintf(temp, "display.drawCircle(%d, %d, %d, %d)\n\r", x, y, r, c);
//Serial.print(temp);
display.drawCircle(x, y, r, c);
break;
case '6':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d,%d", &x1, &y1, &x2, &y2, &x3, &y3, &c);
//sprintf(temp, "display.drawTriangle(%d, %d, %d, %d, %d, %d, %d)\n\r", x1, y1, x2, y2, x3, y3, c);
//Serial.print(temp);
display.drawTriangle(x1, y1, x2, y2, x3, y3, c);
break;
case '7':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d", &x, &y, &w, &h, &r, &c);
//sprintf(temp, "display.drawRoundRect(%d, %d, %d, %d, %d, %d)\n\r", x, y, w, h, r, c);
//Serial.print(temp);
display.drawRoundRect(x, y, w, h, r, c);
break;
case '8':
sscanf(s + 3, "%d,%d,%d,%d,%d", &x, &y, &w, &h, &c);
//sprintf(temp, "display.fillRect(%d, %d, %d, %d, %d)\n\r", x, y, w, h, c);
//Serial.print(temp);
display.fillRect(x, y, w, h, c);
break;
case '9':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &r, &c);
//sprintf(temp, "display.fillCircle(%d, %d, %d, %d)\n\r", x, y, r, c);
//Serial.print(temp);
display.fillCircle(x, y, r, c);
break;
case 'A':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d,%d", &x1, &y1, &x2, &y2, &x3, &y3, &c);
//sprintf(temp, "display.fillTriangle(%d, %d, %d, %d, %d, %d, %d)\n\r", x1, y1, x2, y2, x3, y3, c);
//Serial.print(temp);
display.fillTriangle(x1, y1, x2, y2, x3, y3, c);
break;
case 'B':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d", &x, &y, &w, &h, &r, &c);
//sprintf(temp, "display.fillRoundRect(%d, %d, %d, %d, %d, %d)\n\r", x, y, w, h, r, c);
//Serial.print(temp);
display.fillRoundRect(x, y, w, h, r, c);
break;
case 'C':
sscanf(s + 3, "\"%2000[^\"]\"", strTemp);
n = strlen(strTemp);
for (int i = 0; i < n; i++) {
strTemp[i] = toupper(strTemp[i]);
}
for (int i = 0; i < n; i += 2) {
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
}
strTemp[n / 2] = 0;
//Serial.print("display.print(\"");
//Serial.print(strTemp);
//Serial.println("\");");
display.print(strTemp);
break;
case 'D':
sscanf(s + 3, "%d", &c);
//sprintf(temp, "display.setTextSize(%d)\n", c);
//Serial.print(temp);
display.setTextSize(c);
break;
case 'E':
sscanf(s + 3, "%d,%d", &x, &y);
//sprintf(temp, "display.setCursor(%d, %d)\n", x, y);
//Serial.print(temp);
display.setCursor(x, y);
break;
case 'F':
sscanf(s + 3, "%c", &b);
//sprintf(temp, "display.setTextWrap(%s)\n", b == 'T' ? "True" : "False");
//Serial.print(temp);
if (b == 'T') display.setTextWrap(true);
if (b == 'F') display.setTextWrap(false);
break;
case 'G':
sscanf(s + 3, "%d", &c);
c &= 3;
//sprintf(temp, "display.setRotation(%d)\n", c);
//Serial.print(temp);
display.setRotation(c);
break;
case 'H':
sscanf(s + 3, "%d,%d,\"%149[^\"]\"", &x, &y, strTemp);
n = strlen(strTemp);
for (int i = 0; i < n; i++) {
strTemp[i] = toupper(strTemp[i]);
}
for (int i = 0; i < n; i += 2) {
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
}
strTemp[n / 2] = 0;
r = display.sdCardInit();
if (r) {
r = display.drawBitmapFromSD(strTemp, x, y);
Serial.print("#H(");
Serial.print(r, DEC);
Serial.println(")*");
Serial.flush();
//sprintf(temp, "display.drawBitmap(%d, %d, %s)\n", x, y, strTemp);
//Serial.print(temp);
} else {
Serial.println("#H(-1)*");
Serial.flush();
}
break;
case 'I':
sscanf(s + 3, "%d", &c);
//sprintf(temp, "display.setDisplayMode(%s)\n", c == 0 ? "INKPLATE_1BIT" : "INKPLATE_3BIT");
//Serial.print(temp);
if (c == INKPLATE_1BIT) display.selectDisplayMode(INKPLATE_1BIT);
if (c == INKPLATE_3BIT) display.selectDisplayMode(INKPLATE_3BIT);
break;
case 'J':
sscanf(s + 3, "%c", &b);
if (b == '?') {
//if (0 == 0) {
// Serial.println("#J(0)*");
//} else {
// Serial.println("#J(1)*");
//}
if (display.getDisplayMode() == INKPLATE_1BIT) {
Serial.println("#J(0)*");
Serial.flush();
void loop()
{
// put your main code here, to run repeatedly:
if (Serial.available())
{
while (Serial.available())
{
for (int i = 0; i < (BUFFER_SIZE - 1); i++)
{
commandBuffer[i] = commandBuffer[i + 1];
}
if (display.getDisplayMode() == INKPLATE_3BIT) {
Serial.println("#J(1)*");
Serial.flush();
}
}
break;
case 'K':
sscanf(s + 3, "%c", &b);
if (b == '1') {
//Serial.print("display.clearDisplay();\n");
display.clearDisplay();
}
break;
case 'L':
sscanf(s + 3, "%c", &b);
if (b == '1') {
//Serial.print("display.display();\n");
display.display();
}
break;
case 'M':
sscanf(s + 3, "%d,%d,%d", &y1, &x2, &y2);
//sprintf(temp, "display.partialUpdate(%d, %d, %d);\n", y1, x2, y2);
//Serial.print(temp);
display.partialUpdate();
break;
case 'N':
sscanf(s + 3, "%c", &b);
if (b == '?') {
Serial.print("#N(");
Serial.print(display.readTemperature(), DEC);
//Serial.print(23, DEC);
Serial.println(")*");
Serial.flush();
}
break;
case 'O':
sscanf(s + 3, "%d", &c);
if (c >= 0 && c <= 2) {
Serial.print("#O(");
Serial.print(display.readTouchpad(c), DEC);
//Serial.print(0, DEC);
Serial.println(")*");
Serial.flush();
}
break;
case 'P':
sscanf(s + 3, "%c", &b);
if (b == '?') {
Serial.print("#P(");
Serial.print(display.readBattery(), 2);
//Serial.print(3.54, 2);
Serial.println(")*");
Serial.flush();
}
break;
case 'Q':
sscanf(s + 3, "%d", &c);
c &= 1;
//if (c == 0) Serial.print("display.einkOff();\n");
//if (c == 1) Serial.print("display.einkOn();\n");
if (c == 0) display.einkOff();
if (c == 1) display.einkOn();
break;
case 'R':
sscanf(s + 3, "%c", &b);
if (b == '?') {
Serial.print("#R(");
Serial.print(display.getPanelState(), DEC);
//Serial.print(1, DEC);
Serial.println(")*");
Serial.flush();
}
break;
}
*s = 0;
*e = 0;
commandBuffer[BUFFER_SIZE - 1] = Serial.read();
}
}
char *s = NULL;
char *e = NULL;
for (int i = 0; i < BUFFER_SIZE; i++)
{
if (commandBuffer[i] == '#' && s == NULL)
s = &commandBuffer[i];
if (commandBuffer[i] == '*' && e == NULL)
e = &commandBuffer[i];
}
if (s != NULL && e != NULL)
{
if ((e - s) > 0)
{
int x, x1, x2, y, y1, y2, x3, y3, l, c, w, h, r, n;
char b;
char temp[150];
switch (*(s + 1))
{
case '?':
Serial.print("OK");
break;
case '0':
sscanf(s + 3, "%d,%d,%d", &x, &y, &c);
// sprintf(temp, "display.drawPixel(%d, %d, %d)\n\r", x, y, c);
// Serial.print(temp);
display.drawPixel(x, y, c);
break;
case '1':
sscanf(s + 3, "%d,%d,%d,%d,%d", &x1, &y1, &x2, &y2, &c);
// sprintf(temp, "display.drawLine(%d, %d, %d, %d, %d)\n\r", x1, y1, x2, y2, c);
// Serial.print(temp);
display.drawLine(x1, y1, x2, y2, c);
break;
case '2':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &l, &c);
// sprintf(temp, "display.drawFastVLine(%d, %d, %d, %d)\n\r", x, y, l, c);
// Serial.print(temp);
display.drawFastVLine(x, y, l, c);
break;
case '3':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &l, &c);
// sprintf(temp, "display.drawFastHLine(%d, %d, %d, %d)\n\r", x, y, l, c);
// Serial.print(temp);
display.drawFastHLine(x, y, l, c);
break;
case '4':
sscanf(s + 3, "%d,%d,%d,%d,%d", &x, &y, &w, &h, &c);
// sprintf(temp, "display.drawRect(%d, %d, %d, %d, %d)\n\r", x, y, w, h, c);
// Serial.print(temp);
display.drawRect(x, y, w, h, c);
break;
case '5':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &r, &c);
// sprintf(temp, "display.drawCircle(%d, %d, %d, %d)\n\r", x, y, r, c);
// Serial.print(temp);
display.drawCircle(x, y, r, c);
break;
case '6':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d,%d", &x1, &y1, &x2, &y2, &x3, &y3, &c);
// sprintf(temp, "display.drawTriangle(%d, %d, %d, %d, %d, %d, %d)\n\r", x1, y1, x2, y2, x3, y3, c);
// Serial.print(temp);
display.drawTriangle(x1, y1, x2, y2, x3, y3, c);
break;
case '7':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d", &x, &y, &w, &h, &r, &c);
// sprintf(temp, "display.drawRoundRect(%d, %d, %d, %d, %d, %d)\n\r", x, y, w, h, r, c);
// Serial.print(temp);
display.drawRoundRect(x, y, w, h, r, c);
break;
case '8':
sscanf(s + 3, "%d,%d,%d,%d,%d", &x, &y, &w, &h, &c);
// sprintf(temp, "display.fillRect(%d, %d, %d, %d, %d)\n\r", x, y, w, h, c);
// Serial.print(temp);
display.fillRect(x, y, w, h, c);
break;
case '9':
sscanf(s + 3, "%d,%d,%d,%d", &x, &y, &r, &c);
// sprintf(temp, "display.fillCircle(%d, %d, %d, %d)\n\r", x, y, r, c);
// Serial.print(temp);
display.fillCircle(x, y, r, c);
break;
case 'A':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d,%d", &x1, &y1, &x2, &y2, &x3, &y3, &c);
// sprintf(temp, "display.fillTriangle(%d, %d, %d, %d, %d, %d, %d)\n\r", x1, y1, x2, y2, x3, y3, c);
// Serial.print(temp);
display.fillTriangle(x1, y1, x2, y2, x3, y3, c);
break;
case 'B':
sscanf(s + 3, "%d,%d,%d,%d,%d,%d", &x, &y, &w, &h, &r, &c);
// sprintf(temp, "display.fillRoundRect(%d, %d, %d, %d, %d, %d)\n\r", x, y, w, h, r, c);
// Serial.print(temp);
display.fillRoundRect(x, y, w, h, r, c);
break;
case 'C':
sscanf(s + 3, "\"%2000[^\"]\"", strTemp);
n = strlen(strTemp);
for (int i = 0; i < n; i++)
{
strTemp[i] = toupper(strTemp[i]);
}
for (int i = 0; i < n; i += 2)
{
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
}
strTemp[n / 2] = 0;
// Serial.print("display.print(\"");
// Serial.print(strTemp);
// Serial.println("\");");
display.print(strTemp);
break;
case 'D':
sscanf(s + 3, "%d", &c);
// sprintf(temp, "display.setTextSize(%d)\n", c);
// Serial.print(temp);
display.setTextSize(c);
break;
case 'E':
sscanf(s + 3, "%d,%d", &x, &y);
// sprintf(temp, "display.setCursor(%d, %d)\n", x, y);
// Serial.print(temp);
display.setCursor(x, y);
break;
case 'F':
sscanf(s + 3, "%c", &b);
// sprintf(temp, "display.setTextWrap(%s)\n", b == 'T' ? "True" : "False");
// Serial.print(temp);
if (b == 'T')
display.setTextWrap(true);
if (b == 'F')
display.setTextWrap(false);
break;
case 'G':
sscanf(s + 3, "%d", &c);
c &= 3;
// sprintf(temp, "display.setRotation(%d)\n", c);
// Serial.print(temp);
display.setRotation(c);
break;
case 'H':
sscanf(s + 3, "%d,%d,\"%149[^\"]\"", &x, &y, strTemp);
n = strlen(strTemp);
for (int i = 0; i < n; i++)
{
strTemp[i] = toupper(strTemp[i]);
}
for (int i = 0; i < n; i += 2)
{
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
}
strTemp[n / 2] = 0;
r = display.sdCardInit();
if (r)
{
r = display.drawBitmapFromSd(strTemp, x, y);
Serial.print("#H(");
Serial.print(r, DEC);
Serial.println(")*");
Serial.flush();
// sprintf(temp, "display.drawBitmap(%d, %d, %s)\n", x, y, strTemp);
// Serial.print(temp);
}
else
{
Serial.println("#H(-1)*");
Serial.flush();
}
break;
case 'I':
sscanf(s + 3, "%d", &c);
// sprintf(temp, "display.setDisplayMode(%s)\n", c == 0 ? "INKPLATE_1BIT" : "INKPLATE_3BIT");
// Serial.print(temp);
if (c == INKPLATE_1BIT)
display.selectDisplayMode(INKPLATE_1BIT);
if (c == INKPLATE_3BIT)
display.selectDisplayMode(INKPLATE_3BIT);
break;
case 'J':
sscanf(s + 3, "%c", &b);
if (b == '?')
{
// if (0 == 0) {
// Serial.println("#J(0)*");
//} else {
// Serial.println("#J(1)*");
//}
if (display.getDisplayMode() == INKPLATE_1BIT)
{
Serial.println("#J(0)*");
Serial.flush();
}
if (display.getDisplayMode() == INKPLATE_3BIT)
{
Serial.println("#J(1)*");
Serial.flush();
}
}
break;
case 'K':
sscanf(s + 3, "%c", &b);
if (b == '1')
{
// Serial.print("display.clearDisplay();\n");
display.clearDisplay();
}
break;
case 'L':
sscanf(s + 3, "%c", &b);
if (b == '1')
{
// Serial.print("display.display();\n");
display.display();
}
break;
case 'M':
sscanf(s + 3, "%d,%d,%d", &y1, &x2, &y2);
// sprintf(temp, "display.partialUpdate(%d, %d, %d);\n", y1, x2, y2);
// Serial.print(temp);
display.partialUpdate();
break;
case 'N':
sscanf(s + 3, "%c", &b);
if (b == '?')
{
Serial.print("#N(");
Serial.print(display.readTemperature(), DEC);
// Serial.print(23, DEC);
Serial.println(")*");
Serial.flush();
}
break;
case 'O':
sscanf(s + 3, "%d", &c);
if (c >= 0 && c <= 2)
{
Serial.print("#O(");
Serial.print(display.readTouchpad(c), DEC);
// Serial.print(0, DEC);
Serial.println(")*");
Serial.flush();
}
break;
case 'P':
sscanf(s + 3, "%c", &b);
if (b == '?')
{
Serial.print("#P(");
Serial.print(display.readBattery(), 2);
// Serial.print(3.54, 2);
Serial.println(")*");
Serial.flush();
}
break;
case 'Q':
sscanf(s + 3, "%d", &c);
c &= 1;
// if (c == 0) Serial.print("display.einkOff();\n");
// if (c == 1) Serial.print("display.einkOn();\n");
if (c == 0)
display.einkOff();
if (c == 1)
display.einkOn();
break;
case 'R':
sscanf(s + 3, "%c", &b);
if (b == '?')
{
Serial.print("#R(");
Serial.print(display.getPanelState(), DEC);
// Serial.print(1, DEC);
Serial.println(")*");
Serial.flush();
}
break;
}
*s = 0;
*e = 0;
}
}
}
}
int hexToChar(char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
int hexToChar(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
}

View File

@ -29,7 +29,7 @@ bool Image::drawImage(const char *path, int x, int y, bool dither, bool invert)
else
{
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)
return drawJpegFromSD(path, x, y, dither, invert);
}
@ -43,143 +43,6 @@ bool Image::drawImage(const WiFiClient *s, int x, int y, int len, bool dither, b
};
// Loads first line in current dither buffer
void Image::ditherStart(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits)
{
for (int i = 0; i < w; ++i)
if (bits == 24)
{
if (invert)
ditherBuffer[0][i] = ((255 - *(bufferPtr++)) * 2126 / 10000) + ((255 - *(bufferPtr++)) * 7152 / 10000) +
((255 - *(bufferPtr++)) * 722 / 10000);
else
ditherBuffer[0][i] =
(*(bufferPtr++) * 2126 / 10000) + (*(bufferPtr++) * 7152 / 10000) + (*(bufferPtr++) * 722 / 10000);
}
else if (bits == 8)
{
if (invert)
ditherBuffer[0][i] = 255 - *(bufferPtr++);
else
ditherBuffer[0][i] = *(bufferPtr++);
}
if (bits == 4)
{
int _w = w / 8;
int paddingBits = w % 8;
for (int i = 0; i < _w; ++i)
{
for (int n = 0; n < 4; n++)
{
uint8_t temp = *(bufferPtr++);
ditherBuffer[0][i * 8 + n * 2] = temp & 0xF0;
ditherBuffer[0][i * 8 + n * 2 + 1] = (temp & 0x0F) << 4;
if (invert)
{
ditherBuffer[0][i * 8 + n * 2] = ~ditherBuffer[0][i * 8 + n * 2];
ditherBuffer[0][i * 8 + n * 2 + 1] = ~ditherBuffer[0][i * 8 + n * 2 + 1];
}
}
}
if (paddingBits)
{
uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++);
if (invert)
pixelRow = ~pixelRow;
for (int n = 0; n < paddingBits; n++)
{
ditherBuffer[0][_w * 8 + n] = (pixelRow & (0xFULL << ((7 - n) * 4))) >> ((7 - n) * 4 - 4);
}
}
}
}
// Loads next line, after this ditherGetPixel can be called and alters values in next line
void Image::ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits)
{
for (int i = 0; i < w; ++i)
{
if (bits == 24)
{
if (invert)
ditherBuffer[1][i] = ((255 - *(bufferPtr++)) * 2126 / 10000) + ((255 - *(bufferPtr++)) * 7152 / 10000) +
((255 - *(bufferPtr++)) * 722 / 10000);
else
ditherBuffer[1][i] =
(*(bufferPtr++) * 2126 / 10000) + (*(bufferPtr++) * 7152 / 10000) + (*(bufferPtr++) * 722 / 10000);
}
else if (bits == 8)
{
if (invert)
ditherBuffer[1][i] = 255 - *(bufferPtr++);
else
ditherBuffer[1][i] = *(bufferPtr++);
}
}
if (bits == 4)
{
int _w = w / 8;
int paddingBits = w % 8;
for (int i = 0; i < _w; ++i)
{
for (int n = 0; n < 4; n++)
{
uint8_t temp = *(bufferPtr++);
ditherBuffer[0][i * 8 + n * 2] = temp & 0xF0;
ditherBuffer[0][i * 8 + n * 2 + 1] = (temp & 0x0F) << 4;
if (invert)
{
ditherBuffer[0][i * 8 + n * 2] = ~ditherBuffer[0][i * 8 + n * 2];
ditherBuffer[0][i * 8 + n * 2 + 1] = ~ditherBuffer[0][i * 8 + n * 2 + 1];
}
}
}
if (paddingBits)
{
uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++);
if (invert)
pixelRow = ~pixelRow;
for (int n = 0; n < paddingBits; n++)
{
ditherBuffer[1][_w * 8 + n] = (pixelRow & (0xFULL << (28 - n * 4))) >> (28 - n * 4 - 4);
}
}
}
}
// Gets specific pixel, mainly at i, j is just used for bound checking when changing next line values
uint8_t Image::ditherGetPixel(int i, int j, int w, int h)
{
uint8_t oldpixel = ditherBuffer[0][i];
uint8_t newpixel = (oldpixel & B11100000);
ditherBuffer[0][i] = newpixel;
uint8_t quant_error = oldpixel - newpixel;
if (i + 1 < w)
ditherBuffer[0][i + 1] = min(255, (int)ditherBuffer[0][i + 1] + (((int)quant_error * 7) >> 4));
if (j + 1 < h && 0 <= i - 1)
ditherBuffer[1][i - 1] = min(255, (int)ditherBuffer[1][i - 1] + (((int)quant_error * 3) >> 4));
if (j + 1 < h)
ditherBuffer[1][i + 0] = min(255, (int)ditherBuffer[1][i + 0] + (((int)quant_error * 5) >> 4));
if (j + 1 < h && i + 1 < w)
ditherBuffer[1][i + 1] = min(255, (int)ditherBuffer[1][i + 1] + (((int)quant_error * 1) >> 4));
return newpixel;
}
// Swaps current and next line, for next one to be overwritten
uint8_t Image::ditherSwap(int w)
{
for (int i = 0; i < w; ++i)
ditherBuffer[0][i] = ditherBuffer[1][i];
}
void Image::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
{
int16_t byteWidth = (w + 7) >> 3; // Bitmap scanline pad = whole byte

View File

@ -28,8 +28,8 @@ 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 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 drawBitmapFromSd(const char *fileName, 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);
@ -54,15 +54,16 @@ class Image : virtual public Network
bool _invert);
uint8_t pixelBuffer[800 * 4 + 5];
uint8_t ditherBuffer[800 * 3 + 5][2];
uint8_t pallete[128]; // 2 colors per byte, _###_###
uint8_t ditherBuffer[2][800 + 5];
uint8_t ditherPalette[256]; // 8 bit colors
uint8_t palette[128]; // 2 3 bit colors per byte, _###_###
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(int i, int j, int w, int h);
uint8_t ditherSwap(int w);
uint8_t ditherGetPixel(uint8_t px, int i, int w, bool paletted);
void ditherSwap(int w);
void readBmpHeader(uint8_t *buf, bitmapHeader *_h);
void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h);

View File

@ -1,5 +1,12 @@
#include "Image.h"
bool Image::legalBmp(bitmapHeader *bmpHeader)
{
return bmpHeader->signature == 0x4D42 && bmpHeader->compression == 0 &&
(bmpHeader->color == 1 || bmpHeader->color == 4 || bmpHeader->color == 8 || bmpHeader->color == 16 ||
bmpHeader->color == 24 || bmpHeader->color == 32);
}
void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
{
uint8_t header[55];
@ -7,8 +14,8 @@ void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
_f->rewind();
_f->read(header, 55);
uint16_t color = read16(header + 28);
uint32_t totalColors = read32(header + 46);
uint16_t color = READ16(header + 28);
uint32_t totalColors = READ32(header + 46);
if (color <= 8)
{
@ -31,16 +38,16 @@ void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
void Image::readBmpHeader(uint8_t *buf, bitmapHeader *_h)
{
_h->signature = read16(buf + 0);
_h->fileSize = read32(buf + 2);
_h->startRAW = read32(buf + 10);
_h->dibHeaderSize = read32(buf + 14);
_h->width = read32(buf + 18);
_h->height = read32(buf + 22);
_h->color = read16(buf + 28);
_h->compression = read32(buf + 30);
_h->signature = READ16(buf + 0);
_h->fileSize = READ32(buf + 2);
_h->startRAW = READ32(buf + 10);
_h->dibHeaderSize = READ32(buf + 14);
_h->width = READ32(buf + 18);
_h->height = READ32(buf + 22);
_h->color = READ16(buf + 28);
_h->compression = READ32(buf + 30);
uint32_t totalColors = read32(buf + 46);
uint32_t totalColors = READ32(buf + 46);
uint8_t paletteRGB[1024];
@ -50,110 +57,33 @@ void Image::readBmpHeader(uint8_t *buf, bitmapHeader *_h)
totalColors = (1ULL << _h->color);
memcpy(paletteRGB, buf + 53, totalColors * 4);
memset(pallete, 0, sizeof pallete);
memset(palette, 0, sizeof palette);
for (int i = 0; i < totalColors; ++i)
{
uint32_t c = read32(paletteRGB + (i << 2));
uint32_t c = READ32(paletteRGB + (i << 2));
uint8_t r = (c & 0xFF000000) >> 24;
uint8_t g = (c & 0x00FF0000) >> 16;
uint8_t b = (c & 0x0000FF00) >> 8;
pallete[i >> 1] |= RGB3BIT(r, g, b) << (i & 1 ? 0 : 4);
palette[i >> 1] |= RGB3BIT(r, g, b) << (i & 1 ? 0 : 4);
ditherPalette[i] = RGB8BIT(r, g, b);
}
}
};
bool Image::legalBmp(bitmapHeader *bmpHeader)
{
return bmpHeader->signature == 0x4D42 && bmpHeader->compression == 0 &&
(bmpHeader->color == 1 || bmpHeader->color == 4 || bmpHeader->color == 8 || bmpHeader->color == 16 ||
bmpHeader->color == 24 || bmpHeader->color == 32);
}
void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool dither, bool invert)
{
int16_t w = bmpHeader->width, h = bmpHeader->height;
int8_t c = bmpHeader->color;
startWrite();
for (int j = 0; j < w; ++j)
{
switch (c)
{
case 1:
// Should we ignore palette on 1 bit?
writePixel(x + j, y, (invert ^ (pallete[0] < pallete[1])) ^ !!(pixelBuffer[j >> 3] & (1 << (7 - j & 7))));
break;
// as for 2 bit, literally cannot find an example online or in PS, so skipped
case 4: {
uint8_t px = pixelBuffer[j >> 1] & (j & 1 ? 0x0F : 0xF0) >> (j & 1 ? 0 : 4);
if (invert)
writePixel(x + j, y, 7 - (pallete[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4)));
else
writePixel(x + j, y, pallete[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4));
break;
}
case 8: {
uint8_t px = pixelBuffer[j];
if (invert)
writePixel(x + j, y, 7 - (pallete[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4)));
else
writePixel(x + j, y, pallete[px >> 1] & (px & 1 ? 0x0F : 0xF0) >> (px & 1 ? 0 : 4));
break;
}
case 16: {
uint16_t px = ((uint16_t)pixelBuffer[(j << 1) | 1] << 8) | pixelBuffer[(j << 1)];
uint8_t r = (px & 0x7C00) >> 7;
uint8_t g = (px & 0x3E0) >> 2;
uint8_t b = (px & 0x1F) << 3;
if (invert)
writePixel(x + j, y, 7 - RGB3BIT(r, g, b));
else
writePixel(x + j, y, RGB3BIT(r, g, b));
break;
}
case 24: {
uint8_t r = pixelBuffer[j * 3];
uint8_t g = pixelBuffer[j * 3 + 1];
uint8_t b = pixelBuffer[j * 3 + 2];
if (invert)
writePixel(x + j, y, 7 - RGB3BIT(r, g, b));
else
writePixel(x + j, y, RGB3BIT(r, g, b));
break;
}
case 32:
uint8_t r = pixelBuffer[j * 4];
uint8_t g = pixelBuffer[j * 4 + 1];
uint8_t b = pixelBuffer[j * 4 + 2];
if (invert)
writePixel(x + j, y, 7 - RGB3BIT(r, g, b));
else
writePixel(x + j, y, RGB3BIT(r, g, b));
break;
}
}
endWrite();
}
bool Image::drawBitmapFromSD(const char *fileName, int x, int y, bool dither, bool invert)
bool Image::drawBitmapFromSd(const char *fileName, int x, int y, bool dither, bool invert)
{
SdFile dat;
if (dat.open(fileName, O_RDONLY))
return drawBitmapFromSD(&dat, x, y, dither, invert);
return drawBitmapFromSd(&dat, x, y, dither, invert);
else
return 0;
}
bool Image::drawBitmapFromSD(SdFile *p, int x, int y, bool dither, bool invert)
bool Image::drawBitmapFromSd(SdFile *p, int x, int y, bool dither, bool invert)
{
bitmapHeader bmpHeader;
@ -174,11 +104,11 @@ bool Image::drawBitmapFromSD(SdFile *p, int x, int y, bool dither, bool invert)
int8_t c = bmpHeader.color;
p->seekSet(bmpHeader.startRAW);
if (dither)
memset(ditherBuffer, 0, sizeof ditherBuffer);
for (int i = 0; i < h; ++i)
{
int16_t n = rowSize(w, c);
int16_t n = ROWSIZE(w, c);
p->read(pixelBuffer, n);
displayBmpLine(x, y + bmpHeader.height - i, &bmpHeader, dither, invert);
}
@ -203,15 +133,125 @@ bool Image::drawBitmapFromWeb(const char *url, int x, int y, bool dither, bool i
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)
{
memcpy(pixelBuffer, bufferPtr, rowSize(bmpHeader.width, bmpHeader.color));
memcpy(pixelBuffer, bufferPtr, ROWSIZE(bmpHeader.width, bmpHeader.color));
displayBmpLine(x, y + bmpHeader.height - i, &bmpHeader, dither, invert);
bufferPtr += rowSize(bmpHeader.width, bmpHeader.color);
bufferPtr += ROWSIZE(bmpHeader.width, bmpHeader.color);
}
free(buf);
return 1;
}
void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool dither, bool invert)
{
int16_t w = bmpHeader->width, h = bmpHeader->height;
int8_t c = bmpHeader->color;
startWrite();
for (int j = 0; j < w; ++j)
{
switch (c)
{
case 1:
writePixel(x + j, y, (invert ^ (palette[0] < palette[1])) ^ !!(pixelBuffer[j >> 3] & (1 << (7 - j & 7))));
break;
// as for 2 bit, literally cannot find an example online or in PS, so skipped
case 4: {
uint8_t px = pixelBuffer[j >> 1] & (j & 1 ? 0x0F : 0xF0) >> (j & 1 ? 0 : 4);
uint8_t val;
if (dither)
val = ditherGetPixel(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);
break;
}
case 8: {
uint8_t px = pixelBuffer[j];
uint8_t val;
if (dither)
val = ditherGetPixel(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);
break;
}
case 16: {
uint16_t px = ((uint16_t)pixelBuffer[(j << 1) | 1] << 8) | pixelBuffer[(j << 1)];
uint8_t r = (px & 0x7C00) >> 7;
uint8_t g = (px & 0x3E0) >> 2;
uint8_t b = (px & 0x1F) << 3;
uint8_t val;
if (dither)
val = ditherGetPixel(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);
break;
}
case 24: {
uint8_t r = pixelBuffer[j * 3];
uint8_t g = pixelBuffer[j * 3 + 1];
uint8_t b = pixelBuffer[j * 3 + 2];
uint8_t val;
if (dither)
val = ditherGetPixel(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);
break;
}
case 32:
uint8_t r = pixelBuffer[j * 4];
uint8_t g = pixelBuffer[j * 4 + 1];
uint8_t b = pixelBuffer[j * 4 + 2];
uint8_t val;
if (dither)
val = ditherGetPixel(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));
break;
}
}
ditherSwap(w);
endWrite();
}

View File

@ -0,0 +1,32 @@
#include "Image.h"
uint8_t Image::ditherGetPixel(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 quantError = oldPixel - newPixel;
ditherBuffer[1][i + 0] += (quantError * 5) >> 4;
if (i != w - 1)
{
ditherBuffer[0][i + 1] += (quantError * 7) >> 4;
ditherBuffer[1][i + 1] += (quantError * 1) >> 4;
}
if (i != 0)
ditherBuffer[1][i - 1] += (quantError * 3) >> 4;
return newPixel >> 5;
}
void Image::ditherSwap(int w)
{
for (int i = 0; i < w; ++i)
{
ditherBuffer[0][i] = ditherBuffer[1][i];
ditherBuffer[1][i] = 0;
}
}

View File

@ -16,8 +16,10 @@
#define PAD3 2
#define RGB3BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 13)
#define read32(c) (uint32_t)(*(c) | (*((c) + 1) << 8) | (*((c) + 2) << 16) | (*((c) + 3) << 24));
#define read16(c) (uint16_t)(*(c) | (*((c) + 1) << 8));
#define rowSize(w, c) (((int16_t)c * w + 31) >> 5) << 2
#define RGB8BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 8)
#define READ32(c) (uint32_t)(*(c) | (*((c) + 1) << 8) | (*((c) + 2) << 16) | (*((c) + 3) << 24));
#define READ16(c) (uint16_t)(*(c) | (*((c) + 1) << 8));
#define ROWSIZE(w, c) (((int16_t)c * w + 31) >> 5) << 2
#endif

View File

@ -6,7 +6,17 @@
Inkplate display(INKPLATE_1BIT);
#define DELAYMS 1000
const char *images[] = {"1bit.bmp", "4bit.bmp", "8bit.bmp", "16bit.bmp", "24bit.bmp", "32bit.bmp"};
const char *imageUrls[] = {
"https://raw.githubusercontent.com/nitko12/Inkplate-revision/master/test/bitmaps/1bit.bmp",
"https://raw.githubusercontent.com/nitko12/Inkplate-revision/master/test/bitmaps/4bit.bmp",
"https://raw.githubusercontent.com/nitko12/Inkplate-revision/master/test/bitmaps/8bit.bmp",
"https://raw.githubusercontent.com/nitko12/Inkplate-revision/master/test/bitmaps/16bit.bmp",
"https://raw.githubusercontent.com/nitko12/Inkplate-revision/master/test/bitmaps/24bit.bmp",
"https://raw.githubusercontent.com/nitko12/Inkplate-revision/master/test/bitmaps/32bit.bmp",
};
const bool depth[] = {INKPLATE_1BIT, INKPLATE_3BIT, INKPLATE_3BIT, INKPLATE_3BIT, INKPLATE_3BIT, INKPLATE_3BIT};
void setup()
@ -91,7 +101,7 @@ void loop()
display.clearDisplay();
delay(5000);
display.drawBitmapFromSD(images[j], 0, 0, dither, invert);
display.drawBitmapFromSd(images[j], 0, 0, dither, invert);
display.display();
display.clearDisplay();
delay(5000);
@ -111,6 +121,7 @@ void loop()
display.setCursor(100, 100);
display.print("Displaying ");
display.print(images[j]);
display.print(" from web");
if (!dither)
display.print(" non");
display.print(" dithered and");
@ -122,7 +133,7 @@ void loop()
display.clearDisplay();
delay(5000);
display.drawBitmapFromSD(images[j], 0, 0, dither, invert);
display.drawBitmapFromWeb(imageUrls[j], 0, 0, dither, invert);
display.display();
display.clearDisplay();
delay(5000);

View File

@ -22,7 +22,17 @@ void loop()
if (display.sdCardInit())
{
Serial.println(display.drawBitmapFromSD("8bit.bmp", 0, 0));
Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 0, 0));
}
display.display();
delay(5000);
if (display.sdCardInit())
{
int16_t t = millis();
Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 1, 0));
Serial.println(millis() - t);
}
display.display();