Bitmap from web, first working prototype.

This commit is contained in:
Thorinair 2020-07-24 13:33:25 +02:00
parent 682cb5494f
commit 4107d83bc2
3 changed files with 330 additions and 9 deletions

View File

@ -1,6 +1,8 @@
#include <stdlib.h>
#include "Adafruit_GFX.h"
#include "WiFi.h"
#include "HTTPClient.h"
#include "Inkplate.h"
Adafruit_MCP23017 mcp;
SPIClass spi2(HSPI);
@ -331,7 +333,7 @@ uint8_t Inkplate::getDisplayMode() {
int Inkplate::drawBitmapFromSD(SdFile* p, int x, int y) {
if(sdCardOk == 0) return 0;
struct bitmapHeader bmpHeader;
readBmpHeader(p, &bmpHeader);
readBmpHeaderSd(p, &bmpHeader);
if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 || !(bmpHeader.color == 1 || bmpHeader.color == 24)) return 0;
if ((bmpHeader.color == 24 || bmpHeader.color == 32) && getDisplayMode() != INKPLATE_3BIT) {
@ -342,8 +344,8 @@ int Inkplate::drawBitmapFromSD(SdFile* p, int x, int y) {
selectDisplayMode(INKPLATE_1BIT);
}
if (bmpHeader.color == 1) drawMonochromeBitmap(p, bmpHeader, x, y);
if (bmpHeader.color == 24) drawGrayscaleBitmap24(p, bmpHeader, x, y);
if (bmpHeader.color == 1) drawMonochromeBitmapSd(p, bmpHeader, x, y);
if (bmpHeader.color == 24) drawGrayscaleBitmap24Sd(p, bmpHeader, x, y);
return 1;
}
@ -358,6 +360,44 @@ int Inkplate::drawBitmapFromSD(char* fileName, int x, int y) {
}
}
int Inkplate::drawBitmapFromWeb(WiFiClient* s, int x, int y, int len) {
struct bitmapHeader bmpHeader;
readBmpHeaderWeb(s, &bmpHeader);
if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 || !(bmpHeader.color == 1 || bmpHeader.color == 24)) return 0;
if ((bmpHeader.color == 24 || bmpHeader.color == 32) && getDisplayMode() != INKPLATE_3BIT) {
selectDisplayMode(INKPLATE_3BIT);
}
if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) {
selectDisplayMode(INKPLATE_1BIT);
}
if (bmpHeader.color == 1) drawMonochromeBitmapWeb(s, bmpHeader, x, y, len);
if (bmpHeader.color == 24) drawGrayscaleBitmap24Web(s, bmpHeader, x, y, len);
return 1;
}
int Inkplate::drawBitmapFromWeb(char* url, int x, int y) {
if (WiFi.status() != WL_CONNECTED) return 0;
HTTPClient http;
http.getStream().setNoDelay(true);
//http.getStream().setTimeout(1);
http.begin(url);
int httpCode = http.GET();
if (httpCode != 200) return 0;
int32_t len = http.getSize();
if (len <= 0) return 0;
WiFiClient * dat = http.getStreamPtr();
//dat->setTimeout(20);
//dat->setNoDelay(true);
return drawBitmapFromWeb(dat, x, y, len);
}
int Inkplate::sdCardInit() {
spi2.begin(14, 12, 13, 15);
sdCardOk = sd.begin(15, SD_SCK_MHZ(25));
@ -768,7 +808,7 @@ uint16_t Inkplate::read16(uint8_t* c) {
return (*(c) | (*(c + 1) << 8));
}
void Inkplate::readBmpHeader(SdFile *_f, struct bitmapHeader *_h) {
void Inkplate::readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h) {
uint8_t header[100];
_f->rewind();
_f->read(header, 100);
@ -783,7 +823,21 @@ void Inkplate::readBmpHeader(SdFile *_f, struct bitmapHeader *_h) {
return;
}
int Inkplate::drawMonochromeBitmap(SdFile *f, struct bitmapHeader bmpHeader, int x, int y) {
void Inkplate::readBmpHeaderWeb(WiFiClient *_s, struct bitmapHeader *_h) {
uint8_t header[34];
_s->read(header, 34);
_h->signature = read16(header + 0);
_h->fileSize = read32(header + 2);
_h->startRAW = read32(header + 10);
_h->dibHeaderSize = read32(header + 14);
_h->width = read32(header + 18);
_h->height = read32(header + 22);
_h->color = read16(header + 28);
_h->compression = read32(header + 30);
return;
}
int Inkplate::drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y) {
int w = bmpHeader.width;
int h = bmpHeader.height;
uint8_t paddingBits = w % 32;
@ -809,7 +863,7 @@ int Inkplate::drawMonochromeBitmap(SdFile *f, struct bitmapHeader bmpHeader, int
return 1;
}
int Inkplate::drawGrayscaleBitmap24(SdFile *f, struct bitmapHeader bmpHeader, int x, int y) {
int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y) {
int w = bmpHeader.width;
int h = bmpHeader.height;
char padding = w % 4;
@ -838,6 +892,110 @@ int Inkplate::drawGrayscaleBitmap24(SdFile *f, struct bitmapHeader bmpHeader, in
return 1;
}
int Inkplate::drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len) {
int w = bmpHeader.width;
int h = bmpHeader.height;
uint8_t paddingBits = w % 32;
w /= 32;
uint8_t buffer[100];
s->readBytes(buffer, bmpHeader.startRAW);
int i, j;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
uint32_t pixelRow = s->read() << 24 | s->read() << 16 | s->read() << 8 | s->read();
for (int n = 0; n < 32; n++) {
drawPixel((i * 32) + n + x, h - j + y, !(pixelRow & (1ULL << (31 - n))));
}
}
if (paddingBits) {
uint32_t pixelRow = s->read() << 24 | s->read() << 16 | s->read() << 8 | s->read();
for (int n = 0; n < paddingBits; n++) {
drawPixel((i * 32) + n + x, h - j + y, !(pixelRow & (1ULL << (31 - n))));
}
}
}
return 1;
}
int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len) {
int w = bmpHeader.width;
int h = bmpHeader.height;
char padding = w % 4;
Serial.println(len);
Serial.println(bmpHeader.startRAW);
int total = len - 34;
uint8_t* buf = (uint8_t*) ps_malloc(total);
if (buf == NULL)
return 0;
long t_start = millis();
//int i, j;
//size_t read = s->read(buf, len - 34);
//for (i = 0; i < len - 34; i++)
// s->read();
int read;
int pnt = 0;
int cnk = 512;
while (pnt < total) {
if (total - pnt < cnk)
cnk = total - pnt;
read = s->read(buf+pnt, cnk);
if (read > 0) {
pnt += read;
Serial.println(" Read: " + String(read));
}
//delay(10);
}
//while (pnt < total) {
// if (total - pnt < cnk)
// cnk = total - pnt;
// s->read(buf+pnt, cnk);
// pnt += cnk;
// Serial.println(" Read: " + String(cnk));
//}
//for (j = 0; j < h; j++) {
// size_t read = s->read(buf, 64);
// Serial.println(" Read: " + String(read));
// delay(1);
//}
long t_stop = millis();
Serial.println("Time: " + String(t_stop - t_start));
int i, j, k = bmpHeader.startRAW - 34;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
uint8_t r = buf[k++];
uint8_t g = buf[k++];
uint8_t b = buf[k++];
//This is the proper way of converting True Color (24 Bit RGB) bitmap file into grayscale, but it takes waaay too much time (full size picture takes about 17s to decode!)
//float px = (0.2126 * (readByteFromSD(&file) / 255.0)) + (0.7152 * (readByteFromSD(&file) / 255.0)) + (0.0722 * (readByteFromSD(&file) / 255.0));
//px = pow(px, 1.5);
//display.drawPixel(i + x, h - j + y, (uint8_t)(px*7));
//So then, we are convertng it to grayscale using good old average and gamma correction (from LUT). With this metod, it is still slow (full size image takes 4 seconds), but much beter than prev mentioned method.
uint8_t px = (r * 2126 / 10000) + (g * 7152 / 10000) + (b * 722 / 10000);
//drawPixel(i + x, h - j + y, gammaLUT[px]);
drawPixel(i + x, h - j + y, px>>5);
//drawPixel(i + x, h - j + y, px/32);
}
if (padding) {
for (int p = 0; p < padding; p++) {
k++;
}
}
}
free(buf);
return 1;
}
void Inkplate::precalculateGamma(uint8_t* c, float gamma) {
for (int i = 0; i < 256; i++) {
c[i] = int(round((pow(i / 255.0, gamma)) * 15));

View File

@ -15,6 +15,7 @@
#include "SPI.h"
#include "Adafruit_MCP23017.h"
#include "SdFat.h"
#include "WiFiClient.h"
#define INKPLATE_GAMMA 1.45
#define E_INK_WIDTH 800
@ -132,6 +133,8 @@ class Inkplate : public Adafruit_GFX {
uint8_t getDisplayMode();
int drawBitmapFromSD(SdFile* p, int x, int y);
int drawBitmapFromSD(char* fileName, int x, int y);
int drawBitmapFromWeb(WiFiClient* s, int x, int y, int len);
int drawBitmapFromWeb(char* url, int x, int y);
int sdCardInit();
SdFat getSdFat();
SPIClass getSPI();
@ -163,9 +166,12 @@ class Inkplate : public Adafruit_GFX {
void display3b();
uint32_t read32(uint8_t* c);
uint16_t read16(uint8_t* c);
void readBmpHeader(SdFile *_f, struct bitmapHeader *_h);
int drawMonochromeBitmap(SdFile *f, struct bitmapHeader bmpHeader, int x, int y);
int drawGrayscaleBitmap24(SdFile *f, struct bitmapHeader bmpHeader, int x, int y);
void readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h);
void readBmpHeaderWeb(WiFiClient *_s, struct bitmapHeader *_h);
int drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y);
int drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y);
int drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len);
int drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len);
void precalculateGamma(uint8_t* c, float gamma);
};

View File

@ -0,0 +1,157 @@
/*
10_Inkplate_Download_And_Show example for e-radionica Inkplate6
For this example you will need a micro USB cable, Inkplate6, an SD card and an
available WiFi connection.
Select "Inkplate 6(ESP32)" from Tools -> Board menu.
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/
To work with SD card on Inkplate, you will need to add one extra library.
Download and install it from here: https://github.com/e-radionicacom/Inkplate-6-SDFat-Arduino-Library
You can open .bmp files that have color depth of 1 bit (monochrome bitmap) and
24 bit AND have resoluton smaller than 800x600 or otherwise it won't fit on screen.
This example will show you how you can download a .bmp file (picture) from the web to the SD card and
display that image on e-paper 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/
23 July 2020 by e-radionica.com
*/
#include "Inkplate.h" //Include Inkplate library to the sketch
#include "SdFat.h" //Include library for SD card
#include "WiFi.h" //Include library for WiFi
#include "HTTPClient.h" //Include library for HTTP downloading
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
const char* ssid = "Twilight Sparkle"; //Your WiFi SSID
const char* password = "thori4twily"; //Your WiFi password
//Photo taken by: Paulian Prajitura
char* url = "https://dl.thorinair.net/neowise2.bmp"; //URL of image to download
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.println("Connecting to WiFi...");
display.partialUpdate();
//Connect to the WiFi network.
WiFi.begin(ssid, password);
WiFi.setSleep(false);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
display.println("WiFi OK! Downloading...");
display.partialUpdate();
if(!display.drawBitmapFromWeb(url, 0, 0)) {
//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 or 24 bits with no compression!
display.println("Image open error");
display.display();
}
display.display();
//HTTPClient http;
//
//http.begin(url);
//
////Get the image, check if connection was successful.
//uint32_t httpCode = http.GET();
//if (httpCode == 200) {
//
// display.println("HTTP opened! Size: " + String(len) + " - Saving to SD...");
// display.partialUpdate();
//
//
//
// //String str = http.getString();
// //int str_len = http.getSize();
// //char char_array[str_len];
// //str.toCharArray(char_array, str_len);
// //http.end();
//
// SdFat sd = display.getSdFat();
// sd.remove("image.bmp");
// File image = sd.open("image.bmp", O_CREAT | O_WRITE);
// if (image) {
//
//
//
// http.writeToStream(&stream);
////
// //String body = http.getString();
////
// //for (int i = 0; i < http.getSize(); i++) {
// // //Serial.print(body[i]);
// // image.write(body[i]);
// //}
//
// //WiFiClient* stream = http.getStreamPtr();
// //while (stream->available()) {
// // uint8_t c = stream->read();
// // //Serial.print(c);
// // image.write(c);
// //}
////
// ////image.write(char_array, str_len); //Write HTTP content to file
//
// //WiFiClient * stream = http.getStreamPtr();
// //byte buffer[len];
// //stream->readBytes(buffer, len);
// //for (int i = 0; i < len; i++)
// // image.write(buffer[i]);
//
// //uint32_t pos = 0;
// //char buff[2048];
// //while (pos < len && http.available()) {
// // ESP.wdtFeed();
// // yield();
// // http.seek(pos, fs::SeekMode::SeekSet);
// // const auto read = http.readBytes(buff, sizeof(buff));
// // pos += read;
// // image.write(buff, read);
// //}
//
// image.close(); //Close the file
// display.println("Image saved!");
// display.partialUpdate();
//
// delay(1000);
//
// //Load and display the image on e-paper at position X=0, Y=0
// if(!display.drawBitmapFromSD("image.bmp", 0, 0)) {
// //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 or 24 bits with no compression!
// display.println("Image open error");
// display.display();
// }
// display.display();
// }
// else {
// //If image file was not open successfully, display error on screen
// display.println("File error!");
// display.partialUpdate();
// return;
// }
//}
//else {
// //If HTTP connection was not successful, display error on screen
// display.println("HTTP connection error!");
// display.partialUpdate();
// return;
//}
}
void loop() {
//Nothing...
}