You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
8.9 KiB
C++

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

#include <Arduino.h>
#include <SPIFFS.h>
#include "display.h"
#include "jpec.h"
#include "esp_task_wdt.h"
// mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board
// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> (18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V
GxEPD2_BW<GxEPD2_750, GxEPD2_750::HEIGHT> display(GxEPD2_750(/*CS=*/5, /*DC=*/17, /*RST=*/16, /*BUSY=*/4));
GFXcanvas1 *displayCanvas;
File tmpFileCache;
long startMills;
// bmp
void write16(File &f, uint16_t v);
void write32(File &f, uint32_t v);
uint8_t filldata3[] = {0x0, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0};
// bmp
void setupDisplay()
{
Serial.println("setupDisplay");
delay(100);
display.init(115200); // TODO
display.setRotation(0);
display.setFullWindow();
display.firstPage();
displayCanvas = new GFXcanvas1(display.width(), display.height());
Serial.println("setup done");
}
GFXcanvas1 *displayGetCanvas()
{
return displayCanvas;
}
void displayOpen()
{
displayCanvas->setRotation(0);
displayCanvas->fillScreen(GxEPD_WHITE);
}
void displayWritePixel(int16_t x, int16_t y, uint16_t color)
{
displayCanvas->drawPixel(x, y, color);
}
void displayFlush()
{
display.fillScreen(GxEPD_WHITE);
display.drawBitmap(0, 0, displayCanvas->getBuffer(), displayCanvas->width(), displayCanvas->height(), GxEPD_WHITE, GxEPD_BLACK);
display.display();
}
/*
void printSplash()
{
const char Hello[] = "Hello Paperdash!";
display.setRotation(1);
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
int16_t tbx, tby;
uint16_t tbw, tbh;
display.getTextBounds(Hello, 0, 0, &tbx, &tby, &tbw, &tbh);
// center bounding box by transposition of origin:
uint16_t x = ((display.width() - tbw) / 2) - tbx;
uint16_t y = ((display.height() - tbh) / 2) - tby;
display.setFullWindow();
display.firstPage();
do
{
display.fillScreen(GxEPD_WHITE);
display.setCursor(x, y);
display.print(Hello);
} while (display.nextPage());
}
*/
void exportJPG(GFXcanvas1 *_canvas, const char *fileName, uint8_t q)
{
Serial.println(F("exportJPG"));
long start = millis();
SPIFFS.remove(fileName);
tmpFileCache = SPIFFS.open(fileName, FILE_WRITE);
if (!tmpFileCache)
{
Serial.println("Failed to open file for writing");
return;
}
/* Create a JPEG encoder provided image data */
jpec_enc_t *e = jpec_enc_new2(_canvas->getBuffer(), _canvas->width(), _canvas->height(), q, [](int offset, uint8_t val) {
tmpFileCache.write(val);
// every 1000ms
if (startMills + 1000 < millis())
{
startMills = millis();
esp_task_wdt_reset();
}
});
/* Compress */
jpec_enc_run(e);
Serial.print(millis() - start);
Serial.println("ms");
/* Release the encoder */
jpec_enc_del(e);
tmpFileCache.close();
}
void exportBMP(GFXcanvas1 *_canvas, const char *fileName)
{
Serial.println(F("exportBMP"));
startMills = millis();
SPIFFS.remove(fileName);
tmpFileCache = SPIFFS.open(fileName, FILE_WRITE);
if (!tmpFileCache)
{
Serial.println("Failed to open file for writing");
return;
}
uint8_t *bitmap = _canvas->getBuffer();
int16_t w = _canvas->width();
int16_t h = _canvas->height();
uint16_t depth = 1;
uint32_t rowSizeCode = (w + 8 - depth) * depth / 8;
// BMP rows are padded (if needed) to 4-byte boundary
uint32_t rowSizeBMP = (w * depth / 8 + 3) & ~3;
uint32_t headerSize = 40;
uint32_t imageOffset = 62;
uint32_t fileSize = imageOffset + h * rowSizeBMP;
write16(tmpFileCache, 0x4D42); // BMP signature
write32(tmpFileCache, fileSize); // fileSize
write32(tmpFileCache, 0); // creator bytes
write32(tmpFileCache, imageOffset); // image offset
write32(tmpFileCache, headerSize); // Header size
write32(tmpFileCache, w); // image width
write32(tmpFileCache, h); // image height
write16(tmpFileCache, 1); // # planes
write16(tmpFileCache, depth); // bits per pixel
write32(tmpFileCache, 0); // format uncompressed
uint32_t j = 0;
for (uint32_t i = 34; i < imageOffset; i++)
{
tmpFileCache.write(filldata3[j++]); // remaining header bytes
}
uint32_t rowidx = w * h / 8;
for (uint16_t row = 0; row < h; row++) // for each line
{
rowidx -= rowSizeCode;
uint32_t colidx;
for (colidx = 0; colidx < rowSizeCode; colidx++)
{
uint8_t data = pgm_read_byte(&bitmap[rowidx + colidx]);
tmpFileCache.write(data);
}
while (colidx++ < rowSizeBMP)
{
tmpFileCache.write(uint8_t(0)); // padding
}
esp_task_wdt_reset();
}
Serial.print(millis() - startMills);
Serial.println("ms");
tmpFileCache.close();
}
void write16(File &f, uint16_t v)
{
f.write(uint8_t(v));
f.write(uint8_t(v >> 8));
}
void write32(File &f, uint32_t v)
{
f.write(uint8_t(v));
f.write(uint8_t(v >> 8));
f.write(uint8_t(v >> 16));
f.write(uint8_t(v >> 24));
}
uint8_t displayPixelBWRatio()
{
uint8_t *buffer = displayCanvas->getBuffer();
uint32_t pixelWhite = 0;
for (uint16_t y = 0; y < displayCanvas->height(); y++)
{
for (uint16_t x = 0; x < displayCanvas->width(); x++)
{
uint8_t *ptr = (uint8_t *)&buffer[(x / 8) + y * ((displayCanvas->width() + 7) / 8)];
// return ((*ptr) & (0x80 >> (x & 7))) != 0 ? 0xFF : 0;
pixelWhite += ((*ptr) & (0x80 >> (x & 7))) != 0 ? 1 : 0;
}
}
uint32_t pixelCount = displayCanvas->width() * displayCanvas->height();
uint8_t pixelRatio = (uint8_t)round(100.0 / pixelCount * pixelWhite);
Serial.println(100.0 / pixelCount * pixelWhite);
Serial.printf("Pixel count: %d, white pixel: %d, ratio: %d\n", pixelCount, pixelWhite, pixelRatio);
return pixelRatio;
}
void displayPrintScreenJPG(const char *fileName, uint8_t q)
{
exportJPG(displayCanvas, fileName, q);
}
void displayPrintScreenBMP(const char *fileName)
{
exportBMP(displayCanvas, fileName);
}
size_t write8(uint8_t *buffer, uint8_t v)
{
memset(buffer, uint8_t(v), sizeof(uint8_t));
return sizeof(uint8_t);
}
size_t write16(uint8_t *buffer, uint16_t v)
{
memset(buffer, uint8_t(v), sizeof(uint8_t));
memset(buffer + sizeof(uint8_t), uint8_t(v >> 8), sizeof(uint8_t));
return sizeof(uint16_t);
}
size_t write32(uint8_t *buffer, uint32_t v)
{
memset(buffer, uint8_t(v), sizeof(uint8_t));
memset(buffer + sizeof(uint8_t), uint8_t(v >> 8), sizeof(uint8_t));
memset(buffer + sizeof(uint8_t) * 2, uint8_t(v >> 16), sizeof(uint8_t));
memset(buffer + sizeof(uint8_t) * 3, uint8_t(v >> 24), sizeof(uint8_t));
return sizeof(uint32_t);
}
int displayStreamPrintScreenBMP(uint8_t *buffer, size_t maxLen, size_t index)
{
Serial.println(F("exportBMP"));
Serial.printf("maxLen: %d, index: %d\n", maxLen, index);
startMills = millis();
GFXcanvas1 *_canvas = displayCanvas;
uint8_t *bitmap = _canvas->getBuffer();
int16_t w = _canvas->width();
int16_t h = _canvas->height();
uint16_t depth = 1;
uint32_t rowSizeCode = (w + 8 - depth) * depth / 8;
// BMP rows are padded (if needed) to 4-byte boundary
uint32_t rowSizeBMP = (w * depth / 8 + 3) & ~3;
uint32_t headerSize = 40;
uint32_t imageOffset = 62;
uint32_t fileSize = imageOffset + h * rowSizeBMP;
uint32_t pointer = 0;
if (index == 0)
{
Serial.println("...header");
pointer += write16(buffer + pointer, 0x4D42); // BMP signature
pointer += write32(buffer + pointer, fileSize); // fileSize
pointer += write32(buffer + pointer, 0); // creator bytes
pointer += write32(buffer + pointer, imageOffset); // image offset
pointer += write32(buffer + pointer, headerSize); // Header size
pointer += write32(buffer + pointer, w); // image width
pointer += write32(buffer + pointer, h); // image height
pointer += write16(buffer + pointer, 1); // # planes
pointer += write16(buffer + pointer, depth); // bits per pixel
pointer += write32(buffer + pointer, 0); // format uncompressed
uint32_t j = 0;
for (uint32_t i = 34; i < imageOffset; i++)
{
pointer += write8(buffer + pointer, filldata3[j++]);
}
// Serial.println(pointer);
return pointer;
}
else
{
Serial.println("...image");
// pointer = imageOffset;
// 1 row = 80byte
// 60 rows ?
size_t maxRows = maxLen / 80;
Serial.printf("maxRows: %d\n", maxRows);
size_t row_from = (index - imageOffset) / 80;
Serial.printf("row_from: %d\n", row_from);
uint16_t row_till = row_from + maxRows > h ? h : row_from + maxRows;
Serial.printf("row_till: %d\n", row_till);
uint32_t rowidx = w * h / 8;
// set offset
rowidx -= rowSizeCode * row_from;
for (uint16_t row = row_from; row < row_till; row++) // for each line
//for (uint16_t row = 0; row < h; row++) // for each line | 384
{
rowidx -= rowSizeCode;
uint32_t colidx;
for (colidx = 0; colidx < rowSizeCode; colidx++)
{
uint8_t data = pgm_read_byte(&bitmap[rowidx + colidx]);
pointer += write8(buffer + pointer, data);
}
/*
while (colidx++ < rowSizeBMP)
{
Serial.println(".");
pointer += write8(buffer + pointer, uint8_t(0));
}
*/
esp_task_wdt_reset();
}
return pointer;
}
Serial.print(millis() - startMills);
Serial.println("ms");
return 0;
}