From 2ba755e9b293e63773a36ab9e69fa5f893da4da4 Mon Sep 17 00:00:00 2001 From: nitko12 Date: Thu, 10 Sep 2020 13:17:24 +0200 Subject: [PATCH] Jpeg dither added. --- licenses/AdafruitGFX_License.txt | 24 ++++++++++++++++ src/Inkplate.cpp | 2 +- src/include/Graphics.cpp | 2 +- src/include/Image.h | 9 ++++-- src/include/ImageDither.cpp | 47 +++++++++++++++++++++++++------- src/include/ImageJPEG.cpp | 30 ++++++++++++++++++-- src/include/defines.h | 4 +-- test/test.ino | 13 ++------- 8 files changed, 101 insertions(+), 30 deletions(-) create mode 100644 licenses/AdafruitGFX_License.txt diff --git a/licenses/AdafruitGFX_License.txt b/licenses/AdafruitGFX_License.txt new file mode 100644 index 0000000..7492e93 --- /dev/null +++ b/licenses/AdafruitGFX_License.txt @@ -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. diff --git a/src/Inkplate.cpp b/src/Inkplate.cpp index 209c968..b827d1f 100644 --- a/src/Inkplate.cpp +++ b/src/Inkplate.cpp @@ -95,7 +95,7 @@ #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); for (uint32_t i = 0; i < 256; ++i) diff --git a/src/include/Graphics.cpp b/src/include/Graphics.cpp index f994da4..d428ca9 100644 --- a/src/include/Graphics.cpp +++ b/src/include/Graphics.cpp @@ -23,7 +23,7 @@ Graphics::Graphics(int16_t w, int16_t h) setTextColor(0xFFFF, 0xFFFF); setTextWrap(true); cp437(false); - GraphicsFont = NULL; + gfxFont = NULL; } void Graphics::setRotation(uint8_t x) diff --git a/src/include/Image.h b/src/include/Image.h index 0e1b857..5607f5f 100644 --- a/src/include/Image.h +++ b/src/include/Image.h @@ -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); 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 palette[128]; // 2 3 bit colors per byte, _###_### bool legalBmp(bitmapHeader *bmpHeader); 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 ditherSwapBlockJpeg(int x); void readBmpHeader(uint8_t *buf, bitmapHeader *_h); void readBmpHeaderSd(SdFile *_f, bitmapHeader *_h); diff --git a/src/include/ImageDither.cpp b/src/include/ImageDither.cpp index f5447ef..2c0ff0e 100644 --- a/src/include/ImageDither.cpp +++ b/src/include/ImageDither.cpp @@ -5,6 +5,9 @@ uint8_t Image::ditherGetPixelBmp(uint8_t px, int i, int w, bool paletted) if (paletted) 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 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; } -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 quantError = oldPixel - newPixel; - ditherBuffer[1][x + 0] += (quantError * 5) >> 4; - if (x != w - 1) - { - ditherBuffer[0][x + 1] += (quantError * 7) >> 4; - ditherBuffer[1][x + 1] += (quantError * 1) >> 4; - } - if (x != 0) - ditherBuffer[1][x - 1] += (quantError * 3) >> 4; + jpegDitherBuffer[j + 1 + 1][i + 0 + 1] += (quantError * 5) >> 4; + + jpegDitherBuffer[j + 0 + 1][i + 1 + 1] += (quantError * 7) >> 4; + jpegDitherBuffer[j + 1 + 1][i + 1 + 1] += (quantError * 1) >> 4; + + jpegDitherBuffer[j + 1 + 1][i - 1 + 1] += (quantError * 3) >> 4; return newPixel >> 5; } @@ -48,4 +59,20 @@ void Image::ditherSwap(int w) ditherBuffer[0][i] = ditherBuffer[1][i]; 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; } \ No newline at end of file diff --git a/src/include/ImageJPEG.cpp b/src/include/ImageJPEG.cpp index a54f4ba..b71c4c5 100644 --- a/src/include/ImageJPEG.cpp +++ b/src/include/ImageJPEG.cpp @@ -20,6 +20,11 @@ bool Image::drawJpegFromSd(SdFile *p, int x, int y, bool dither, bool invert) { uint8_t ret = 0; + blockW = -1; + blockH = -1; + lastY = -1; + memset(ditherBuffer, 0, sizeof ditherBuffer); + TJpgDec.setJpgScale(1); 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; + blockW = -1; + blockH = -1; + lastY = -1; + + TJpgDec.setJpgScale(1); + TJpgDec.setCallback(drawJpegChunk); + if (TJpgDec.drawJpg(x, y, buff, len, dither, invert) == 0) 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) return 0; + if (dither && y != _imagePtrJpeg->lastY) + { + _imagePtrJpeg->ditherSwap(800); + _imagePtrJpeg->lastY = y; + } + _imagePtrJpeg->startWrite(); for (int j = 0; j < h; ++j) { for (int i = 0; i < 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) val = 7 - val; - + if (_imagePtrJpeg->getDisplayMode() == INKPLATE_1BIT) + val = (~val >> 2) & 1; _imagePtrJpeg->writePixel(x + i, y + j, val); } } + if (dither) + _imagePtrJpeg->ditherSwapBlockJpeg(x); _imagePtrJpeg->endWrite(); return 1; diff --git a/src/include/defines.h b/src/include/defines.h index 7ad5dc8..ce0edf9 100644 --- a/src/include/defines.h +++ b/src/include/defines.h @@ -18,8 +18,8 @@ #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 READ32(c) (uint32_t)(*(c) | (*((c) + 1) << 8) | (*((c) + 2) << 16) | (*((c) + 3) << 24)); -#define READ16(c) (uint16_t)(*(c) | (*((c) + 1) << 8)); +#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 ROWSIZE(w, c) (((int16_t)c * w + 31) >> 5) << 2 #endif \ No newline at end of file diff --git a/test/test.ino b/test/test.ino index 1cf5cfe..3077639 100644 --- a/test/test.ino +++ b/test/test.ino @@ -1,6 +1,6 @@ #include "Inkplate.h" #include "SdFat.h" -Inkplate display(INKPLATE_1BIT); +Inkplate display(INKPLATE_3BIT); void setup() { @@ -19,18 +19,9 @@ void loop() display.clearDisplay(); display.display(); - if (display.sdCardInit()) { - Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 0, 0)); - } - display.display(); - - delay(5000); - - if (display.sdCardInit()) - { - Serial.println(display.drawBitmapFromSd("Lenna.bmp", 0, 0, 1, 0)); + Serial.println(display.drawJpegFromSd("Lenna.jpg", 0, 0, 1, 0)); } display.display();