mirror of
https://github.com/paperdash/device-epd.git
synced 2024-11-13 19:12:00 +00:00
157 lines
3.3 KiB
C++
157 lines
3.3 KiB
C++
#include "image.h"
|
|
#include "format/JPEG.h"
|
|
#include "format/PNG.h"
|
|
#include "display.h"
|
|
|
|
structImageProcess ImageProcess;
|
|
|
|
// dithering
|
|
uint16_t ditheringBufferSize;
|
|
int16_t *ditheringCurRowDelta;
|
|
int16_t *ditheringNextRowDelta;
|
|
|
|
void setupImage()
|
|
{
|
|
// create buffer for dithering
|
|
ditheringBufferSize = displayGetWidth() + 1;
|
|
ditheringCurRowDelta = new int16_t[ditheringBufferSize];
|
|
ditheringNextRowDelta = new int16_t[ditheringBufferSize];
|
|
|
|
setupImageJPEG();
|
|
//setupImagePNG();
|
|
}
|
|
|
|
void ImageNew(int x, int y, int w, int h, bool dithering)
|
|
{
|
|
Serial.printf("ImageNew: x: %d, y: %d, dithering: %d \n", x, y, dithering);
|
|
|
|
ImageProcess.x = x;
|
|
ImageProcess.y = y;
|
|
ImageProcess.w = w;
|
|
ImageProcess.h = h;
|
|
ImageProcess.dithering = dithering;
|
|
|
|
memset(ditheringCurRowDelta, 0, sizeof(ditheringCurRowDelta[0]) * ditheringBufferSize);
|
|
memset(ditheringNextRowDelta, 0, sizeof(ditheringNextRowDelta[0]) * ditheringBufferSize);
|
|
}
|
|
|
|
void ImageWriteBuffer(uint8_t buff[], size_t c)
|
|
{
|
|
// initial detect format
|
|
if (ImageProcess.format == 0)
|
|
{
|
|
if (memcmp(buff, ImageHeaderPNG, sizeof(ImageHeaderPNG) - 1) == 0 && false)
|
|
{
|
|
Serial.println(" image format: PNG");
|
|
ImageProcess.format = 3;
|
|
|
|
pngOpenFramebuffer();
|
|
}
|
|
else if (memcmp(buff, ImageHeaderJPEG, sizeof(ImageHeaderJPEG) - 1) == 0)
|
|
{
|
|
Serial.println(" image format: JPEG");
|
|
ImageProcess.format = 4;
|
|
|
|
jpegOpenFramebuffer();
|
|
}
|
|
else
|
|
{
|
|
ImageProcess.format = 1;
|
|
Serial.println(" unkown image format. first header are:");
|
|
Serial.println(buff[0]);
|
|
Serial.println(buff[1]);
|
|
Serial.println(buff[2]);
|
|
Serial.println(buff[3]);
|
|
Serial.println(buff[4]);
|
|
Serial.println(buff[5]);
|
|
}
|
|
}
|
|
|
|
// write display frame
|
|
switch (ImageProcess.format)
|
|
{
|
|
// PNG
|
|
case 3:
|
|
pngWriteFramebuffer(0, buff, c);
|
|
break;
|
|
// JPEG
|
|
case 4:
|
|
jpegWriteFramebuffer(0, buff, c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ImageFlushBuffer()
|
|
{
|
|
// update display
|
|
switch (ImageProcess.format)
|
|
{
|
|
// PNG
|
|
case 3:
|
|
pngFlushFramebuffer();
|
|
break;
|
|
// JPEG
|
|
case 4:
|
|
jpegFlushFramebuffer();
|
|
break;
|
|
}
|
|
|
|
// clear settings
|
|
ImageProcess.format = 0;
|
|
ImageProcess.x = 0;
|
|
ImageProcess.y = 0;
|
|
ImageProcess.w = 0;
|
|
ImageProcess.h = 0;
|
|
ImageProcess.dithering = false;
|
|
}
|
|
|
|
void ImageProcessPixel(uint16_t x, uint16_t y, uint8_t rgba[4])
|
|
{
|
|
uint8_t r = rgba[0]; // 0 - 255
|
|
uint8_t g = rgba[1]; // 0 - 255
|
|
uint8_t b = rgba[2]; // 0 - 255
|
|
|
|
int16_t gray = round(r * 0.3 + g * 0.59 + b * 0.11);
|
|
int16_t blackOrWhite;
|
|
|
|
// Add errors to color if there are
|
|
if (ImageProcess.dithering)
|
|
{
|
|
gray += ditheringCurRowDelta[x];
|
|
}
|
|
|
|
if (gray <= 127)
|
|
{
|
|
blackOrWhite = 0;
|
|
}
|
|
else
|
|
{
|
|
blackOrWhite = 255;
|
|
}
|
|
|
|
if (ImageProcess.dithering)
|
|
{
|
|
int16_t oldPixel = gray;
|
|
int16_t newPixel = blackOrWhite;
|
|
|
|
int err = oldPixel - newPixel;
|
|
|
|
if (x > 0)
|
|
{
|
|
ditheringNextRowDelta[x - 1] += err * 3 / 16;
|
|
}
|
|
ditheringNextRowDelta[x] += err * 5 / 16;
|
|
ditheringNextRowDelta[x + 1] += err * 1 / 16;
|
|
ditheringCurRowDelta[x + 1] += err * 7 / 16;
|
|
|
|
if (x == 0 && y > 0)
|
|
{
|
|
// new line
|
|
memcpy(ditheringCurRowDelta, ditheringNextRowDelta, sizeof(ditheringCurRowDelta[0]) * ditheringBufferSize);
|
|
memset(ditheringNextRowDelta, 0, sizeof(ditheringNextRowDelta[0]) * ditheringBufferSize);
|
|
}
|
|
}
|
|
|
|
GFXcanvas1 *canvas = displayGetCanvas();
|
|
canvas->drawPixel(ImageProcess.x + x, ImageProcess.y + y, (uint16_t)blackOrWhite);
|
|
} |