Jpeg dither added.
This commit is contained in:
parent
6fd0a07186
commit
2ba755e9b2
|
@ -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.
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue