Added bmp dither.
This commit is contained in:
parent
e5ca63391a
commit
82a082003a
|
@ -16,15 +16,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Inkplate.h" //Include Inkplate library to the sketch
|
#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 <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 ssid "" // Name of the WiFi network (SSID) that you want to connect Inkplate to
|
||||||
#define pass "" // Password of that WiFi network
|
#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() {
|
void setup()
|
||||||
|
{
|
||||||
display.begin(); // Init Inkplate library (you should call this function ONLY ONCE)
|
display.begin(); // Init Inkplate library (you should call this function ONLY ONCE)
|
||||||
display.clearDisplay(); // Clear frame buffer of display
|
display.clearDisplay(); // Clear frame buffer of display
|
||||||
display.display(); // Put clear image on display
|
display.display(); // Put clear image on display
|
||||||
|
@ -34,14 +36,21 @@ void setup() {
|
||||||
display.println("Scanning for WiFi networks..."); // Write text
|
display.println("Scanning for WiFi networks..."); // Write text
|
||||||
display.display(); // Send everything to display (refresh display)
|
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
|
int n = WiFi.scanNetworks(); // Start searching WiFi networks and put the nubmer of found WiFi networks in variable
|
||||||
if (n == 0) { //If you did not find any network, show the message and stop the program.
|
// 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.print("No WiFi networks found!");
|
||||||
display.partialUpdate();
|
display.partialUpdate();
|
||||||
while (true);
|
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++) {
|
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.SSID(i));
|
||||||
display.print((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? 'O' : '*');
|
display.print((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? 'O' : '*');
|
||||||
display.print('\n');
|
display.print('\n');
|
||||||
|
@ -55,8 +64,10 @@ void setup() {
|
||||||
display.print("Connecting to "); // Print the name of WiFi network
|
display.print("Connecting to "); // Print the name of WiFi network
|
||||||
display.print(ssid);
|
display.print(ssid);
|
||||||
WiFi.begin(ssid, pass); // Try to connect to WiFi network
|
WiFi.begin(ssid, pass); // Try to connect to WiFi network
|
||||||
while (WiFi.status() != WL_CONNECTED) {
|
while (WiFi.status() != WL_CONNECTED)
|
||||||
delay(1000); //While it is connecting to network, display dot every second, just to know that Inkplate is alive.
|
{
|
||||||
|
delay(1000); // While it is connecting to network, display dot every second, just to know that Inkplate is
|
||||||
|
// alive.
|
||||||
display.print('.');
|
display.print('.');
|
||||||
display.partialUpdate();
|
display.partialUpdate();
|
||||||
}
|
}
|
||||||
|
@ -64,8 +75,10 @@ void setup() {
|
||||||
display.partialUpdate();
|
display.partialUpdate();
|
||||||
|
|
||||||
HTTPClient http;
|
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.begin("http://example.com/index.html"))
|
||||||
if(http.GET()>0) { //If connection was successful, try to read content of the Web page and display it on screen
|
{ // 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;
|
String htmlText;
|
||||||
htmlText = http.getString();
|
htmlText = http.getString();
|
||||||
display.setTextSize(1); // Set smaller text size, so everything can fit on screen
|
display.setTextSize(1); // Set smaller text size, so everything can fit on screen
|
||||||
|
@ -77,6 +90,7 @@ void setup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop()
|
||||||
|
{
|
||||||
// Nothing
|
// Nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
|
|
||||||
#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(
|
||||||
|
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
|
SdFile file; // Create SdFile object used for accessing files on SD card
|
||||||
|
|
||||||
void setup() {
|
void setup()
|
||||||
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
display.begin(); // Init Inkplate library (you should call this function ONLY ONCE)
|
display.begin(); // Init Inkplate library (you should call this function ONLY ONCE)
|
||||||
|
@ -34,39 +36,45 @@ void setup() {
|
||||||
display.display(); // Put clear image on 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=0, Y=0
|
// 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
|
// NOTE: Both drawBitmapFromSd methods allow for an optional fourth "invert" parameter. Setting this parameter
|
||||||
//will flip all colors on the image, making black white and white black. This may be necessary when exporting bitmaps from
|
// to true will flip all colors on the image, making black white and white black. This may be necessary when
|
||||||
//certain softwares.
|
// exporting bitmaps from certain softwares.
|
||||||
if (!display.drawBitmapFromSD("image1.bmp", 0, 0, 1)) {
|
if (!display.drawBitmapFromSd("image1.bmp", 0, 0, 1))
|
||||||
|
{
|
||||||
// If is something failed (wrong filename or wrong bitmap format), write error message on the screen.
|
// 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!
|
// REMEMBER! You can only use Windows Bitmap file with color depth of 1, 4, 8 or 24 bits with no
|
||||||
//You can turn of dithering for somewhat faster image load by changing the last 1 to 0, or removing the 1 argument completely
|
// 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.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)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
||||||
// Now try to load image using SdFat library class (for more advanced users) and display image on epaper.
|
// 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)) {
|
if (file.open("image2.bmp", O_RDONLY))
|
||||||
display.drawBitmapFromSD(&file, 0, 0);
|
{
|
||||||
|
display.drawBitmapFromSd(&file, 0, 0);
|
||||||
display.display();
|
display.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop()
|
||||||
|
{
|
||||||
// Nothing...
|
// Nothing...
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
If we missed some function, you can modify this and make yor own.
|
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.
|
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)
|
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.
|
You can send commands via USB port or by directly connecting to ESP32 TX and RX pins.
|
||||||
|
@ -31,17 +32,22 @@ Inkplate display(INKPLATE_1BIT);
|
||||||
#define BUFFER_SIZE 1000
|
#define BUFFER_SIZE 1000
|
||||||
char commandBuffer[BUFFER_SIZE + 1];
|
char commandBuffer[BUFFER_SIZE + 1];
|
||||||
char strTemp[2001];
|
char strTemp[2001];
|
||||||
void setup() {
|
void setup()
|
||||||
|
{
|
||||||
display.begin();
|
display.begin();
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
memset(commandBuffer, 0, BUFFER_SIZE);
|
memset(commandBuffer, 0, BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop()
|
||||||
|
{
|
||||||
// put your main code here, to run repeatedly:
|
// put your main code here, to run repeatedly:
|
||||||
if (Serial.available()) {
|
if (Serial.available())
|
||||||
while (Serial.available()) {
|
{
|
||||||
for (int i = 0; i < (BUFFER_SIZE - 1); i++) {
|
while (Serial.available())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (BUFFER_SIZE - 1); i++)
|
||||||
|
{
|
||||||
commandBuffer[i] = commandBuffer[i + 1];
|
commandBuffer[i] = commandBuffer[i + 1];
|
||||||
}
|
}
|
||||||
commandBuffer[BUFFER_SIZE - 1] = Serial.read();
|
commandBuffer[BUFFER_SIZE - 1] = Serial.read();
|
||||||
|
@ -49,16 +55,22 @@ void loop() {
|
||||||
}
|
}
|
||||||
char *s = NULL;
|
char *s = NULL;
|
||||||
char *e = NULL;
|
char *e = NULL;
|
||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
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 (commandBuffer[i] == '#' && s == NULL)
|
||||||
|
s = &commandBuffer[i];
|
||||||
|
if (commandBuffer[i] == '*' && e == NULL)
|
||||||
|
e = &commandBuffer[i];
|
||||||
}
|
}
|
||||||
if (s != NULL && e != NULL) {
|
if (s != NULL && e != NULL)
|
||||||
if ((e - s) > 0) {
|
{
|
||||||
|
if ((e - s) > 0)
|
||||||
|
{
|
||||||
int x, x1, x2, y, y1, y2, x3, y3, l, c, w, h, r, n;
|
int x, x1, x2, y, y1, y2, x3, y3, l, c, w, h, r, n;
|
||||||
char b;
|
char b;
|
||||||
char temp[150];
|
char temp[150];
|
||||||
switch (*(s + 1)) {
|
switch (*(s + 1))
|
||||||
|
{
|
||||||
case '?':
|
case '?':
|
||||||
Serial.print("OK");
|
Serial.print("OK");
|
||||||
break;
|
break;
|
||||||
|
@ -150,10 +162,12 @@ void loop() {
|
||||||
case 'C':
|
case 'C':
|
||||||
sscanf(s + 3, "\"%2000[^\"]\"", strTemp);
|
sscanf(s + 3, "\"%2000[^\"]\"", strTemp);
|
||||||
n = strlen(strTemp);
|
n = strlen(strTemp);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
strTemp[i] = toupper(strTemp[i]);
|
strTemp[i] = toupper(strTemp[i]);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < n; i += 2) {
|
for (int i = 0; i < n; i += 2)
|
||||||
|
{
|
||||||
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
|
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
|
||||||
}
|
}
|
||||||
strTemp[n / 2] = 0;
|
strTemp[n / 2] = 0;
|
||||||
|
@ -181,8 +195,10 @@ void loop() {
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
// sprintf(temp, "display.setTextWrap(%s)\n", b == 'T' ? "True" : "False");
|
// sprintf(temp, "display.setTextWrap(%s)\n", b == 'T' ? "True" : "False");
|
||||||
// Serial.print(temp);
|
// Serial.print(temp);
|
||||||
if (b == 'T') display.setTextWrap(true);
|
if (b == 'T')
|
||||||
if (b == 'F') display.setTextWrap(false);
|
display.setTextWrap(true);
|
||||||
|
if (b == 'F')
|
||||||
|
display.setTextWrap(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'G':
|
case 'G':
|
||||||
|
@ -196,23 +212,28 @@ void loop() {
|
||||||
case 'H':
|
case 'H':
|
||||||
sscanf(s + 3, "%d,%d,\"%149[^\"]\"", &x, &y, strTemp);
|
sscanf(s + 3, "%d,%d,\"%149[^\"]\"", &x, &y, strTemp);
|
||||||
n = strlen(strTemp);
|
n = strlen(strTemp);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
strTemp[i] = toupper(strTemp[i]);
|
strTemp[i] = toupper(strTemp[i]);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < n; i += 2) {
|
for (int i = 0; i < n; i += 2)
|
||||||
|
{
|
||||||
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
|
strTemp[i / 2] = (hexToChar(strTemp[i]) << 4) | (hexToChar(strTemp[i + 1]) & 0x0F);
|
||||||
}
|
}
|
||||||
strTemp[n / 2] = 0;
|
strTemp[n / 2] = 0;
|
||||||
r = display.sdCardInit();
|
r = display.sdCardInit();
|
||||||
if (r) {
|
if (r)
|
||||||
r = display.drawBitmapFromSD(strTemp, x, y);
|
{
|
||||||
|
r = display.drawBitmapFromSd(strTemp, x, y);
|
||||||
Serial.print("#H(");
|
Serial.print("#H(");
|
||||||
Serial.print(r, DEC);
|
Serial.print(r, DEC);
|
||||||
Serial.println(")*");
|
Serial.println(")*");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
// sprintf(temp, "display.drawBitmap(%d, %d, %s)\n", x, y, strTemp);
|
// sprintf(temp, "display.drawBitmap(%d, %d, %s)\n", x, y, strTemp);
|
||||||
// Serial.print(temp);
|
// Serial.print(temp);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Serial.println("#H(-1)*");
|
Serial.println("#H(-1)*");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
@ -222,23 +243,28 @@ void loop() {
|
||||||
sscanf(s + 3, "%d", &c);
|
sscanf(s + 3, "%d", &c);
|
||||||
// sprintf(temp, "display.setDisplayMode(%s)\n", c == 0 ? "INKPLATE_1BIT" : "INKPLATE_3BIT");
|
// sprintf(temp, "display.setDisplayMode(%s)\n", c == 0 ? "INKPLATE_1BIT" : "INKPLATE_3BIT");
|
||||||
// Serial.print(temp);
|
// Serial.print(temp);
|
||||||
if (c == INKPLATE_1BIT) display.selectDisplayMode(INKPLATE_1BIT);
|
if (c == INKPLATE_1BIT)
|
||||||
if (c == INKPLATE_3BIT) display.selectDisplayMode(INKPLATE_3BIT);
|
display.selectDisplayMode(INKPLATE_1BIT);
|
||||||
|
if (c == INKPLATE_3BIT)
|
||||||
|
display.selectDisplayMode(INKPLATE_3BIT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'J':
|
case 'J':
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
if (b == '?') {
|
if (b == '?')
|
||||||
|
{
|
||||||
// if (0 == 0) {
|
// if (0 == 0) {
|
||||||
// Serial.println("#J(0)*");
|
// Serial.println("#J(0)*");
|
||||||
//} else {
|
//} else {
|
||||||
// Serial.println("#J(1)*");
|
// Serial.println("#J(1)*");
|
||||||
//}
|
//}
|
||||||
if (display.getDisplayMode() == INKPLATE_1BIT) {
|
if (display.getDisplayMode() == INKPLATE_1BIT)
|
||||||
|
{
|
||||||
Serial.println("#J(0)*");
|
Serial.println("#J(0)*");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
}
|
}
|
||||||
if (display.getDisplayMode() == INKPLATE_3BIT) {
|
if (display.getDisplayMode() == INKPLATE_3BIT)
|
||||||
|
{
|
||||||
Serial.println("#J(1)*");
|
Serial.println("#J(1)*");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
@ -247,7 +273,8 @@ void loop() {
|
||||||
|
|
||||||
case 'K':
|
case 'K':
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
if (b == '1') {
|
if (b == '1')
|
||||||
|
{
|
||||||
// Serial.print("display.clearDisplay();\n");
|
// Serial.print("display.clearDisplay();\n");
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
}
|
}
|
||||||
|
@ -255,7 +282,8 @@ void loop() {
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
if (b == '1') {
|
if (b == '1')
|
||||||
|
{
|
||||||
// Serial.print("display.display();\n");
|
// Serial.print("display.display();\n");
|
||||||
display.display();
|
display.display();
|
||||||
}
|
}
|
||||||
|
@ -270,7 +298,8 @@ void loop() {
|
||||||
|
|
||||||
case 'N':
|
case 'N':
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
if (b == '?') {
|
if (b == '?')
|
||||||
|
{
|
||||||
Serial.print("#N(");
|
Serial.print("#N(");
|
||||||
Serial.print(display.readTemperature(), DEC);
|
Serial.print(display.readTemperature(), DEC);
|
||||||
// Serial.print(23, DEC);
|
// Serial.print(23, DEC);
|
||||||
|
@ -281,7 +310,8 @@ void loop() {
|
||||||
|
|
||||||
case 'O':
|
case 'O':
|
||||||
sscanf(s + 3, "%d", &c);
|
sscanf(s + 3, "%d", &c);
|
||||||
if (c >= 0 && c <= 2) {
|
if (c >= 0 && c <= 2)
|
||||||
|
{
|
||||||
Serial.print("#O(");
|
Serial.print("#O(");
|
||||||
Serial.print(display.readTouchpad(c), DEC);
|
Serial.print(display.readTouchpad(c), DEC);
|
||||||
// Serial.print(0, DEC);
|
// Serial.print(0, DEC);
|
||||||
|
@ -292,7 +322,8 @@ void loop() {
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
if (b == '?') {
|
if (b == '?')
|
||||||
|
{
|
||||||
Serial.print("#P(");
|
Serial.print("#P(");
|
||||||
Serial.print(display.readBattery(), 2);
|
Serial.print(display.readBattery(), 2);
|
||||||
// Serial.print(3.54, 2);
|
// Serial.print(3.54, 2);
|
||||||
|
@ -306,13 +337,16 @@ void loop() {
|
||||||
c &= 1;
|
c &= 1;
|
||||||
// if (c == 0) Serial.print("display.einkOff();\n");
|
// if (c == 0) Serial.print("display.einkOff();\n");
|
||||||
// if (c == 1) Serial.print("display.einkOn();\n");
|
// if (c == 1) Serial.print("display.einkOn();\n");
|
||||||
if (c == 0) display.einkOff();
|
if (c == 0)
|
||||||
if (c == 1) display.einkOn();
|
display.einkOff();
|
||||||
|
if (c == 1)
|
||||||
|
display.einkOn();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
sscanf(s + 3, "%c", &b);
|
sscanf(s + 3, "%c", &b);
|
||||||
if (b == '?') {
|
if (b == '?')
|
||||||
|
{
|
||||||
Serial.print("#R(");
|
Serial.print("#R(");
|
||||||
Serial.print(display.getPanelState(), DEC);
|
Serial.print(display.getPanelState(), DEC);
|
||||||
// Serial.print(1, DEC);
|
// Serial.print(1, DEC);
|
||||||
|
@ -327,7 +361,8 @@ void loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int hexToChar(char c) {
|
int hexToChar(char c)
|
||||||
|
{
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
return c - '0';
|
return c - '0';
|
||||||
if (c >= 'A' && c <= 'F')
|
if (c >= 'A' && c <= 'F')
|
||||||
|
|
|
@ -29,7 +29,7 @@ bool Image::drawImage(const char *path, int x, int y, bool dither, bool invert)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
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
|
int16_t byteWidth = (w + 7) >> 3; // Bitmap scanline pad = whole byte
|
||||||
|
|
|
@ -28,8 +28,8 @@ 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 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(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(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);
|
||||||
|
@ -54,15 +54,16 @@ class Image : virtual public Network
|
||||||
bool _invert);
|
bool _invert);
|
||||||
|
|
||||||
uint8_t pixelBuffer[800 * 4 + 5];
|
uint8_t pixelBuffer[800 * 4 + 5];
|
||||||
uint8_t ditherBuffer[800 * 3 + 5][2];
|
uint8_t ditherBuffer[2][800 + 5];
|
||||||
uint8_t pallete[128]; // 2 colors per byte, _###_###
|
uint8_t ditherPalette[256]; // 8 bit colors
|
||||||
|
uint8_t palette[128]; // 2 3 bit colors per byte, _###_###
|
||||||
|
|
||||||
bool legalBmp(bitmapHeader *bmpHeader);
|
bool legalBmp(bitmapHeader *bmpHeader);
|
||||||
|
|
||||||
void ditherStart(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits);
|
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);
|
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 ditherGetPixel(uint8_t px, int i, int w, bool paletted);
|
||||||
uint8_t ditherSwap(int w);
|
void ditherSwap(int w);
|
||||||
|
|
||||||
void readBmpHeader(uint8_t *buf, bitmapHeader *_h);
|
void readBmpHeader(uint8_t *buf, bitmapHeader *_h);
|
||||||
void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h);
|
void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h);
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
#include "Image.h"
|
#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)
|
void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
|
||||||
{
|
{
|
||||||
uint8_t header[55];
|
uint8_t header[55];
|
||||||
|
@ -7,8 +14,8 @@ void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
|
||||||
_f->rewind();
|
_f->rewind();
|
||||||
_f->read(header, 55);
|
_f->read(header, 55);
|
||||||
|
|
||||||
uint16_t color = read16(header + 28);
|
uint16_t color = READ16(header + 28);
|
||||||
uint32_t totalColors = read32(header + 46);
|
uint32_t totalColors = READ32(header + 46);
|
||||||
|
|
||||||
if (color <= 8)
|
if (color <= 8)
|
||||||
{
|
{
|
||||||
|
@ -31,16 +38,16 @@ void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
|
||||||
|
|
||||||
void Image::readBmpHeader(uint8_t *buf, bitmapHeader *_h)
|
void Image::readBmpHeader(uint8_t *buf, bitmapHeader *_h)
|
||||||
{
|
{
|
||||||
_h->signature = read16(buf + 0);
|
_h->signature = READ16(buf + 0);
|
||||||
_h->fileSize = read32(buf + 2);
|
_h->fileSize = READ32(buf + 2);
|
||||||
_h->startRAW = read32(buf + 10);
|
_h->startRAW = READ32(buf + 10);
|
||||||
_h->dibHeaderSize = read32(buf + 14);
|
_h->dibHeaderSize = READ32(buf + 14);
|
||||||
_h->width = read32(buf + 18);
|
_h->width = READ32(buf + 18);
|
||||||
_h->height = read32(buf + 22);
|
_h->height = READ32(buf + 22);
|
||||||
_h->color = read16(buf + 28);
|
_h->color = READ16(buf + 28);
|
||||||
_h->compression = read32(buf + 30);
|
_h->compression = READ32(buf + 30);
|
||||||
|
|
||||||
uint32_t totalColors = read32(buf + 46);
|
uint32_t totalColors = READ32(buf + 46);
|
||||||
|
|
||||||
uint8_t paletteRGB[1024];
|
uint8_t paletteRGB[1024];
|
||||||
|
|
||||||
|
@ -50,110 +57,33 @@ void Image::readBmpHeader(uint8_t *buf, bitmapHeader *_h)
|
||||||
totalColors = (1ULL << _h->color);
|
totalColors = (1ULL << _h->color);
|
||||||
|
|
||||||
memcpy(paletteRGB, buf + 53, totalColors * 4);
|
memcpy(paletteRGB, buf + 53, totalColors * 4);
|
||||||
memset(pallete, 0, sizeof pallete);
|
memset(palette, 0, sizeof palette);
|
||||||
|
|
||||||
for (int i = 0; i < totalColors; ++i)
|
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 r = (c & 0xFF000000) >> 24;
|
||||||
uint8_t g = (c & 0x00FF0000) >> 16;
|
uint8_t g = (c & 0x00FF0000) >> 16;
|
||||||
uint8_t b = (c & 0x0000FF00) >> 8;
|
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)
|
bool Image::drawBitmapFromSd(const char *fileName, int x, int y, 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)
|
|
||||||
{
|
{
|
||||||
SdFile dat;
|
SdFile dat;
|
||||||
if (dat.open(fileName, O_RDONLY))
|
if (dat.open(fileName, O_RDONLY))
|
||||||
return drawBitmapFromSD(&dat, x, y, dither, invert);
|
return drawBitmapFromSd(&dat, x, y, dither, invert);
|
||||||
else
|
else
|
||||||
return 0;
|
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;
|
bitmapHeader bmpHeader;
|
||||||
|
|
||||||
|
@ -174,11 +104,11 @@ bool Image::drawBitmapFromSD(SdFile *p, int x, int y, bool dither, bool invert)
|
||||||
int8_t c = bmpHeader.color;
|
int8_t c = bmpHeader.color;
|
||||||
|
|
||||||
p->seekSet(bmpHeader.startRAW);
|
p->seekSet(bmpHeader.startRAW);
|
||||||
|
if (dither)
|
||||||
|
memset(ditherBuffer, 0, sizeof ditherBuffer);
|
||||||
for (int i = 0; i < h; ++i)
|
for (int i = 0; i < h; ++i)
|
||||||
{
|
{
|
||||||
int16_t n = rowSize(w, c);
|
int16_t n = ROWSIZE(w, c);
|
||||||
|
|
||||||
p->read(pixelBuffer, n);
|
p->read(pixelBuffer, n);
|
||||||
displayBmpLine(x, y + bmpHeader.height - i, &bmpHeader, dither, invert);
|
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)
|
getDisplayMode() != INKPLATE_3BIT)
|
||||||
selectDisplayMode(INKPLATE_3BIT);
|
selectDisplayMode(INKPLATE_3BIT);
|
||||||
|
|
||||||
|
if (dither)
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
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);
|
displayBmpLine(x, y + bmpHeader.height - i, &bmpHeader, dither, invert);
|
||||||
bufferPtr += rowSize(bmpHeader.width, bmpHeader.color);
|
bufferPtr += ROWSIZE(bmpHeader.width, bmpHeader.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return 1;
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,10 @@
|
||||||
#define PAD3 2
|
#define PAD3 2
|
||||||
|
|
||||||
#define RGB3BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 13)
|
#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 RGB8BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 8)
|
||||||
#define read16(c) (uint16_t)(*(c) | (*((c) + 1) << 8));
|
|
||||||
#define rowSize(w, c) (((int16_t)c * w + 31) >> 5) << 2
|
#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
|
#endif
|
|
@ -6,7 +6,17 @@
|
||||||
|
|
||||||
Inkplate display(INKPLATE_1BIT);
|
Inkplate display(INKPLATE_1BIT);
|
||||||
|
|
||||||
|
#define DELAYMS 1000
|
||||||
|
|
||||||
const char *images[] = {"1bit.bmp", "4bit.bmp", "8bit.bmp", "16bit.bmp", "24bit.bmp", "32bit.bmp"};
|
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};
|
const bool depth[] = {INKPLATE_1BIT, INKPLATE_3BIT, INKPLATE_3BIT, INKPLATE_3BIT, INKPLATE_3BIT, INKPLATE_3BIT};
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
|
@ -91,7 +101,7 @@ void loop()
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
||||||
display.drawBitmapFromSD(images[j], 0, 0, dither, invert);
|
display.drawBitmapFromSd(images[j], 0, 0, dither, invert);
|
||||||
display.display();
|
display.display();
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
@ -111,6 +121,7 @@ void loop()
|
||||||
display.setCursor(100, 100);
|
display.setCursor(100, 100);
|
||||||
display.print("Displaying ");
|
display.print("Displaying ");
|
||||||
display.print(images[j]);
|
display.print(images[j]);
|
||||||
|
display.print(" from web");
|
||||||
if (!dither)
|
if (!dither)
|
||||||
display.print(" non");
|
display.print(" non");
|
||||||
display.print(" dithered and");
|
display.print(" dithered and");
|
||||||
|
@ -122,7 +133,7 @@ void loop()
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
||||||
display.drawBitmapFromSD(images[j], 0, 0, dither, invert);
|
display.drawBitmapFromWeb(imageUrls[j], 0, 0, dither, invert);
|
||||||
display.display();
|
display.display();
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
|
@ -22,7 +22,17 @@ void loop()
|
||||||
|
|
||||||
if (display.sdCardInit())
|
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();
|
display.display();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue