mirror of
https://github.com/usetrmnl/bb_epaper.git
synced 2026-04-29 13:43:26 -07:00
Added 3 and 4 color examples which use 2-plane G5 images
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// 3 color (Black/White/Red) example
|
||||
//
|
||||
#include <bb_epaper.h>
|
||||
#include "smiley_hearts.h"
|
||||
BBEPAPER bbep(EP29YR_168x384);
|
||||
// My Xiao ESP32C3 + LCD Adapter
|
||||
#define DC_PIN 4
|
||||
#define BUSY_PIN 20
|
||||
#define RESET_PIN 5
|
||||
#define CS_PIN 21
|
||||
|
||||
void setup()
|
||||
{
|
||||
bbep.initIO(DC_PIN, RESET_PIN, BUSY_PIN, CS_PIN, -1, -1);
|
||||
bbep.allocBuffer(); // use a back buffer
|
||||
// bbep.setRotation(270);
|
||||
bbep.fillScreen(BBEP_WHITE);
|
||||
bbep.setTextColor(BBEP_RED);
|
||||
bbep.setFont(FONT_12x16);
|
||||
bbep.println("bb_epaper v1");
|
||||
bbep.setTextColor(BBEP_BLACK);
|
||||
bbep.println("B/W/Y/R Test");
|
||||
for (int i=1; i<44; i++) {
|
||||
bbep.drawCircle(bbep.width()/2, 80, i, (i < 22) ? BBEP_BLACK : BBEP_RED);
|
||||
}
|
||||
bbep.loadG5Image(smiley_hearts, 0, 160, 0,0,1.0f);
|
||||
bbep.writePlane();
|
||||
bbep.refresh(REFRESH_FULL);
|
||||
bbep.wait();
|
||||
bbep.sleep(DEEP_SLEEP);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Created with imageconvert, written by Larry Bank
|
||||
// 128 x 128 x 2-bits per pixel (split into 2 1-bit planes)
|
||||
// compressed image data size = 362 bytes
|
||||
//
|
||||
const uint8_t smiley_hearts[] = {
|
||||
0xb2,0xbb,0x80,0x00,0x80,0x00,0x62,0x01,0xe7,0x35,0x15,0x9c,0xc4,0x7a,0x72,0xd2,
|
||||
0x68,0x20,0xe1,0x03,0x84,0x1c,0x20,0xe1,0x07,0x08,0x3a,0x70,0x83,0xa7,0x09,0xd0,
|
||||
0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x75,0xdd,0x18,0x76,0x18,0x82,0x3a,0x04,0x18,
|
||||
0x20,0x6e,0x90,0x69,0xf4,0xd3,0x74,0x9a,0x6e,0x96,0xfd,0xab,0xa5,0xf9,0x84,0xb6,
|
||||
0x99,0x15,0x74,0x10,0xb8,0x83,0x7a,0xde,0x96,0xfa,0xdb,0xaf,0xeb,0x6f,0xfd,0x7b,
|
||||
0xeb,0xfb,0xeb,0xff,0xbe,0x9f,0xbd,0x6b,0xde,0xd3,0x5d,0xeb,0xb4,0xd7,0x7a,0xd0,
|
||||
0x69,0x85,0xc3,0xc2,0x78,0x69,0x85,0xc1,0xe7,0x0d,0x22,0xcc,0x4f,0xd9,0x79,0x3e,
|
||||
0x23,0xff,0xff,0xff,0xff,0xfd,0x5f,0xff,0xab,0xff,0xab,0xfd,0x5f,0xda,0xf6,0xbd,
|
||||
0xaf,0x6b,0xda,0xd5,0xed,0x6a,0xf6,0xad,0x5a,0xd5,0xed,0x5a,0xb5,0x61,0x43,0x56,
|
||||
0xad,0x58,0x50,0xd5,0xa8,0x61,0x43,0x0a,0x18,0x50,0xc2,0x86,0x14,0x18,0x28,0x30,
|
||||
0x53,0x99,0x8d,0x4e,0x70,0x21,0x1c,0xa2,0x03,0xf9,0xcd,0xc4,0xb3,0x99,0x0e,0x67,
|
||||
0x2e,0x24,0xc1,0x03,0xc2,0x0f,0x04,0x1e,0x10,0x7a,0x0f,0x08,0x3c,0x20,0xf4,0xf0,
|
||||
0x9e,0x83,0xd3,0xd3,0xd3,0xc2,0x7a,0x7d,0xe9,0xe9,0xe9,0xe9,0xe9,0xfe,0x9e,0x9e,
|
||||
0xbd,0xe9,0xfe,0x9f,0xe9,0xfe,0x9f,0xe9,0xff,0xe9,0xff,0xe9,0xff,0xeb,0xdf,0xff,
|
||||
0xfe,0xbd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xbf,0xf3,0x0b,0x13,0x24,0x1f,
|
||||
0x09,0x43,0xf5,0x6d,0x6d,0x26,0xfd,0x2b,0xf4,0x9b,0xf5,0x6d,0x6d,0x04,0x44,0x51,
|
||||
0x09,0xfd,0x6a,0x1b,0xf4,0x99,0x4a,0x62,0x75,0xb1,0xb5,0x1f,0x6d,0x2f,0xb4,0x96,
|
||||
0xdb,0x5f,0x6d,0x25,0xb6,0xd2,0xfb,0x4b,0xb6,0x18,0x55,0xdb,0x49,0x6d,0xb4,0xbd,
|
||||
0x86,0x10,0x4b,0x6d,0xa5,0xd8,0x61,0x84,0x97,0x61,0x84,0x96,0xc3,0x0c,0x20,0xbb,
|
||||
0x60,0xc1,0x25,0xb0,0xc1,0x82,0x09,0x70,0xce,0x1a,0x1a,0x12,0xd8,0x62,0x17,0x61,
|
||||
0x82,0x5b,0x39,0x00,0xc2,0xd9,0xc8,0xc4,0x16,0xc5,0x6d,0x6d,0x6d,0x6c,0x2c,0x35,
|
||||
0xb5,0xb0,0xb0,0xd6,0x18,0x5b,0x58,0x61,0x61,0x85,0x83,0x05,0x86,0x16,0x0c,0xe4,
|
||||
0x26,0x13,0x99,0x8c,0xe7,0x3a,0x0c,0xc7,0xe0,0x00};
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created with imageconvert, written by Larry Bank
|
||||
// 80 x 80 x 2-bits per pixel (split into 2 1-bit planes)
|
||||
// compressed image data size = 333 bytes
|
||||
//
|
||||
const uint8_t smiley_bwr[] = {
|
||||
0xb2,0xbb,0x50,0x00,0x50,0x00,0x45,0x01,0x3a,0x41,0x33,0x9e,0x29,0x04,0x0e,0x08,
|
||||
0x1c,0x20,0xe1,0x1c,0x70,0xc0,0xe8,0xe2,0xca,0x07,0x08,0x10,0x37,0x41,0x06,0xe8,
|
||||
0x20,0xdc,0x20,0x83,0x0e,0x93,0x74,0x83,0x74,0x13,0x7a,0x7a,0x4d,0xd2,0x30,0xca,
|
||||
0x62,0x55,0xba,0x4b,0x6d,0xfb,0x56,0xe9,0x2d,0xf4,0xad,0x5b,0xd7,0xbd,0x7b,0xbd,
|
||||
0x2e,0xf5,0xfb,0xd5,0xef,0xff,0xa5,0xed,0xfa,0xff,0xfd,0x27,0xa6,0xff,0xff,0xff,
|
||||
0x4f,0xf7,0xa7,0xa4,0xd3,0x57,0xb4,0xfe,0x23,0xff,0xff,0xe6,0x18,0xcc,0xa1,0xfa,
|
||||
0x69,0xff,0xee,0xb6,0x96,0xff,0xe9,0x37,0xf5,0xbf,0xd3,0xf6,0xd3,0x4d,0x2e,0x9a,
|
||||
0x7f,0x86,0x17,0xb6,0xc9,0x13,0x44,0xc9,0x2f,0x16,0xd2,0x1a,0xdb,0x0c,0x24,0xb7,
|
||||
0x61,0x84,0x15,0x6c,0x30,0xc2,0x4b,0x76,0x18,0x4a,0xb6,0xc1,0x97,0x8c,0x5b,0x6c,
|
||||
0x42,0x4b,0x86,0x92,0xb6,0xd7,0x6c,0x30,0x92,0xb6,0x0c,0x12,0x56,0xcc,0x5a,0xa5,
|
||||
0xb1,0x5b,0x61,0x2b,0x0d,0x2b,0x69,0x43,0x0c,0x20,0xac,0x30,0x95,0x86,0x12,0xb0,
|
||||
0x60,0x82,0x86,0x71,0xc3,0x14,0x31,0x0a,0x18,0x50,0x61,0x41,0x9c,0xa1,0xe3,0xa3,
|
||||
0x15,0x28,0xa1,0xff,0x3a,0x21,0x99,0xcf,0x14,0xc1,0x03,0xc2,0x0f,0x08,0x3c,0x20,
|
||||
0xf4,0xf4,0x1e,0x13,0xd3,0xd3,0xd1,0x86,0x53,0x12,0xaf,0x4b,0x6f,0xda,0xbd,0x2d,
|
||||
0xf5,0x6a,0xf5,0xef,0xf7,0xd2,0xef,0xff,0x57,0xbf,0xfd,0x7b,0xf5,0xff,0xf4,0xf4,
|
||||
0xff,0xff,0xfd,0x3f,0xbd,0x3d,0x34,0xd7,0xb4,0xfe,0x23,0xff,0xff,0xe6,0x18,0xcc,
|
||||
0xa1,0xfa,0x69,0xff,0xfa,0xda,0xdf,0xfa,0x4d,0xfa,0xdf,0xd3,0xf6,0x9a,0x6b,0xa6,
|
||||
0x9f,0xc3,0x0b,0xdb,0x24,0x4d,0x13,0x24,0xb8,0xb6,0x90,0xf6,0xc3,0x09,0x2e,0xc3,
|
||||
0x08,0x2e,0xc3,0x0c,0x24,0xbb,0x0c,0x25,0xdb,0x06,0x5e,0x31,0x6d,0x88,0x4b,0x86,
|
||||
0x96,0xda,0xec,0x30,0x96,0xc1,0x82,0x5b,0x31,0x6a,0xb6,0x2b,0x61,0x61,0xad,0xac,
|
||||
0x30,0xb0,0xc2,0xc3,0x0b,0x06,0x0b,0x3a,0x21,0x98,0xff,0xc0,0x00};
|
||||
@@ -2,18 +2,26 @@
|
||||
// 3 color (Black/White/Red) example
|
||||
//
|
||||
#include <bb_epaper.h>
|
||||
#include "smiley_bwr.h"
|
||||
//BBEPAPER bbep(EP154R_152x152); // 1.54" 152x152 B/W/R
|
||||
BBEPAPER bbep(EP266YR_184x360); // 1.54" 152x152 B/W/R
|
||||
BBEPAPER bbep(EP26R_152x296);
|
||||
//BBEPAPER bbep(EP266YR_184x360); // 1.54" 152x152 B/W/R
|
||||
// My Arduino Nano 33 BLE e-paper adapter
|
||||
#define DC_PIN 16
|
||||
#define BUSY_PIN 15
|
||||
#define RESET_PIN 14
|
||||
#define CS_PIN 10
|
||||
//#define DC_PIN 16
|
||||
//#define BUSY_PIN 15
|
||||
//#define RESET_PIN 14
|
||||
//#define CS_PIN 10
|
||||
// My Xiao + LCD Adapter
|
||||
#define DC_PIN 4
|
||||
#define BUSY_PIN 20
|
||||
#define RESET_PIN 5
|
||||
#define CS_PIN 21
|
||||
|
||||
void setup()
|
||||
{
|
||||
bbep.initIO(DC_PIN, RESET_PIN, BUSY_PIN, CS_PIN);
|
||||
bbep.initIO(DC_PIN, RESET_PIN, BUSY_PIN, CS_PIN, -1, -1);
|
||||
bbep.allocBuffer(); // use a back buffer
|
||||
// bbep.setRotation(270);
|
||||
bbep.fillScreen(BBEP_WHITE);
|
||||
bbep.setTextColor(BBEP_RED);
|
||||
bbep.setFont(FONT_12x16);
|
||||
@@ -21,8 +29,9 @@ void setup()
|
||||
bbep.setTextColor(BBEP_BLACK);
|
||||
bbep.println("B/W/R Test");
|
||||
for (int i=1; i<44; i++) {
|
||||
bbep.drawCircle(bbep.width()/2, bbep.height()/2, i, (i < 22) ? BBEP_BLACK : BBEP_RED);
|
||||
bbep.drawCircle(bbep.width()/2, 64, i, (i < 22) ? BBEP_BLACK : BBEP_RED);
|
||||
}
|
||||
bbep.loadG5Image(smiley_bwr, 0, 160, 0,0,1.0f);
|
||||
bbep.writePlane();
|
||||
bbep.refresh(REFRESH_FULL);
|
||||
bbep.wait();
|
||||
|
||||
+173
-40
@@ -10,16 +10,27 @@
|
||||
#include "PNGdec.h"
|
||||
|
||||
PNG png; // static instance of class
|
||||
uint8_t u8Temp[1024];
|
||||
|
||||
enum {
|
||||
MODE_BW = 0,
|
||||
MODE_BWR,
|
||||
MODE_BWYR,
|
||||
MODE_4GRAY
|
||||
};
|
||||
//
|
||||
// Create the comments and const array boilerplate for the hex data bytes
|
||||
//
|
||||
void StartHexFile(FILE *f, int iLen, int w, int h, const char *fname)
|
||||
void StartHexFile(FILE *f, int iLen, int w, int h, const char *fname, int iMode)
|
||||
{
|
||||
int i;
|
||||
char szTemp[256];
|
||||
fprintf(f, "//\n// Created with imageconvert, written by Larry Bank\n");
|
||||
fprintf(f, "// %d x %d x 1-bit per pixel\n", w, h);
|
||||
if (iMode == MODE_BW) {
|
||||
fprintf(f, "// %d x %d x 1-bit per pixel\n", w, h);
|
||||
} else {
|
||||
fprintf(f, "// %d x %d x 2-bits per pixel (split into 2 1-bit planes)\n", w, h);
|
||||
}
|
||||
fprintf(f, "// compressed image data size = %d bytes\n//\n", iLen);
|
||||
strcpy(szTemp, fname);
|
||||
i = strlen(szTemp);
|
||||
@@ -46,16 +57,86 @@ void AddHexBytes(FILE *f, void *pData, int iLen, int bLast)
|
||||
}
|
||||
} /* AddHexBytes() */
|
||||
//
|
||||
// Match the given pixel to black (00), white (01), or red (1x)
|
||||
//
|
||||
unsigned char GetBWRPixel(int r, int g, int b)
|
||||
{
|
||||
uint8_t ucOut=0;
|
||||
int gr;
|
||||
|
||||
gr = (b + r + g*2)>>2; // gray
|
||||
// match the color to closest of black/white/red
|
||||
if (r > g && r > b) { // red is dominant
|
||||
if (gr < 100 && r < 80) {
|
||||
// black
|
||||
} else {
|
||||
if (r-b > 32 && r-g > 32) {
|
||||
// is red really dominant?
|
||||
ucOut |= 3; // red (can be 2 or 3, but 3 is compatible w/BWYR)
|
||||
} else { // yellowish should be white
|
||||
// no, use white instead of pink/yellow
|
||||
ucOut |= 1;
|
||||
}
|
||||
}
|
||||
} else { // check for white/black
|
||||
if (gr >= 100) {
|
||||
ucOut |= 1; // white
|
||||
} else {
|
||||
// black
|
||||
}
|
||||
}
|
||||
return ucOut;
|
||||
} /* GetBWRPixel() */
|
||||
//
|
||||
// Match the given pixel to black (00), white (01), yellow (10), or red (11)
|
||||
// returns 2 bit value of closest matching color
|
||||
//
|
||||
unsigned char GetBWYRPixel(int r, int g, int b)
|
||||
{
|
||||
uint8_t ucOut=0;
|
||||
int gr;
|
||||
|
||||
gr = (b + r + g*2)>>2; // gray
|
||||
// match the color to closest of black/white/yellow/red
|
||||
if (r > b || g > b) { // red or yellow is dominant
|
||||
if (gr < 90 && r < 80 && g < 80) {
|
||||
// black
|
||||
} else {
|
||||
if (r-b > 32 && r-g > 32) {
|
||||
// is red really dominant?
|
||||
ucOut = 3; // red
|
||||
} else if (r-b > 32 && g-b > 32) {
|
||||
// yes, yellow
|
||||
ucOut = 2;
|
||||
} else {
|
||||
ucOut = 1; // gray/white
|
||||
}
|
||||
}
|
||||
} else { // check for white/black
|
||||
if (gr >= 100) {
|
||||
ucOut = 1; // white
|
||||
} else {
|
||||
// black
|
||||
}
|
||||
}
|
||||
return ucOut;
|
||||
} /* GetBWYRPixel() */
|
||||
//
|
||||
// The user passed a file with the wrong bit depth (not 1)
|
||||
// convert to 1-bpp by converting each color to 0 or 1 based on the gray level
|
||||
//
|
||||
void ConvertTo1Bpp(uint8_t *pBMP, int w, int h, int iBpp, uint8_t *palette)
|
||||
void ConvertBpp(uint8_t *pBMP, int iMode, int w, int h, int iBpp, uint8_t *palette)
|
||||
{
|
||||
int g, x, y, iDelta, iPitch, iDestPitch;
|
||||
int gray, r, g, b, x, y, iDelta, iPitch, iDestPitch, iDestBpp;
|
||||
uint8_t *s, *d, *pPal, u8, count;
|
||||
|
||||
iDestBpp = (iMode == MODE_BW) ? 1 : 2;
|
||||
iPitch = (w * iBpp)/8;
|
||||
iDestPitch = (w+7)/8;
|
||||
if (iDestBpp == 1)
|
||||
iDestPitch = (w+7)/8;
|
||||
else {
|
||||
iDestPitch = (w+3)/4;
|
||||
}
|
||||
iDelta = iBpp/8;
|
||||
for (y=0; y<h; y++) {
|
||||
s = &pBMP[iPitch * y];
|
||||
@@ -63,75 +144,96 @@ void ConvertTo1Bpp(uint8_t *pBMP, int w, int h, int iBpp, uint8_t *palette)
|
||||
count = 8; // bits in a byte
|
||||
u8 = 0; // start with all black
|
||||
for (x=0; x<w; x++) { // slower code, but less code :)
|
||||
u8 <<= 1;
|
||||
u8 <<= iDestBpp;
|
||||
switch (iBpp) {
|
||||
case 24:
|
||||
case 32:
|
||||
g = (s[0] + s[1]*2 + s[2])/4; // gray value
|
||||
r = s[0];
|
||||
g = s[1];
|
||||
b = s[2];
|
||||
s += iDelta;
|
||||
break;
|
||||
case 16:
|
||||
g = s[1] & 0xf8; // red
|
||||
g += ((s[0] | s[1] << 8) << 2) & 0x1f0; // green x 2
|
||||
g += (s[0] << 3) & 0xf8; // blue
|
||||
g /= 4;
|
||||
r = s[1] & 0xf8; // red
|
||||
g = ((s[0] | s[1] << 8) >> 3) & 0xfc; // green
|
||||
b = s[0] << 3;
|
||||
s += 2;
|
||||
break;
|
||||
case 8:
|
||||
if (palette) {
|
||||
pPal = &palette[s[0] * 3];
|
||||
g = (pPal[0] + pPal[1]*2 + pPal[2])/4;
|
||||
r = pPal[0];
|
||||
g = pPal[1];
|
||||
b = pPal[2];
|
||||
} else {
|
||||
g = s[0];
|
||||
r = g = b = s[0];
|
||||
}
|
||||
s++;
|
||||
break;
|
||||
case 4:
|
||||
if (palette) {
|
||||
if (x & 1) {
|
||||
pPal = &palette[(s[0] & 0xf) * 4];
|
||||
g = (pPal[0] + pPal[1]*2 + pPal[2])/4;
|
||||
pPal = &palette[(s[0] & 0xf) * 3];
|
||||
s++;
|
||||
} else {
|
||||
pPal = &palette[(s[0]>>4) * 4];
|
||||
g = (pPal[0] + pPal[1]*2 + pPal[2])/4;
|
||||
pPal = &palette[(s[0]>>4) * 3];
|
||||
}
|
||||
r = pPal[0];
|
||||
g = pPal[1];
|
||||
b = pPal[2];
|
||||
} else {
|
||||
if (x & 1) {
|
||||
g = (s[0] & 0xf) | (s[0] << 4);
|
||||
r = g = b = (s[0] & 0xf) | (s[0] << 4);
|
||||
} else {
|
||||
g = (s[0] >> 4) | (s[0] & 0xf0);
|
||||
r = g = b = (s[0] >> 4) | (s[0] & 0xf0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} // switch on bpp
|
||||
if (g >= 128) u8 |= 1; // white
|
||||
count--;
|
||||
if (iMode == MODE_BW || iMode == MODE_4GRAY) {
|
||||
gray = (r + g*2 + b)/4;
|
||||
u8 |= gray >> (8-iDestBpp);
|
||||
} else if (iMode == MODE_BWR) {
|
||||
u8 |= GetBWRPixel(r, g, b); // match the closest colors
|
||||
} else {
|
||||
u8 |= GetBWYRPixel(r, g, b);
|
||||
}
|
||||
count -= iDestBpp;
|
||||
if (count == 0) { // byte is full, move on
|
||||
*d++ = u8;
|
||||
u8 = 0;
|
||||
count = 8;
|
||||
}
|
||||
} // for x
|
||||
if (w & 7) {
|
||||
*d++ = u8; // store last partial byte
|
||||
if (count != 8) {
|
||||
*d++ = (u8 << count); // store last partial byte
|
||||
}
|
||||
} // for y
|
||||
} /* ConvertTo1Bpp() */
|
||||
} /* ConvertBpp() */
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
int w, h, y, rc, bpp;
|
||||
uint8_t *s, *pOut, *pData;
|
||||
int iPitch, iOutSize, iDataSize;
|
||||
int iPitch, iOutSize, iDataSize, iMode;
|
||||
FILE *ihandle;
|
||||
uint8_t *pPalette;
|
||||
G5ENCIMAGE g5enc;
|
||||
BB_BITMAP bbbm;
|
||||
int bHFile; // flag indicating if the output will be a .H file of hex data
|
||||
const char *szModes[] = {"BW", "BWR", "BWYR", "4GRAY", NULL};
|
||||
|
||||
printf("PNG to Group5 image conversion tool\n");
|
||||
if (argc != 3) {
|
||||
printf("Usage: ./pngconvert <PNG image> <g5 compressed image>\n");
|
||||
if (argc != 4) {
|
||||
printf("Usage: ./pngconvert <PNG image> <g5 compressed image> <mode>\n");
|
||||
printf("valid modes: BW, BWR, BWYR, 4GRAY (case insensitive)\n");
|
||||
return -1;
|
||||
}
|
||||
iMode = 0;
|
||||
while (szModes[iMode] && strcasecmp(szModes[iMode], argv[3]) != 0) {
|
||||
iMode++;
|
||||
}
|
||||
if (szModes[iMode] == NULL) {
|
||||
printf("Invalid mode\n");
|
||||
return -1;
|
||||
}
|
||||
pOut = (uint8_t *)argv[2] + strlen(argv[2]) - 1;
|
||||
@@ -178,24 +280,55 @@ int main(int argc, const char * argv[]) {
|
||||
bpp = 32;
|
||||
break;
|
||||
} // switch
|
||||
if (bpp != 1) { // need to convert it to 1-bpp
|
||||
printf("Converting from %d-bpp to 1-bpp\n", bpp);
|
||||
ConvertTo1Bpp(png.getBuffer(), w, h, bpp, pPalette);
|
||||
if (iMode != MODE_BW) { // need to convert it to 1 or 2-bpp
|
||||
printf("Converting pixels to %s\n", szModes[iMode]);
|
||||
ConvertBpp(png.getBuffer(), iMode, w, h, bpp, pPalette);
|
||||
}
|
||||
iPitch = (w+7) >> 3;
|
||||
pOut = (uint8_t *)malloc(iPitch * h * 2);
|
||||
if (iMode == MODE_BW) {
|
||||
s = png.getBuffer();
|
||||
rc = g5_encode_init(&g5enc, w, h, pOut, iPitch * h);
|
||||
for (y=0; y<h && rc == G5_SUCCESS; y++) {
|
||||
rc = g5_encode_encodeLine(&g5enc, s);
|
||||
s += iPitch;
|
||||
}
|
||||
} else { // split the bit planes
|
||||
uint8_t *d, src, ucMask, uc = 0;
|
||||
s = png.getBuffer();
|
||||
rc = g5_encode_init(&g5enc, w, h*2, pOut, iPitch * h * 2);
|
||||
// encode plane 0 first
|
||||
for (y=0; y<h*2 && rc == G5_SUCCESS; y++) {
|
||||
if (y == h) {
|
||||
s = png.getBuffer(); // restart from the top
|
||||
}
|
||||
src = *s++;
|
||||
d = u8Temp;
|
||||
ucMask = (y < h) ? 0x40 : 0x80; // lower or upper source bit
|
||||
for (int x=0; x<w; x++) {
|
||||
uc <<= 1;
|
||||
if (src & ucMask) {
|
||||
uc |= 1;
|
||||
}
|
||||
src <<= 2;
|
||||
if ((x & 3) == 3 && x != w-1) { // new input byte
|
||||
src = *s++;
|
||||
}
|
||||
if ((x & 7) == 7) { // new output byte
|
||||
*d++ = uc;
|
||||
}
|
||||
} // for x
|
||||
*d = uc; // store last partial byte
|
||||
rc = g5_encode_encodeLine(&g5enc, u8Temp);
|
||||
}
|
||||
}
|
||||
iPitch = (w+7) >> 3;
|
||||
pOut = (uint8_t *)malloc(iPitch * h);
|
||||
s = png.getBuffer();
|
||||
rc = g5_encode_init(&g5enc, w, h, pOut, iPitch * h);
|
||||
for (y=0; y<h && rc == G5_SUCCESS; y++) {
|
||||
rc = g5_encode_encodeLine(&g5enc, s);
|
||||
s += iPitch;
|
||||
}
|
||||
if (rc == G5_ENCODE_COMPLETE) {
|
||||
FILE *f;
|
||||
iOutSize = g5_encode_getOutSize(&g5enc);
|
||||
if (iMode != MODE_BW) iPitch *= 2;
|
||||
printf("Input data size: %d bytes, compressed size: %d bytes\n", iPitch*h, iOutSize);
|
||||
printf("Compression ratio: %2.1f:1\n", (float)(iPitch*h) / (float)iOutSize);
|
||||
bbbm.u16Marker = BB_BITMAP_MARKER;
|
||||
bbbm.u16Marker = (iMode == MODE_BW) ? BB_BITMAP_MARKER : BB_BITMAP2_MARKER;
|
||||
bbbm.width = w;
|
||||
bbbm.height = h;
|
||||
bbbm.size = iOutSize;
|
||||
@@ -204,7 +337,7 @@ int main(int argc, const char * argv[]) {
|
||||
printf("Error opening: %s\n", argv[2]);
|
||||
} else {
|
||||
if (bHFile) { // generate HEX file to include in a project
|
||||
StartHexFile(f, iOutSize+sizeof(BB_BITMAP), w, h, argv[2]);
|
||||
StartHexFile(f, iOutSize+sizeof(BB_BITMAP), w, h, argv[2], iMode);
|
||||
AddHexBytes(f, &bbbm, sizeof(BB_BITMAP), 0);
|
||||
AddHexBytes(f, pOut, iOutSize, 1);
|
||||
printf(".H file created successfully!\n");
|
||||
|
||||
@@ -148,6 +148,7 @@ typedef struct g5_enc_image_tag
|
||||
// 16-bit marker at the start of a BB_BITMAP file
|
||||
// (BitBank BitmapFile)
|
||||
#define BB_BITMAP_MARKER 0xBBBF
|
||||
#define BB_BITMAP2_MARKER 0xBBB2
|
||||
|
||||
// Font info per large character (glyph)
|
||||
typedef struct {
|
||||
|
||||
+55
-13
@@ -999,6 +999,37 @@ const uint8_t epd213z_init_full[] PROGMEM =
|
||||
0 // end
|
||||
}; /* epd213z_init_full */
|
||||
|
||||
const uint8_t epd213z_init_gray[] PROGMEM =
|
||||
{
|
||||
0x01, 0x12, // soft reset
|
||||
BUSY_WAIT,
|
||||
0x04, 0x01, 0xf9, 0x00, 0x00,
|
||||
0x02, 0x011, 0x03,
|
||||
0x03, 0x44, 0x00, 0x0f,
|
||||
0x05, 0x45, 0x00, 0x00, 0xf9, 0x00,
|
||||
0x02, 0x3c, 0x01,
|
||||
BUSY_WAIT,
|
||||
0x02, 0x18, 0x80,
|
||||
0x02, 0x4e, 0x00,
|
||||
0x03, 0x4f, 0x00, 0x00,
|
||||
BUSY_WAIT,
|
||||
91, 0x32, // LUT
|
||||
0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT 0
|
||||
0x96, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT 1
|
||||
0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT 2
|
||||
0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT 3
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT VCOM
|
||||
0x0a, 0x0a, 0x07, 0x02, 0x00, // phases for 0 A,B,C,D
|
||||
0x02, 0x02, 0x00, 0x00, 0x00, // phases for 1 A,B
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // 2-9 not needed
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0 // end
|
||||
}; /* epd213z_init_gray */
|
||||
|
||||
const uint8_t epd213z_init_fast[] PROGMEM =
|
||||
{
|
||||
0x01, 0x12, // soft reset
|
||||
@@ -1309,10 +1340,10 @@ const uint8_t epd295_init_sequence_part[] PROGMEM =
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
@@ -2226,6 +2257,7 @@ const EPD_PANEL panelDefs[] PROGMEM = {
|
||||
{128, 296, 0, epd29z_init_full, epd29z_init_fast, epd29z_init_full, 0, BBEP_CHIP_SSD16xx, u8Colors_2clr}, // CrowPanel 2.9 (EP29Z_128x296)
|
||||
{128, 296, 0, epd29z_init_gray, epd29z_init_gray, epd29z_init_gray, BBEP_4GRAY, BBEP_CHIP_SSD16xx, u8Colors_4gray}, // CrowPanel 2.9 (EP29Z_128x296_4GRAY)
|
||||
{122, 250, 0, epd213z_init_full, epd213z_init_fast, epd213z_init_full, 0, BBEP_CHIP_SSD16xx, u8Colors_2clr}, // CrowPanel 2.13 (EP213Z_122x250)
|
||||
{122, 250, 0, epd213z_init_gray, epd213z_init_gray, epd213z_init_gray, BBEP_4GRAY, BBEP_CHIP_SSD16xx, u8Colors_4gray}, // CrowPanel 2.13 (EP213Z_122x250) 4-gray mode
|
||||
};
|
||||
//
|
||||
// Set the e-paper panel type
|
||||
@@ -2236,11 +2268,27 @@ int bbepSetPanelType(BBEPDISP *pBBEP, int iPanel)
|
||||
if (pBBEP == NULL || iPanel <= EP_PANEL_UNDEFINED || iPanel >= EP_PANEL_COUNT)
|
||||
return BBEP_ERROR_BAD_PARAMETER;
|
||||
|
||||
pBBEP->native_width = pBBEP->width = panelDefs[iPanel].width;
|
||||
pBBEP->native_height = pBBEP->height = panelDefs[iPanel].height;
|
||||
switch (pBBEP->iOrientation) {
|
||||
case 0:
|
||||
case 180:
|
||||
pBBEP->width = pBBEP->native_width = panelDefs[iPanel].width;
|
||||
pBBEP->height = pBBEP->native_height = panelDefs[iPanel].height;
|
||||
break;
|
||||
case 90:
|
||||
case 270:
|
||||
pBBEP->width = pBBEP->native_height = panelDefs[iPanel].height;
|
||||
pBBEP->height = pBBEP->native_width = panelDefs[iPanel].width;
|
||||
break;
|
||||
}
|
||||
|
||||
pBBEP->x_offset = panelDefs[iPanel].x_offset;
|
||||
pBBEP->chip_type = panelDefs[iPanel].chip_type;
|
||||
pBBEP->iFlags = panelDefs[iPanel].flags;
|
||||
// If the memory is already allocated and the user is setting a
|
||||
// panel type which needs 2 planes, assume they have been allocated
|
||||
if (pBBEP->ucScreen && (pBBEP->iFlags & (BBEP_3COLOR | BBEP_4GRAY | BBEP_4COLOR))) {
|
||||
pBBEP->iFlags |= BBEP_HAS_SECOND_PLANE;
|
||||
}
|
||||
pBBEP->pInitFull = panelDefs[iPanel].pInitFull;
|
||||
pBBEP->pInitFast = panelDefs[iPanel].pInitFast;
|
||||
pBBEP->pInitPart = panelDefs[iPanel].pInitPart;
|
||||
@@ -2740,17 +2788,11 @@ void bbepSetRotation(BBEPDISP *pBBEP, int iRotation)
|
||||
switch (iRotation) {
|
||||
default: return;
|
||||
case 0:
|
||||
pBBEP->width = pBBEP->native_width;
|
||||
pBBEP->height = pBBEP->native_height;
|
||||
break;
|
||||
case 90:
|
||||
pBBEP->width = pBBEP->native_height;
|
||||
pBBEP->height = pBBEP->native_width;
|
||||
break;
|
||||
case 180:
|
||||
pBBEP->width = pBBEP->native_width;
|
||||
pBBEP->height = pBBEP->native_height;
|
||||
break;
|
||||
case 90:
|
||||
case 270:
|
||||
pBBEP->width = pBBEP->native_height;
|
||||
pBBEP->height = pBBEP->native_width;
|
||||
|
||||
+97
-1
@@ -398,6 +398,22 @@ BBEPDISP *pBBEP = (BBEPDISP *)pb;
|
||||
pBBEP->ucScreen[i] = u8;
|
||||
} /* bbepSetPixelFast4Clr() */
|
||||
|
||||
// Fast version (no pointer verification + no boundary checking)
|
||||
// special version for logical ORing 2 planes together
|
||||
void bbepSetPixelFast4ClrV2(void *pb, int x, int y, unsigned char ucColor)
|
||||
{
|
||||
int i;
|
||||
int iPitch;
|
||||
uint8_t u8;
|
||||
BBEPDISP *pBBEP = (BBEPDISP *)pb;
|
||||
|
||||
iPitch = (pBBEP->width+3)>>2;
|
||||
i = (x >> 2) + (y * iPitch);
|
||||
u8 = pBBEP->ucScreen[i];
|
||||
u8 |= ucColor << (1+((3-(x & 3))*2));
|
||||
pBBEP->ucScreen[i] = u8;
|
||||
} /* bbepSetPixelFast4ClrV2() */
|
||||
|
||||
int bbepSetPixel4Gray(void *pb, int x, int y, unsigned char ucColor)
|
||||
{
|
||||
int i;
|
||||
@@ -625,6 +641,84 @@ void InvertBytes(uint8_t *pData, uint8_t bLen)
|
||||
}
|
||||
} /* InvertBytes() */
|
||||
//
|
||||
// 2-plane G5 image
|
||||
// requires a local framebuffer
|
||||
//
|
||||
int bbepLoadG5_2Bit(BBEPDISP *pBBEP, const uint8_t *pG5, int x, int y, float fScale)
|
||||
{
|
||||
uint16_t rc, tx, ty, cx, cy, dx, dy, size;
|
||||
int row, width, height;
|
||||
BB_BITMAP *pbbb;
|
||||
uint8_t *pOldBuffer;
|
||||
BB_SET_PIXEL_FAST *pOldPixel;
|
||||
uint32_t u32Frac, u32XAcc, u32YAcc; // integer fraction vars
|
||||
|
||||
pbbb = (BB_BITMAP *)pG5;
|
||||
u32Frac = (uint32_t)(65536.0f / fScale); // calculate the fraction to advance the destination x/y
|
||||
cx = pgm_read_word(&pbbb->width);
|
||||
cy = pgm_read_word(&pbbb->height);
|
||||
width = pBBEP->width;
|
||||
height = pBBEP->height;
|
||||
// Calculate scaled destination size
|
||||
dx = (int)(fScale * (float)cx);
|
||||
dy = (int)(fScale * (float)cy);
|
||||
size = pgm_read_word(&pbbb->size);
|
||||
rc = g5_decode_init(&g5dec, cx, cy*2, (uint8_t *)&pbbb[1], size);
|
||||
pOldBuffer = pBBEP->ucScreen; // keep old pointer
|
||||
pOldPixel = pBBEP->pfnSetPixelFast;
|
||||
if (!(pBBEP->iFlags & BBEP_4COLOR)) {
|
||||
pBBEP->pfnSetPixelFast = bbepSetPixelFast2Clr;
|
||||
}
|
||||
for (int iPlane = 0; iPlane < 2; iPlane++) {
|
||||
// Treat it as 2 1-bit planes
|
||||
if (iPlane == 1) {
|
||||
if (pBBEP->iFlags & BBEP_4COLOR) {
|
||||
pBBEP->pfnSetPixelFast = bbepSetPixelFast4ClrV2;
|
||||
} else {
|
||||
pBBEP->ucScreen += (((pBBEP->native_width+7)/8) * pBBEP->native_height);
|
||||
}
|
||||
}
|
||||
g5_decode_line(&g5dec, u8Cache); // decode first line to start
|
||||
u32YAcc = 0; //65536; // force first line to get decoded
|
||||
row = 1;
|
||||
for (ty=y; ty<(y+dy) && ty < height; ty++) {
|
||||
uint8_t u8, *s, u8Color, src_mask;
|
||||
while (u32YAcc >= 65536) { // advance to next source line
|
||||
g5_decode_line(&g5dec, u8Cache);
|
||||
row++;
|
||||
u32YAcc -= 65536;
|
||||
}
|
||||
s = u8Cache;
|
||||
u32XAcc = 0;
|
||||
u8 = *s++; // grab first source byte (8 pixels)
|
||||
src_mask = 0x80;
|
||||
for (tx=x; tx<x+dx && tx < width; tx++) {
|
||||
u8Color = ((u8 & src_mask) != 0);
|
||||
(*pBBEP->pfnSetPixelFast)(pBBEP, tx, ty, u8Color);
|
||||
u32XAcc += u32Frac;
|
||||
while (u32XAcc >= 65536) {
|
||||
u32XAcc -= 65536; // whole source pixel horizontal movement
|
||||
src_mask >>= 1;
|
||||
if (src_mask == 0) { // need to load the next byte
|
||||
u8 = *s++;
|
||||
src_mask = 0x80;
|
||||
}
|
||||
}
|
||||
} // for tx
|
||||
u32YAcc += u32Frac;
|
||||
} // for y
|
||||
while (row < cy) {
|
||||
g5_decode_line(&g5dec, u8Cache); // make sure we reach the 2nd plane
|
||||
row++;
|
||||
}
|
||||
} // for each plane
|
||||
// Restore pointers
|
||||
pBBEP->ucScreen = pOldBuffer;
|
||||
pBBEP->pfnSetPixelFast = pOldPixel;
|
||||
|
||||
return BBEP_SUCCESS;
|
||||
} /* bbepLoadG5_2Bit() */
|
||||
//
|
||||
// Load a 1-bpp Group5 compressed bitmap
|
||||
// Pass the pointer to the beginning of the G5 file
|
||||
// If the FG == BG color, and there is a back buffer, it will
|
||||
@@ -646,6 +740,9 @@ int bbepLoadG5(BBEPDISP *pBBEP, const uint8_t *pG5, int x, int y, int iFG, int i
|
||||
iBG = pBBEP->pColorLookup[iBG & 0xf];
|
||||
}
|
||||
pbbb = (BB_BITMAP *)pG5;
|
||||
if (pgm_read_word(&pbbb->u16Marker) == BB_BITMAP2_MARKER) {
|
||||
return bbepLoadG5_2Bit(pBBEP, pG5, x, y, fScale);
|
||||
}
|
||||
if (pgm_read_word(&pbbb->u16Marker) != BB_BITMAP_MARKER) return BBEP_ERROR_BAD_DATA;
|
||||
u32Frac = (uint32_t)(65536.0f / fScale); // calculate the fraction to advance the destination x/y
|
||||
cx = pgm_read_word(&pbbb->width);
|
||||
@@ -1989,7 +2086,6 @@ void bbepEllipse(BBEPDISP *pBBEP, int iCenterX, int iCenterY, int32_t iRadiusX,
|
||||
pBBEP->last_error = BBEP_ERROR_BAD_PARAMETER;
|
||||
return; // invalid radii
|
||||
}
|
||||
ucColor = pBBEP->pColorLookup[ucColor & 0xf];
|
||||
if (iRadiusX > iRadiusY) {// use X as the primary radius
|
||||
iRadius = iRadiusX;
|
||||
iXFrac = 65536;
|
||||
|
||||
+2
-1
@@ -102,9 +102,10 @@ int rc = BBEP_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case EPD_CROWPANEL213:
|
||||
case EPD_CROWPANEL213_4GRAY:
|
||||
pinMode(7, OUTPUT);
|
||||
digitalWrite(7, HIGH); // screen power on
|
||||
if (setPanelType(EP213Z_122x250) == BBEP_SUCCESS) {
|
||||
if (setPanelType((iProduct == EPD_CROWPANEL213) ? EP213Z_122x250 : EP213Z_122x250_4GRAY) == BBEP_SUCCESS) {
|
||||
initIO(13, 10, 9, 14, 11, 12, 12000000);
|
||||
setRotation(270);
|
||||
return BBEP_SUCCESS;
|
||||
|
||||
@@ -123,6 +123,7 @@ enum {
|
||||
EPD_CROWPANEL29,
|
||||
EPD_CROWPANEL29_4GRAY,
|
||||
EPD_CROWPANEL213,
|
||||
EPD_CROWPANEL213_4GRAY,
|
||||
EPD_PRODUCT_COUNT
|
||||
};
|
||||
|
||||
@@ -176,6 +177,7 @@ enum {
|
||||
EP29Z_128x296, // SSD1680 (CrowPanel 2.9")
|
||||
EP29Z_128x296_4GRAY, // SSD1680 (CrowPanel 2.9")
|
||||
EP213Z_122x250, // SSD1680 (CrowPanel 2.13")
|
||||
EP213Z_122x250_4GRAY, // CrowPanel 2.13" 4 gray mode
|
||||
EP_PANEL_COUNT
|
||||
};
|
||||
#ifdef FUTURE
|
||||
|
||||
Reference in New Issue
Block a user