Skip to content

Commit

Permalink
feat: implement inline canvas compression during drawing
Browse files Browse the repository at this point in the history
implement compressing and storing the canvas in memory (partially) to reduce time taken by readPixel calls in CanvasClient::saveCanvas method

Signed-off-by: Aditya Agarwal <[email protected]>
  • Loading branch information
Aditya-A-garwal committed Feb 16, 2024
1 parent e832c57 commit f8c3e34
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 14 deletions.
6 changes: 3 additions & 3 deletions include/canvasClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class RowCompressor {

class CanvasClient {

constexpr static unsigned CLIENT_BUFFER_LEN = 2048;
constexpr static unsigned CLIENT_BUFFER_LEN = 4096;
constexpr static unsigned ROW_BUFFER_LEN = 512;

constexpr static unsigned MAX_SSID_LEN = 64;
Expand Down Expand Up @@ -116,8 +116,8 @@ class CanvasClient {
ConnectionStatus connect(uint16_t maxAttempt);
void disconnect();

void loadCanvas(uint8_t id);
void saveCanvas(uint8_t id);
void loadCanvas(uint8_t id, CompressedCanvas *compressed);
void saveCanvas(uint8_t id, CompressedCanvas *compressed);

private:

Expand Down
3 changes: 3 additions & 0 deletions include/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,7 @@ const uint16_t SLOT_MENU_Y = COLOR_SELECTOR_Y - 8;
const uint16_t SLOT_MENU_W = SAVE_W * 3;
const uint16_t SLOT_MENU_H = SAVE_H * 4;

constexpr unsigned CANVAS_BUFFER_W = 32;
constexpr unsigned CANVAS_BUFFER_H = 32;

#endif
22 changes: 16 additions & 6 deletions src/canvasClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ bool RowCompressor::compress(uint8_t *codes, uint16_t count) {

for (unsigned l = 0, r; l < count; l = r) {
for (r = l; r <= count; ++r) {
if (r == count || codes[l] != codes[r]) {
break;
if (r == count || codes[l] != codes[r]) {
break;
}
}

Expand Down Expand Up @@ -84,7 +84,7 @@ void CanvasClient::disconnect() {
WiFi.end();
}

void CanvasClient::loadCanvas(uint8_t id) {
void CanvasClient::loadCanvas(uint8_t id, CompressedCanvas *compressed) {

if (!client.connect(IPAddress(serverIP), serverPort)) {
Serial.println("Connection Failed");
Expand Down Expand Up @@ -120,13 +120,19 @@ void CanvasClient::loadCanvas(uint8_t id) {
for (uint16_t j = 0; j < imageWidth; ++j) {
canvas->writePixel(row + 1, j + 1, rowbuf.color[j]);
}

for (uint16_t j = 0; j < imageWidth; ++j) {
rowbuf.code[j] = color2code(rowbuf.color[j]); //! this is very risky code
}

compressed[row].compress(rowbuf.code, imageWidth); //! this code can be optimized
}

while (client.connected()) {}
client.stop();
}

void CanvasClient::saveCanvas(uint8_t id) {
void CanvasClient::saveCanvas(uint8_t id, CompressedCanvas *compressed) {

uint16_t imageHeight = canvas->height() - 2;
uint16_t imageWidth = canvas->width() - 2;
Expand Down Expand Up @@ -165,8 +171,12 @@ void CanvasClient::saveCanvas(uint8_t id) {
for (uint16_t i = 0; i < imageHeight; ++i) {

x = micros();
for (unsigned j = 0; j < imageWidth; ++j) {
rowbuf.code[j] = color2code(canvas->readPixel(i + 1, j + 1));

// see if this row can be uncompressed right now
if (!compressed[i].uncompress(rowbuf.code)) {
for (unsigned j = 0; j < imageWidth; ++j) {
rowbuf.code[j] = color2code(canvas->readPixel(i + 1, j + 1));
}
}
readTime += micros() - x;

Expand Down
61 changes: 56 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ Button infoButton(INFO_X, INFO_Y, INFO_W, INFO_H, INFO_C, "INFO", &tft);

CanvasClient client(&canvas);

void executeSlotSelection(CanvasClient *client, void (CanvasClient::*method)(uint8_t));
GFXcanvas1 canvasBuffer(CANVAS_BUFFER_W, CANVAS_BUFFER_H);

CompressedCanvas compressed[CANVAS_H - 2];
uint8_t rawCode[CANVAS_W - 2] {};

void clearCompressedCanvas();

void executeSlotSelection(CanvasClient *client, void (CanvasClient::*method)(uint8_t, CompressedCanvas *));
void drawLowerWidgets();

void setup(void) {
Expand All @@ -55,15 +62,49 @@ void setup(void) {
logo.draw();
canvas.draw();
drawLowerWidgets();

clearCompressedCanvas();
}

void loop(void) {

uint16_t x, y;
unsigned canvasUpdateTime = 0;
getTouchCoors(&x, &y);

// update each widget
canvas.update(x, y, thicknessSelector.getThickness(), colorSelector.getColor());
canvasUpdateTime = micros();
if (canvas.update(x, y, thicknessSelector.getThickness(), colorSelector.getColor())) {

const uint16_t cx = x - CANVAS_X - 1;
const uint16_t cy = y - CANVAS_Y - 1;

const uint16_t thickness = thicknessSelector.getThickness();
const uint16_t color = colorSelector.getColor();
const uint8_t code = color2code(color);

const uint16_t row_origin = cy - thickness;
const uint16_t col_origin = cx - thickness;

canvasBuffer.fillCircle(thickness, thickness, thickness, 1);

for (unsigned i = 0; i <= thickness*2; ++i) {

if (!compressed[i + row_origin].uncompress(rawCode)) { //! it is possible for only a prefix to be compressed, dont ignore that case
continue;
}

for (unsigned j = 0; j <= thickness*2; ++j) {

if (canvasBuffer.getPixel(j, i)) {
rawCode[j + col_origin] = code;
}
}

compressed[i + row_origin].compress(rawCode, CANVAS_W - 2);
}
}
canvasUpdateTime = (micros() - canvasUpdateTime) / 1000;

if (colorSelector.update(x, y)) {

Expand Down Expand Up @@ -117,21 +158,31 @@ void loop(void) {

if (clearButton.update(x, y)) {
canvas.clear();
clearCompressedCanvas();
}

if (infoButton.update(x, y)) {

}

delay(2);
if (canvasUpdateTime < 5) {
delay(5 - canvasUpdateTime);
}
}

void clearCompressedCanvas() {
memset(rawCode, 8, sizeof(rawCode));
for (unsigned i = 0; i < CANVAS_H-2; ++i) {
compressed[i].compress(rawCode, CANVAS_W-2);
}
}

void executeSlotSelection(CanvasClient *client, void (CanvasClient::*method)(uint8_t)) {
void executeSlotSelection(CanvasClient *client, void (CanvasClient::*method)(uint8_t, CompressedCanvas *)) {

uint8_t selectedSlot = slotSelector.getSlot();

if (selectedSlot != 0) {
(client->*method)(selectedSlot);
(client->*method)(selectedSlot, compressed);
}

slotSelector.clear();
Expand Down

0 comments on commit f8c3e34

Please sign in to comment.