Few new fixes.
This commit is contained in:
parent
5d94d15672
commit
6fd572b52f
|
@ -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:
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
|
||||||
// }
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
class Network
|
class Network
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
bool joinAP(char *ssid, char *pass);
|
||||||
|
void disconnect();
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
bool downloadFile(uint8_t *buffer, const char *url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue