Jpeg dither added.

This commit is contained in:
nitko12 2020-09-10 13:17:24 +02:00
parent 6fd0a07186
commit 2ba755e9b2
8 changed files with 101 additions and 30 deletions

View File

@ -0,0 +1,24 @@
Software License Agreement (BSD License)
Copyright (c) 2012 Adafruit Industries. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -95,7 +95,7 @@
#define DATA 0x0E8C0030 #define DATA 0x0E8C0030
Inkplate::Inkplate(uint8_t _mode) : GFX(E_INK_WIDTH, E_INK_HEIGHT) Inkplate::Inkplate(uint8_t _mode) : Graphics(E_INK_WIDTH, E_INK_HEIGHT)
{ {
setDisplayMode(_mode); setDisplayMode(_mode);
for (uint32_t i = 0; i < 256; ++i) for (uint32_t i = 0; i < 256; ++i)

View File

@ -23,7 +23,7 @@ Graphics::Graphics(int16_t w, int16_t h)
setTextColor(0xFFFF, 0xFFFF); setTextColor(0xFFFF, 0xFFFF);
setTextWrap(true); setTextWrap(true);
cp437(false); cp437(false);
GraphicsFont = NULL; gfxFont = NULL;
} }
void Graphics::setRotation(uint8_t x) void Graphics::setRotation(uint8_t x)

View File

@ -57,15 +57,20 @@ class Image : virtual public Network
static bool drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool dither, bool invert); static bool drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap, bool dither, bool invert);
uint8_t pixelBuffer[800 * 4 + 5]; uint8_t pixelBuffer[800 * 4 + 5];
uint8_t ditherBuffer[2][800 + 5]; uint8_t ditherBuffer[2][800 + 20];
uint8_t jpegDitherBuffer[18][18];
int16_t blockW = 0, blockH = 0;
int16_t lastY = -1;
uint8_t ditherPalette[256]; // 8 bit colors uint8_t ditherPalette[256]; // 8 bit colors
uint8_t palette[128]; // 2 3 bit colors per byte, _###_### uint8_t palette[128]; // 2 3 bit colors per byte, _###_###
bool legalBmp(bitmapHeader *bmpHeader); bool legalBmp(bitmapHeader *bmpHeader);
uint8_t ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted); uint8_t ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted);
uint8_t ditherGetPixelJpeg(uint8_t px, int x, int y, int w); uint8_t ditherGetPixelJpeg(uint8_t px, int i, int j, int x, int y, int w, int h);
void ditherSwap(int w); void ditherSwap(int w);
void ditherSwapBlockJpeg(int x);
void readBmpHeader(uint8_t *buf, bitmapHeader *_h); void readBmpHeader(uint8_t *buf, bitmapHeader *_h);
void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h); void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h);

View File

@ -5,6 +5,9 @@ uint8_t Image::ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted)
if (paletted) if (paletted)
px = ditherPalette[px]; px = ditherPalette[px];
if (getDisplayMode() == INKPLATE_1BIT)
px = (uint16_t)px >> 1;
uint8_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)ditherBuffer[0][i] + px)); uint8_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)ditherBuffer[0][i] + px));
uint8_t newPixel = oldPixel & (getDisplayMode() == INKPLATE_1BIT ? B10000000 : B11100000); uint8_t newPixel = oldPixel & (getDisplayMode() == INKPLATE_1BIT ? B10000000 : B11100000);
@ -22,21 +25,29 @@ uint8_t Image::ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted)
return newPixel >> 5; return newPixel >> 5;
} }
uint8_t Image::ditherGetPixelJpeg(uint8_t px, int x, int y, int w) uint8_t Image::ditherGetPixelJpeg(uint8_t px, int i, int j, int x, int y, int w, int h)
{ {
uint8_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)ditherBuffer[0][x] + px)); if (blockW == -1)
{
blockW = w;
blockH = h;
}
if (getDisplayMode() == INKPLATE_1BIT)
px = (uint16_t)px >> 1;
uint16_t oldPixel = min((uint16_t)0xFF, (uint16_t)((uint16_t)px + (uint16_t)jpegDitherBuffer[j + 1][i + 1] +
(j ? (uint16_t)0 : (uint16_t)ditherBuffer[0][x + i])));
uint8_t newPixel = oldPixel & (getDisplayMode() == INKPLATE_1BIT ? B10000000 : B11100000); uint8_t newPixel = oldPixel & (getDisplayMode() == INKPLATE_1BIT ? B10000000 : B11100000);
uint8_t quantError = oldPixel - newPixel; uint8_t quantError = oldPixel - newPixel;
ditherBuffer[1][x + 0] += (quantError * 5) >> 4; jpegDitherBuffer[j + 1 + 1][i + 0 + 1] += (quantError * 5) >> 4;
if (x != w - 1)
{ jpegDitherBuffer[j + 0 + 1][i + 1 + 1] += (quantError * 7) >> 4;
ditherBuffer[0][x + 1] += (quantError * 7) >> 4; jpegDitherBuffer[j + 1 + 1][i + 1 + 1] += (quantError * 1) >> 4;
ditherBuffer[1][x + 1] += (quantError * 1) >> 4;
} jpegDitherBuffer[j + 1 + 1][i - 1 + 1] += (quantError * 3) >> 4;
if (x != 0)
ditherBuffer[1][x - 1] += (quantError * 3) >> 4;
return newPixel >> 5; return newPixel >> 5;
} }
@ -49,3 +60,19 @@ void Image::ditherSwap(int w)
ditherBuffer[1][i] = 0; ditherBuffer[1][i] = 0;
} }
} }
void Image::ditherSwapBlockJpeg(int x)
{
for (int i = 0; i < 18; ++i)
{
if (x + i)
ditherBuffer[1][x + i - 1] += jpegDitherBuffer[blockH - 1 + 2][i];
jpegDitherBuffer[i][0 + 1] = jpegDitherBuffer[i][blockW - 1 + 2];
}
for (int j = 0; j < 18; ++j)
for (int i = 0; i < 18; ++i)
if (i != 1)
jpegDitherBuffer[j][i] = 0;
jpegDitherBuffer[17][1] = 0;
}

View File

@ -20,6 +20,11 @@ bool Image::drawJpegFromSd(SdFile *p, int x, int y, bool dither, bool invert)
{ {
uint8_t ret = 0; uint8_t ret = 0;
blockW = -1;
blockH = -1;
lastY = -1;
memset(ditherBuffer, 0, sizeof ditherBuffer);
TJpgDec.setJpgScale(1); TJpgDec.setJpgScale(1);
TJpgDec.setCallback(drawJpegChunk); TJpgDec.setCallback(drawJpegChunk);
@ -76,6 +81,13 @@ bool Image::drawJpegFromBuffer(uint8_t *buff, int32_t len, int x, int y, bool di
{ {
bool ret = 0; bool ret = 0;
blockW = -1;
blockH = -1;
lastY = -1;
TJpgDec.setJpgScale(1);
TJpgDec.setCallback(drawJpegChunk);
if (TJpgDec.drawJpg(x, y, buff, len, dither, invert) == 0) if (TJpgDec.drawJpg(x, y, buff, len, dither, invert) == 0)
ret = 1; ret = 1;
@ -87,20 +99,32 @@ bool Image::drawJpegChunk(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t
if (!_imagePtrJpeg) if (!_imagePtrJpeg)
return 0; return 0;
if (dither && y != _imagePtrJpeg->lastY)
{
_imagePtrJpeg->ditherSwap(800);
_imagePtrJpeg->lastY = y;
}
_imagePtrJpeg->startWrite(); _imagePtrJpeg->startWrite();
for (int j = 0; j < h; ++j) for (int j = 0; j < h; ++j)
{ {
for (int i = 0; i < w; ++i) for (int i = 0; i < w; ++i)
{ {
uint16_t rgb = bitmap[j * w + i]; uint16_t rgb = bitmap[j * w + i];
uint8_t val = RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb)); uint8_t val;
if (dither)
val = _imagePtrJpeg->ditherGetPixelJpeg(RGB8BIT(RED(rgb), GREEN(rgb), BLUE(rgb)), i, j, x, y, w, h);
else
val = RGB3BIT(RED(rgb), GREEN(rgb), BLUE(rgb));
if (invert) if (invert)
val = 7 - val; val = 7 - val;
if (_imagePtrJpeg->getDisplayMode() == INKPLATE_1BIT)
val = (~val >> 2) & 1;
_imagePtrJpeg->writePixel(x + i, y + j, val); _imagePtrJpeg->writePixel(x + i, y + j, val);
} }
} }
if (dither)
_imagePtrJpeg->ditherSwapBlockJpeg(x);
_imagePtrJpeg->endWrite(); _imagePtrJpeg->endWrite();
return 1; return 1;

View File

@ -18,8 +18,8 @@
#define RGB3BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 13) #define RGB3BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 13)
#define RGB8BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 8) #define RGB8BIT(r, g, b) ((54UL * (r) + 183UL * (g) + 19UL * (b)) >> 8)
#define READ32(c) (uint32_t)(*(c) | (*((c) + 1) << 8) | (*((c) + 2) << 16) | (*((c) + 3) << 24)); #define READ32(c) (uint32_t)(*(c) | (*((c) + 1) << 8) | (*((c) + 2) << 16) | (*((c) + 3) << 24))
#define READ16(c) (uint16_t)(*(c) | (*((c) + 1) << 8)); #define READ16(c) (uint16_t)(*(c) | (*((c) + 1) << 8))
#define ROWSIZE(w, c) (((int16_t)c * w + 31) >> 5) << 2 #define ROWSIZE(w, c) (((int16_t)c * w + 31) >> 5) << 2
#endif #endif

View File

@ -1,6 +1,6 @@
#include "Inkplate.h" #include "Inkplate.h"
#include "SdFat.h" #include "SdFat.h"
Inkplate display(INKPLATE_1BIT); Inkplate display(INKPLATE_3BIT);
void setup() void setup()
{ {
@ -19,18 +19,9 @@ void loop()
display.clearDisplay(); display.clearDisplay();
display.display(); display.display();
if (display.sdCardInit()) if (display.sdCardInit())
{ {
Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 0, 0)); Serial.println(display.drawJpegFromSd("Lenna.jpg", 0, 0, 1, 0));
}
display.display();
delay(5000);
if (display.sdCardInit())
{
Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 1, 0));
} }
display.display(); display.display();