Few new fixes.

This commit is contained in:
nitko12 2020-09-07 15:34:51 +02:00
parent 5d94d15672
commit 6fd572b52f
12 changed files with 666 additions and 407 deletions

View File

@ -12,9 +12,6 @@
#include "include/defines.h" #include "include/defines.h"
static void ckvClock();
static void usleep1();
class Inkplate : public System, public GFX class Inkplate : public System, public GFX
{ {
public: public:

View File

@ -9,7 +9,7 @@
#define GREEN(a) ((((a)&0x07e0) >> 5) << 2) #define GREEN(a) ((((a)&0x07e0) >> 5) << 2)
#define BLUE(a) (((a)&0x001f) << 3) #define BLUE(a) (((a)&0x001f) << 3)
static Image *_imagePtrJpeg = nullptr; Image *_imagePtrJpeg = nullptr;
Image::Image() Image::Image()
{ {
@ -193,147 +193,7 @@ uint8_t Image::ditherSwap(int w)
ditherBuffer[0][i] = ditherBuffer[1][i]; ditherBuffer[0][i] = ditherBuffer[1][i];
} }
bool Image::drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) 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)
{
int w = bmpHeader.width;
int h = bmpHeader.height;
uint8_t paddingBits = w % 32;
int total = len - 34;
w /= 32;
uint8_t *buf = (uint8_t *)ps_malloc(total);
if (buf == NULL)
return 0;
int pnt = 0;
while (pnt < total)
{
int toread = s->available();
if (toread > 0)
{
int read = s->read(buf + pnt, toread);
if (read > 0)
pnt += read;
}
}
int i, j, k = bmpHeader.startRAW - 34;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++];
if (invert)
pixelRow = ~pixelRow;
for (int n = 0; n < 32; n++)
{
drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n))));
}
}
if (paddingBits)
{
uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++];
if (invert)
pixelRow = ~pixelRow;
for (int n = 0; n < paddingBits; n++)
{
drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n))));
}
}
}
free(buf);
return 1;
}
bool Image::drawJpegFromSD(SdFile *p, int x, int y, bool dither, bool invert)
{
uint8_t ret = 0;
TJpgDec.setJpgScale(1);
TJpgDec.setCallback(drawJpegChunk);
uint32_t pnt = 0;
uint32_t total = p->fileSize();
uint8_t *buf = (uint8_t *)ps_malloc(total);
if (buf == NULL)
return 0;
while (pnt < total)
{
uint32_t toread = p->available();
if (toread > 0)
{
int read = p->read(buf + pnt, toread);
if (read > 0)
pnt += read;
}
}
p->close();
selectDisplayMode(INKPLATE_3BIT);
if (TJpgDec.drawJpg(x, y, buf, total, dither, invert) == 0)
ret = 1;
free(buf);
return ret;
}
bool Image::drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool _dither, bool _invert)
{
if (!_imagePtrJpeg)
return 0;
int i, j;
for (j = 0; j < h; ++j)
{
for (i = 0; i < w; ++i)
{
uint16_t rgb = bitmap[j * w + i];
if (_invert)
rgb = ~rgb;
uint8_t px = (RED(rgb) * 2126 / 10000) + (GREEN(rgb) * 7152 / 10000) + (BLUE(rgb) * 722 / 10000);
_imagePtrJpeg->drawPixel(i + x, j + y, px >> 5);
}
}
return 1;
}
bool Image::drawJpegFromSD(const char *fileName, int x, int y, bool dither, bool invert)
{
SdFile dat;
if (dat.open(fileName, O_RDONLY))
return drawJpegFromSD(&dat, x, y, dither, invert);
return 0;
}
void Image::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h)
{
if (getDisplayMode() != INKPLATE_3BIT)
return;
uint8_t _rem = _w % 2;
int i, j;
int xSize = _w / 2 + _rem;
for (i = 0; i < _h; i++)
{
for (j = 0; j < xSize - 1; j++)
{
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1);
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1);
}
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1);
if (_rem == 0)
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1);
}
}
// FUTURE COMPATIBILITY FUNCTIONS; DO NOT USE!
void Image::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
{ {
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0; uint8_t byte = 0;
@ -357,6 +217,30 @@ void Image::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t
endWrite(); endWrite();
} }
void Image::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h)
{
if (getDisplayMode() != INKPLATE_3BIT)
return;
uint8_t _rem = _w & 1;
int i, j;
int xSize = (_w >> 1) + _rem;
startWrite();
for (i = 0; i < _h; i++)
{
for (j = 0; j < xSize - 1; j++)
{
writePixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1);
writePixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1);
}
writePixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1);
if (_rem == 0)
writePixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1);
}
endWrite();
}
// FUTURE COMPATIBILITY FUNCTIONS; DO NOT USE!
void Image::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h) void Image::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h)
{ {
startWrite(); startWrite();

View File

@ -3,6 +3,7 @@
#include "../libs/SdFat/SdFat.h" #include "../libs/SdFat/SdFat.h"
#include "Arduino.h" #include "Arduino.h"
#include "Network.h"
#include "WiFiClient.h" #include "WiFiClient.h"
#include "defines.h" #include "defines.h"
@ -18,7 +19,7 @@ struct bitmapHeader
uint32_t compression; uint32_t compression;
}; };
class Image class Image : Network
{ {
public: public:
Image(); Image();
@ -35,7 +36,8 @@ class Image
bool drawImage(const SdFile *path, int x, int y, bool dither = 1, bool invert = 0); bool drawImage(const SdFile *path, int x, int y, bool dither = 1, bool invert = 0);
bool drawImage(const WiFiClient *s, int x, int y, int len = -1, bool dither = 1, bool invert = 0); bool drawImage(const WiFiClient *s, int x, int y, int len = -1, bool dither = 1, bool invert = 0);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg = 0xFFFF); void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color,
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);
@ -75,8 +77,10 @@ class Image
uint32_t read32(uint8_t *c); uint32_t read32(uint8_t *c);
uint16_t read16(uint8_t *c); uint16_t read16(uint8_t *c);
void readBmpHeader(uint8_t *buf, bitmapHeader *_h);
void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h); void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h);
inline void displayBmpLine(int16_t x, int16_t y, SdFile *f, bitmapHeader *bmpHeader, bool dither, bool invert);
inline void displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool dither, bool invert);
bool drawMonochromeBitmapWeb(WiFiClient *s, bitmapHeader bmpHeader, int x, int y, int len, bool invert); bool drawMonochromeBitmapWeb(WiFiClient *s, bitmapHeader bmpHeader, int x, int y, int len, bool invert);
bool drawGrayscaleBitmap4Web(WiFiClient *s, bitmapHeader bmpHeader, int x, int y, int len, bool dither, bool drawGrayscaleBitmap4Web(WiFiClient *s, bitmapHeader bmpHeader, int x, int y, int len, bool dither,

View File

@ -1,8 +1,11 @@
#include "Image.h" #include "Image.h"
#define RGB3BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 13)
void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h) void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
{ {
uint8_t header[100]; uint8_t header[100];
_f->rewind(); _f->rewind();
_f->read(header, 100); _f->read(header, 100);
_h->signature = read16(header + 0); _h->signature = read16(header + 0);
@ -32,32 +35,50 @@ void Image::readBmpHeaderSd(SdFile *_f, bitmapHeader *_h)
{ {
uint32_t c = read32(paletteRGB + (i << 2)); uint32_t c = read32(paletteRGB + (i << 2));
Serial.println(c, 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);
}
}
}
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);
uint32_t totalColors = read32(buf + 46);
uint8_t paletteRGB[1024];
if (_h->color <= 8)
{
if (!totalColors)
totalColors = (1ULL << _h->color);
memcpy(paletteRGB, buf + 53, totalColors * 4);
memset(pallete, 0, sizeof pallete);
for (int i = 0; i < totalColors; ++i)
{
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;
uint8_t a = (c & 0x000000FF);
Serial.println(b, 2); pallete[i >> 1] |= RGB3BIT(r, g, b) << (i & 1 ? 0 : 4);
Serial.println(g, 2);
Serial.println(r, 2);
Serial.println(a, 2);
pallete[i >> 1] |= ((54UL * r + 183UL * g + 19UL * b) >> 13) << (i & 1 ? 0 : 4);
} }
} }
};
for (int i = 0; i < totalColors / 2; ++i)
{
Serial.println(pallete[i] >> 8);
Serial.println(pallete[i] & 0xF);
}
Serial.println();
return;
}
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)
{ {
@ -87,28 +108,27 @@ bool Image::drawBitmapFromSD(SdFile *p, int x, int y, bool dither, bool invert)
selectDisplayMode(INKPLATE_3BIT); selectDisplayMode(INKPLATE_3BIT);
int16_t w = bmpHeader.width, h = bmpHeader.height; int16_t w = bmpHeader.width, h = bmpHeader.height;
int8_t c = bmpHeader.color;
p->seekSet(bmpHeader.startRAW); p->seekSet(bmpHeader.startRAW);
if (bmpHeader.color == 1)
Serial.println("nice");
for (int i = 0; i < h; ++i) for (int i = 0; i < h; ++i)
displayBmpLine(x, y + i, p, &bmpHeader, dither, invert); {
int16_t rowSize = (((int16_t)c * w + 31) >> 5) << 2;
p->read(pixelBuffer, rowSize);
displayBmpLine(x, y + i, &bmpHeader, dither, invert);
}
return 1; return 1;
} }
void Image::displayBmpLine(int16_t x, int16_t y, SdFile *f, bitmapHeader *bmpHeader, bool dither, bool invert) void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool dither, bool invert)
{ {
int16_t w = bmpHeader->width, h = bmpHeader->height; int16_t w = bmpHeader->width, h = bmpHeader->height;
int8_t c = bmpHeader->color; int8_t c = bmpHeader->color;
int16_t rowSize = (((int16_t)c * w + 31) >> 5) << 2;
startWrite(); startWrite();
f->read(pixelBuffer, rowSize);
for (int j = 0; j < w; ++j) for (int j = 0; j < w; ++j)
{ {
switch (c) switch (c)
@ -142,9 +162,9 @@ void Image::displayBmpLine(int16_t x, int16_t y, SdFile *f, bitmapHeader *bmpHea
uint8_t b = (px & 0x1F) << 3; uint8_t b = (px & 0x1F) << 3;
if (invert) if (invert)
writePixel(x + j, y, 7 - ((54UL * r + 183UL * g + 19UL * b) >> 13)); writePixel(x + j, y, 7 - RGB3BIT(r, g, b));
else else
writePixel(x + j, y, (54UL * r + 183UL * b + 19UL * g) >> 13); writePixel(x + j, y, RGB3BIT(r, g, b));
break; break;
} }
case 24: { case 24: {
@ -153,9 +173,9 @@ void Image::displayBmpLine(int16_t x, int16_t y, SdFile *f, bitmapHeader *bmpHea
uint8_t b = pixelBuffer[j * 3 + 2]; uint8_t b = pixelBuffer[j * 3 + 2];
if (invert) if (invert)
writePixel(x + j, y, 7 - ((54UL * r + 183UL * g + 19UL * b) >> 13)); writePixel(x + j, y, 7 - RGB3BIT(r, g, b));
else else
writePixel(x + j, y, (54UL * r + 183UL * b + 19UL * g) >> 13); writePixel(x + j, y, RGB3BIT(r, g, b));
break; break;
} }
case 32: case 32:
@ -164,9 +184,9 @@ void Image::displayBmpLine(int16_t x, int16_t y, SdFile *f, bitmapHeader *bmpHea
uint8_t b = pixelBuffer[j * 4 + 2]; uint8_t b = pixelBuffer[j * 4 + 2];
if (invert) if (invert)
writePixel(x + j, y, 7 - ((54UL * r + 183UL * g + 19UL * b) >> 13)); writePixel(x + j, y, 7 - RGB3BIT(r, g, b));
else else
writePixel(x + j, y, (54UL * r + 183UL * b + 19UL * g) >> 13); writePixel(x + j, y, RGB3BIT(r, g, b));
break; break;
} }
} }
@ -174,240 +194,110 @@ void Image::displayBmpLine(int16_t x, int16_t y, SdFile *f, bitmapHeader *bmpHea
endWrite(); endWrite();
} }
// bool Image::drawMonochromeBitmapSd(SdFile *f, bitmapHeader bmpHeader, int x, int y, bool invert) bool Image::drawBitmapFromWeb(const char *url, int x, int y, bool dither, bool invert)
// { {
// int w = bmpHeader.width; uint8_t *buf = (uint8_t *)ps_malloc(800 * 600 * 4 + 100); // TODO: allocate as mush as used
// int h = bmpHeader.height; downloadFile(buf, url);
// uint8_t paddingBits = w % 32;
// w /= 32;
struct bitmapHeader bmpHeader;
// int i, j; readBmpHeader(buf, &bmpHeader);
// for (j = 0; j < h; j++)
// {
// uint8_t *bufferPtr = pixelBuffer;
// for (i = 0; i < w; i++) uint8_t *bufferPtr = buf + bmpHeader.startRAW;
// { for (int i = 0; i < bmpHeader.height; ++i)
// uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++); {
// if (invert) memcpy(pixelBuffer, bufferPtr, bmpHeader.width);
// pixelRow = ~pixelRow; displayBmpLine(x, y + i, &bmpHeader, dither, invert);
// for (int n = 0; n < 32; n++) bufferPtr += bmpHeader.width;
// { }
// drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n))));
// }
// }
// if (paddingBits)
// {
// uint32_t pixelRow = f->read() << 24 | f->read() << 16 | f->read() << 8 | f->read();
// if (invert)
// pixelRow = ~pixelRow;
// for (int n = 0; n < paddingBits; n++)
// {
// drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n))));
// }
// }
// }
// f->close();
// return 1;
// }
// bool Image::drawGrayscaleBitmap4Sd(SdFile *f, bitmapHeader bmpHeader, int x, int y, bool dither, bool invert) return 1;
// { }
// int w = bmpHeader.width;
// int h = bmpHeader.height;
// uint8_t paddingBits = w % 8;
// w /= 8;
// f->seekSet(bmpHeader.startRAW); bool Image::drawBitmapFromWeb(WiFiClient *s, int x, int y, int len, bool dither, bool invert)
// int i, j; {
struct bitmapHeader bmpHeader;
// readBmpHeaderWeb(s, &bmpHeader);
// uint8_t *bufferPtr; if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 ||
!(bmpHeader.color == 1 || bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 16 ||
bmpHeader.color == 24))
return 0;
// if (dither) if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 16 || bmpHeader.color == 24 ||
// { bmpHeader.color == 32) &&
// bufferPtr = pixelBuffer; getDisplayMode() != INKPLATE_3BIT)
// f->read(pixelBuffer, w * 4 + (paddingBits ? 4 : 0)); {
selectDisplayMode(INKPLATE_3BIT);
}
// ditherStart(pixelBuffer, bufferPtr, w * 8 + (paddingBits ? 4 : 0), invert, 4); if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT)
// } {
selectDisplayMode(INKPLATE_1BIT);
}
// for (j = 0; j < h; j++) if (bmpHeader.color == 1)
// { drawMonochromeBitmapWeb(s, bmpHeader, x, y, len, invert);
// bufferPtr = pixelBuffer; if (bmpHeader.color == 4)
// f->read(pixelBuffer, w * 4 + (paddingBits ? 4 : 0)); drawGrayscaleBitmap4Web(s, bmpHeader, x, y, len, dither, invert);
if (bmpHeader.color == 8)
drawGrayscaleBitmap8Web(s, bmpHeader, x, y, len, dither, invert);
if (bmpHeader.color == 24)
drawGrayscaleBitmap24Web(s, bmpHeader, x, y, len, dither, invert);
// if (dither && j != h - 1) return 1;
// { }
// ditherLoadNextLine(pixelBuffer, bufferPtr, w * 8 + (paddingBits ? 4 : 0), invert, 4);
// }
// for (i = 0; i < w; i++) bool Image::drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert)
// { {
// if (dither) int w = bmpHeader.width;
// { int h = bmpHeader.height;
uint8_t paddingBits = w % 32;
int total = len - 34;
w /= 32;
// for (int n = 0; n < 8; n++) uint8_t *buf = (uint8_t *)ps_malloc(total);
// { if (buf == NULL)
// drawPixel((i * 8) + n + x, h - 1 - j + y, return 0;
// ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits ? 4 : 0), h) >> 5);
// }
// }
// else
// {
// uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 |
// *(bufferPtr++); if (invert)
// pixelRow = ~pixelRow;
// for (int n = 0; n < 8; n++)
// {
// drawPixel((i * 8) + n + x, h - 1 - j + y,
// (pixelRow & (0xFULL << (28 - n * 4))) >> (28 - n * 4 + 1));
// }
// }
// }
// if (paddingBits)
// {
// if (dither)
// {
// for (int n = 0; n < paddingBits; n++)
// {
// drawPixel((i * 8) + n + x, h - 1 - j + y,
// ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits ? 4 : 0), h) >> 5);
// }
// }
// else
// {
// uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 |
// *(bufferPtr++); if (invert)
// pixelRow = ~pixelRow;
// for (int n = 0; n < paddingBits; n++)
// {
// drawPixel((i * 8) + n + x, h - 1 - j + y,
// ((pixelRow & (0xFULL << (28 - n * 4)))) >> (28 - n * 4 + 1));
// }
// }
// }
// if (dither)
// ditherSwap(w * 8 + paddingBits);
// }
// f->close();
// return 1;
// }
// bool Image::drawGrayscaleBitmap8Sd(SdFile *f, bitmapHeader bmpHeader, int x, int y, bool dither, bool invert) int pnt = 0;
// { while (pnt < total)
// int w = bmpHeader.width; {
// int h = bmpHeader.height; int toread = s->available();
// char padding = w & 3; if (toread > 0)
// f->seekSet(bmpHeader.startRAW); {
// int i, j; int read = s->read(buf + pnt, toread);
if (read > 0)
pnt += read;
}
}
// uint8_t *bufferPtr; int i, j, k = bmpHeader.startRAW - 34;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++];
if (invert)
pixelRow = ~pixelRow;
for (int n = 0; n < 32; n++)
{
drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n))));
}
}
if (paddingBits)
{
uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++];
if (invert)
pixelRow = ~pixelRow;
for (int n = 0; n < paddingBits; n++)
{
drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n))));
}
}
}
// if (dither) free(buf);
// {
// bufferPtr = pixelBuffer;
// f->read(pixelBuffer, w);
// ditherStart(pixelBuffer, bufferPtr, w, invert, 8); return 1;
// } }
// for (j = 0; j < h; j++)
// {
// bufferPtr = pixelBuffer;
// f->read(pixelBuffer, w);
// if (dither && j != h - 1)
// {
// ditherLoadNextLine(pixelBuffer, bufferPtr, w, invert, 8);
// }
// for (i = 0; i < w; i++)
// {
// if (dither)
// drawPixel(i + x, h - 1 - j + y, ditherGetPixel(i, j, w, h) >> 5);
// else
// {
// uint8_t px = 0;
// if (invert)
// px = 255 - *(bufferPtr++);
// else
// px = *(bufferPtr++);
// drawPixel(i + x, h - 1 - j + y, px >> 5);
// }
// }
// }
// if (dither)
// ditherSwap(w);
// if (padding)
// {
// for (int p = 0; p < 4 - padding; p++)
// {
// f->read();
// }
// }
// f->close();
// return 1;
// }
// bool Image::drawGrayscaleBitmap24Sd(SdFile *f, bitmapHeader bmpHeader, int x, int y, bool dither, bool invert)
// {
// int w = bmpHeader.width;
// int h = bmpHeader.height;
// char padding = w & 3;
// f->seekSet(bmpHeader.startRAW);
// int i, j;
// uint8_t *bufferPtr;
// if (dither)
// {
// bufferPtr = pixelBuffer;
// f->read(pixelBuffer, w * 3);
// ditherStart(pixelBuffer, bufferPtr, w, invert, 24);
// }
// for (j = 0; j < h; j++)
// {
// bufferPtr = pixelBuffer;
// f->read(pixelBuffer, w * 3);
// if (dither && j != h - 1)
// {
// ditherLoadNextLine(pixelBuffer, bufferPtr, w, invert, 24);
// }
// for (i = 0; i < w; i++)
// {
// if (dither)
// drawPixel(i + x, h - 1 - j + y, ditherGetPixel(i, j, w, h) >> 5);
// else
// {
// uint8_t px = 0;
// if (invert)
// px = ((255 - *(bufferPtr++)) * 2126 / 10000) + ((255 - *(bufferPtr++)) * 7152 / 10000) +
// ((255 - *(bufferPtr++)) * 722 / 10000);
// else
// px = (*(bufferPtr++) * 2126 / 10000) + (*(bufferPtr++) * 7152 / 10000) +
// (*(bufferPtr++) * 722 / 10000);
// drawPixel(i + x, h - 1 - j + y, px >> 5);
// }
// }
// if (dither)
// ditherSwap(w);
// if (padding)
// {
// for (int p = 0; p < padding; p++)
// {
// f->read();
// }
// }
// }
// f->close();
// return 1;
// }

View File

@ -1,5 +1,77 @@
#include "Image.h" #include "Image.h"
#include "../libs/TJpeg/TJpg_Decoder.h"
#define RED(a) ((((a)&0xf800) >> 11) << 3) #define RED(a) ((((a)&0xf800) >> 11) << 3)
#define GREEN(a) ((((a)&0x07e0) >> 5) << 2) #define GREEN(a) ((((a)&0x07e0) >> 5) << 2)
#define BLUE(a) (((a)&0x001f) << 3) #define BLUE(a) (((a)&0x001f) << 3)
#define RGB3BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 13)
extern Image *_imagePtrJpeg;
bool Image::drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool _dither, bool _invert)
{
if (!_imagePtrJpeg)
return 0;
_imagePtrJpeg->startWrite();
for (int j = 0; j < h; ++j)
{
for (int i = 0; i < w; ++i)
{
uint16_t rgb = bitmap[j * w + i];
if (_invert)
_imagePtrJpeg->drawPixel(i + x, j + y, 7 - RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb)));
else
_imagePtrJpeg->drawPixel(i + x, j + y, RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb)));
}
}
_imagePtrJpeg->endWrite();
return 1;
}
bool Image::drawJpegFromSD(const char *fileName, int x, int y, bool dither, bool invert)
{
SdFile dat;
if (dat.open(fileName, O_RDONLY))
return drawJpegFromSD(&dat, x, y, dither, invert);
return 0;
}
bool Image::drawJpegFromSD(SdFile *p, int x, int y, bool dither, bool invert)
{
uint8_t ret = 0;
TJpgDec.setJpgScale(1);
TJpgDec.setCallback(drawJpegChunk);
uint32_t pnt = 0;
uint32_t total = p->fileSize();
uint8_t *buf = (uint8_t *)ps_malloc(total);
if (buf == NULL)
return 0;
while (pnt < total)
{
uint32_t toread = p->available();
if (toread > 0)
{
int read = p->read(buf + pnt, toread);
if (read > 0)
pnt += read;
}
}
p->close();
selectDisplayMode(INKPLATE_3BIT);
if (TJpgDec.drawJpg(x, y, buf, total, dither, invert) == 0)
ret = 1;
free(buf);
return ret;
}

View File

@ -1 +1,76 @@
#include "Network.h" #include "Network.h"
bool Network::joinAP(char *ssid, char *pass)
{
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(ssid, pass);
int cnt = 0;
while (!isConnected())
{
if (cnt > 15)
return 0;
delay(1000);
++cnt;
}
return 1;
}
void Network::disconnect()
{
WiFi.mode(WIFI_OFF);
}
bool Network::isConnected()
{
return WiFi.status() == WL_CONNECTED;
}
bool Network::downloadFile(uint8_t *buffer, const char *url)
{
if (!isConnected())
return 0;
int ret = 0;
uint8_t *bufferPtr = buffer;
bool sleep = WiFi.getSleep();
WiFi.setSleep(false);
HTTPClient http;
http.getStream().setNoDelay(true);
http.getStream().setTimeout(1);
http.begin(url);
int httpCode = http.GET();
if (httpCode == 200)
{
int total = http.getSize();
int len = total;
uint8_t buff[128] = {0};
WiFiClient *stream = http.getStreamPtr();
while (http.connected() && (len > 0 || len == -1))
{
size_t size = stream->available();
if (size)
{
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
memcpy(bufferPtr, buff, c);
bufferPtr += c;
if (len > 0)
len -= c;
}
yield();
}
}
http.end();
WiFi.setSleep(sleep);
return ret;
}

View File

@ -8,7 +8,13 @@
class Network class Network
{ {
public: public:
private: bool joinAP(char *ssid, char *pass);
void disconnect();
bool isConnected();
bool downloadFile(uint8_t *buffer, const char *url);
private:
}; };
#endif #endif

View File

@ -16,14 +16,14 @@
void Shapes::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) void Shapes::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
{ {
startWrite(); startWrite();
writeFastHLine(x, y, h, color); writeFastVLine(x, y, h, color);
endWrite(); endWrite();
} }
void Shapes::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) void Shapes::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
{ {
startWrite(); startWrite();
writeLine(x, y, x + w - 1, y, color); writeFastHLine(x, y, w, color);
endWrite(); endWrite();
} }
@ -327,3 +327,151 @@ void Shapes::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_
} }
endWrite(); endWrite();
} }
void Shapes::drawElipse(int rx, int ry, int xc, int yc, int c)
{
float dx, dy, d1, d2, x, y;
x = 0;
y = ry;
d1 = (ry * ry) - (rx * rx * ry) + (0.25 * rx * rx);
dx = 2 * ry * ry * x;
dy = 2 * rx * rx * y;
while (dx < dy)
{
drawPixel(x + xc, y + yc, c);
drawPixel(-x + xc, y + yc, c);
drawPixel(x + xc, -y + yc, c);
drawPixel(-x + xc, -y + yc, c);
if (d1 < 0)
{
x++;
dx = dx + (2 * ry * ry);
d1 = d1 + dx + (ry * ry);
}
else
{
x++;
y--;
dx = dx + (2 * ry * ry);
dy = dy - (2 * rx * rx);
d1 = d1 + dx - dy + (ry * ry);
}
}
d2 = ((ry * ry) * ((x + 0.5) * (x + 0.5))) + ((rx * rx) * ((y - 1) * (y - 1))) - (rx * rx * ry * ry);
while (y >= 0)
{
drawPixel(x + xc, y + yc, c);
drawPixel(-x + xc, y + yc, c);
drawPixel(x + xc, -y + yc, c);
drawPixel(-x + xc, -y + yc, c);
if (d2 > 0)
{
y--;
dy = dy - (2 * rx * rx);
d2 = d2 + (rx * rx) - dy;
}
else
{
y--;
x++;
dx = dx + (2 * ry * ry);
dy = dy - (2 * rx * rx);
d2 = d2 + dx - dy + (rx * rx);
}
}
}
void Shapes::fillElipse(int rx, int ry, int xc, int yc, int c)
{
int hh = ry * ry;
int ww = rx * rx;
int hhww = hh * ww;
int x0 = rx;
int dx = 0;
for (int x = -rx; x <= rx; x++)
drawPixel(xc + x, yc, c);
for (int y = 1; y <= ry; y++)
{
int x1 = x0 - (dx - 1);
for (; x1 > 0; x1--)
if (x1 * x1 * hh + y * y * ww <= hhww)
break;
dx = x0 - x1;
x0 = x1;
for (int x = -x0; x <= x0; x++)
{
drawPixel(xc + x, yc - y, c);
drawPixel(xc + x, yc + y, c);
}
}
}
void Shapes::fillPolygon(int *x, int *y, int n, int color)
{
int tx[100], ty[100];
triangulate.triangulate(x, y, n, tx, ty);
for (int i = 0; i < n - 2; ++i)
{
fillTriangle(tx[i * 3 + 0], ty[i * 3 + 0], tx[i * 3 + 1], ty[i * 3 + 1], tx[i * 3 + 2], ty[i * 3 + 2], color);
}
}
void Shapes::drawPolygon(int *x, int *y, int n, int color)
{
for (int i = 0; i < n; ++i)
drawLine(x[i], y[i], x[(i + 1) % n], y[(i + 1) % n], color);
}
void Shapes::drawThickLine(int x1, int y1, int x2, int y2, int color, float thickness)
{
float deg = atan2f((float)(y2 - y1), (float)(x2 - x1));
float l1 = tan(deg);
float k1 = (float)y1 - l1 * (float)x1;
float degShift = (l1 < 0 ? M_PI_2 : -M_PI_2);
int x3 = (int)round((float)x1 + thickness / 2.0 * cos(deg + degShift));
int y3 = (int)round((float)y1 + thickness / 2.0 * sin(deg + degShift));
int x4 = (int)round((float)x2 + thickness / 2.0 * cos(deg + degShift));
int y4 = (int)round((float)y2 + thickness / 2.0 * sin(deg + degShift));
x1 = (int)round((float)x1 + thickness / 2.0 * cos(deg - degShift));
y1 = (int)round((float)y1 + thickness / 2.0 * sin(deg - degShift));
x2 = (int)round((float)x2 + thickness / 2.0 * cos(deg - degShift));
y2 = (int)round((float)y2 + thickness / 2.0 * sin(deg - degShift));
fillTriangle(x1, y1, x2, y2, x3, y3, color);
fillTriangle(x2, y2, x4, y4, x3, y3, color);
}
void Shapes::drawGradientLine(int x1, int y1, int x2, int y2, int color1, int color2, float thickness)
{
int n = color2 - color1;
float px = (float)(x2 - x1) / (float)n;
float py = (float)(y2 - y1) / (float)n;
for (int i = 0; i < n; ++i)
{
if (abs(thickness + 1) < 0.1)
drawLine((int)((float)x1 + (float)i * px), (int)((float)y1 + (float)i * py),
(int)((float)x1 + (float)(i + 1) * px), (int)((float)y1 + (float)(i + 1) * py), color1 + i);
else
drawThickLine((int)((float)x1 + (float)i * px), (int)((float)y1 + (float)i * py),
(int)((float)x1 + (float)(i + 1) * px), (int)((float)y1 + (float)(i + 1) * py), color1 + i,
thickness);
}
}

View File

@ -2,6 +2,7 @@
#define __SHAPES_H__ #define __SHAPES_H__
#include "Arduino.h" #include "Arduino.h"
#include "Triangulate.h"
class Shapes class Shapes
{ {
@ -29,7 +30,16 @@ class Shapes
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
void drawElipse(int rx, int ry, int xc, int yc, int c);
void fillElipse(int rx, int ry, int xc, int yc, int c);
void drawPolygon(int *x, int *y, int n, int color);
void fillPolygon(int *x, int *y, int n, int color);
void drawThickLine(int x1, int y1, int x2, int y2, int color, float thickness);
void drawGradientLine(int x1, int y1, int x2, int y2, int color1, int color2, float thickness = -1);
private: private:
Triangulate triangulate;
virtual void startWrite(void) = 0; virtual void startWrite(void) = 0;
virtual void writePixel(int16_t x, int16_t y, uint16_t color) = 0; virtual void writePixel(int16_t x, int16_t y, uint16_t color) = 0;
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) = 0; virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) = 0;

143
src/include/Triangulate.cpp Normal file
View File

@ -0,0 +1,143 @@
#include "Triangulate.h"
#include "Arduino.h"
#include "math.h"
float Triangulate::area(int x1, int y1, int x2, int y2, int x3, int y3)
{
return fabs((float)((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))) / 2.0);
}
bool Triangulate::isInside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y)
{
float A = area(x1, y1, x2, y2, x3, y3);
float A1 = area(x, y, x2, y2, x3, y3);
float A2 = area(x1, y1, x, y, x3, y3);
float A3 = area(x1, y1, x2, y2, x, y);
return fabs(-A + A1 + A2 + A3) < 1e-3;
}
void Triangulate::preProcess(int *x, int *y, int n)
{
for (int i = 0; i < n; ++i)
{
int prev = (i - 1 + n) % n;
int next = (i + 1 + n) % n;
float deg = atan2(y[prev] - y[i], x[prev] - x[i]) - atan2(y[next] - y[i], x[next] - x[i]);
if (deg < 0.0)
deg += 2 * M_PI;
innerAngle[i] = deg;
}
}
void Triangulate::updateVertex(int p, int *x, int *y, int n)
{
int prev = (p - 1 + n) % n;
int next = (p + 1 + n) % n;
float deg = atan2(y[prev] - y[p], x[prev] - x[p]) - atan2(y[next] - y[p], x[next] - x[p]);
if (deg < 0.0)
deg += 2 * M_PI;
innerAngle[p] = deg;
bool f = 0;
for (int j = 0; j < n; ++j)
{
if (prev != j && p != j && next != j && innerAngle[p] > M_PI &&
isInside(x[prev], y[prev], x[p], y[p], x[next], y[next], x[j], y[j]))
f = 1;
}
earTip[p] = !f;
}
bool Triangulate::isConvex(int *x, int *y, int n)
{
for (int i = 0; i < n; ++i)
if (innerAngle[i] > M_PI)
return 0;
return 1;
}
void Triangulate::trivialTriangles(int *x, int *y, int n)
{
for (int i = 0; i < n - 2; ++i)
{
tx[tc] = x[0];
ty[tc] = y[0];
++tc;
tx[tc] = x[i + 1];
ty[tc] = y[i + 1];
++tc;
tx[tc] = x[i + 2];
ty[tc] = y[i + 2];
++tc;
}
}
void Triangulate::findEars(int *x, int *y, int n)
{
for (int i = 0; i < n; ++i)
{
if (innerAngle[i] > M_PI)
continue;
int prev = (i - 1 + n) % n;
int next = (i + 1 + n) % n;
bool f = 0;
for (int j = 0; j < n; ++j)
{
if (prev != j && i != j && next != j && innerAngle[i] > M_PI &&
isInside(x[prev], y[prev], x[i], y[i], x[next], y[next], x[j], y[j]))
f = 1;
}
earTip[i] = !f;
}
}
int Triangulate::smallestEar(int *x, int *y, int n)
{
int mn = 0;
for (int i = 1; i < n; ++i)
if (earTip[i] && innerAngle[i] < innerAngle[mn])
mn = i;
return mn;
}
void Triangulate::nonTrivialTriangles(int *x, int *y, int n)
{
findEars(x, y, n);
int initialN = n;
while (tc / 3 < initialN - 2)
{
int pos = smallestEar(x, y, n);
int prev = (pos - 1 + n) % n;
int next = (pos + 1 + n) % n;
tx[tc] = x[prev];
ty[tc] = y[prev];
++tc;
tx[tc] = x[pos];
ty[tc] = y[pos];
++tc;
tx[tc] = x[next];
ty[tc] = y[next];
++tc;
for (int i = pos; i < n - 1; i++)
{
x[i] = x[i + 1];
y[i] = y[i + 1];
innerAngle[i] = innerAngle[i + 1];
earTip[i] = earTip[i + 1];
}
--n;
updateVertex(prev, x, y, n);
updateVertex(prev + 1, x, y, n);
}
}
void Triangulate::triangulate(int *x, int *y, int n, int *_tx, int *_ty)
{
tc = 0;
preProcess(x, y, n);
if (isConvex(x, y, n))
trivialTriangles(x, y, n);
else
nonTrivialTriangles(x, y, n);
memcpy(_tx, tx, 100);
memcpy(_ty, ty, 100);
}

30
src/include/Triangulate.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef TRIANGULATE_H
#define TRIANGULATE_H
#include "Arduino.h"
class Triangulate
{
private:
int tx[100];
int ty[100];
int tc = 0;
float innerAngle[100];
bool earTip[100];
float area(int x1, int y1, int x2, int y2, int x3, int y3);
bool isInside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y);
void preProcess(int *x, int *y, int n);
void updateVertex(int p, int *x, int *y, int n);
bool isConvex(int *x, int *y, int n);
void trivialTriangles(int *x, int *y, int n);
void findEars(int *x, int *y, int n);
int smallestEar(int *x, int *y, int n);
void nonTrivialTriangles(int *x, int *y, int n);
public:
void triangulate(int *x, int *y, int n, int *_tx, int *_ty);
};
#endif

View File

@ -24,7 +24,7 @@
#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 display(
INKPLATE_1BIT); // Create an object on Inkplate library and also set library into 1 Bit mode (Monochrome) INKPLATE_3BIT); // 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()
@ -49,7 +49,7 @@ void loop()
// NOTE: Both drawBitmapFromSD methods allow for an optional fourth "invert" parameter. Setting this parameter // 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 // 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. // exporting bitmaps from certain softwares.
if (!display.drawBitmapFromSD("4bitish.bmp", 200, 0, 0)) if (!display.drawBitmapFromSD("4bitTest.bmp", 0, 0, 0))
{ {
// 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 // REMEMBER! You can only use Windows Bitmap file with color depth of 1, 4, 8 or 24 bits with no