From 7a57b2985f567e56d57d0a0229e3a4759797fa31 Mon Sep 17 00:00:00 2001 From: Thomas Ballmann Date: Fri, 20 Mar 2020 20:04:41 +0100 Subject: [PATCH] first step for jpeg image dithering #7 --- include/image.h | 2 + include/imageJPEG.h | 16 +++++++ src/imageJPEG.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 include/imageJPEG.h diff --git a/include/image.h b/include/image.h index 6e8a847..6e88919 100644 --- a/include/image.h +++ b/include/image.h @@ -13,6 +13,8 @@ typedef struct bool dithering; } structImageProcess; +void setupImage(); + void ImageNew(int x, int y, int w, int h, bool dithering); void ImageWriteBuffer(uint8_t buff[], size_t c); void ImageFlushBuffer(); diff --git a/include/imageJPEG.h b/include/imageJPEG.h new file mode 100644 index 0000000..449d0c1 --- /dev/null +++ b/include/imageJPEG.h @@ -0,0 +1,16 @@ +#ifndef IMAGE_JPEG_H +#define IMAGE_JPEG_H + +#include "image.h" +extern structImageProcess ImageProcess; + +// @see http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html +const char ImageHeaderJPEG[] = "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00"; +// FF E0 00 10 4A 46 , 49 46 00 + +void setupImageJPEG(); +void jpegOpenFramebuffer(); +void jpegWriteFramebuffer(int offset, uint8_t bitmap[], int c); +void jpegFlushFramebuffer(); + +#endif \ No newline at end of file diff --git a/src/imageJPEG.cpp b/src/imageJPEG.cpp index 07aa2ed..214ea38 100644 --- a/src/imageJPEG.cpp +++ b/src/imageJPEG.cpp @@ -7,6 +7,14 @@ File tmpFileBuffer; bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap); +static constexpr int MAX_WIDTH = 640; +static constexpr uint8_t BLOCK_SIZE = 15; +static uint8_t blockDelta[BLOCK_SIZE * MAX_WIDTH + 1]; + +static int16_t curRowDeltaJ[MAX_WIDTH + 1]; + +unsigned int pixelCount = 0; + void setupImageJPEG() { Serial.println("setupJPEG"); @@ -16,6 +24,8 @@ void setupImageJPEG() // The decoder must be given the exact name of the rendering function above TJpgDec.setCallback(tft_output); + + memset(blockDelta, 0, sizeof(blockDelta)); } void jpegOpenFramebuffer() @@ -29,11 +39,13 @@ void jpegOpenFramebuffer() { Serial.println("Failed to open file for writing"); } + + pixelCount = 0; } void jpegWriteFramebuffer(int offset, uint8_t bitmap[], int c) { - //Serial.println("jpegWriteFramebuffer"); + Serial.print("."); if (tmpFileBuffer) { tmpFileBuffer.write(bitmap, c); @@ -42,21 +54,97 @@ void jpegWriteFramebuffer(int offset, uint8_t bitmap[], int c) void jpegFlushFramebuffer() { - //Serial.println("jpegFlushFramebuffer"); if (tmpFileBuffer) { tmpFileBuffer.close(); + + uint16_t w = 0, h = 0; + TJpgDec.getFsJpgSize(&w, &h, "/tmp.jpeg"); + Serial.print("Image size: "); + Serial.print(w); + Serial.print("x"); + Serial.println(h); TJpgDec.drawFsJpg(0, 0, "/tmp.jpeg"); } } +void draw_XXX(uint32_t x, uint32_t y, uint8_t color) +{ + //uint8_t r = ((color >> 11) & 0x1F); + //uint8_t g = ((color >> 5) & 0x3F); + //uint8_t b = (color & 0x1F); + /* + uint8_t r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6; + uint8_t g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6; + uint8_t b = (((color & 0x1F) * 527) + 23) >> 6; + */ + uint32_t blue = color & 0x001F; // 5 bits blue + uint32_t green = color & 0x07E0; // 6 bits green + uint32_t red = color & 0xF800; // 5 bits red + + int16_t gray = round(red * 0.3 + green * 0.59 + blue * 0.11); + int16_t blackOrWhite; + + // Add errors to color if there are + if (ImageProcess.dithering) + { + gray += curRowDeltaJ[x]; + } + + if (gray <= 127) + { + blackOrWhite = 0; + } + else + { + blackOrWhite = 255; + } + + displayWritePixel(ImageProcess.x + x, ImageProcess.y + y, blackOrWhite); +} + +void on_drawPixel(uint32_t x, uint32_t y, uint32_t color) +{ + pixelCount++; + + uint32_t blockPageY = y - ((y / 16) * 16); + blockDelta[(blockPageY * MAX_WIDTH) + x] = color; + + // TODO bessere lösung finden ! + if (pixelCount == 10240) + { + // new block + uint32_t originOffsetY = ((y / 16) * 16); + + for (uint16_t _y = 0; _y <= BLOCK_SIZE; _y++) + { + for (uint16_t _x = 0; _x < MAX_WIDTH; _x++) + { + uint32_t originX = _x; + uint32_t originY = originOffsetY + _y + (blockPageY * 16); + uint8_t originColor = blockDelta[(_y * MAX_WIDTH) + _x]; + draw_XXX(originX, originY, originColor); + } + } + + // clean buffer + memset(blockDelta, 0, sizeof(blockDelta)); + + pixelCount = 0; + } +} + // This next function will be called during decoding of the jpeg file to // render each block to the TFT. If you use a different TFT library // you will need to adapt this function to suit. bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) { - if (true) + if (false && y == 0) { + //tft_output: x = 0 y = 0 w = 16 h = 16 + //tft_output: x = 16 y = 0 w = 16 h = 16 + //tft_output: x = 384 y = 0 w = 6 h = 16 + //tft_output: x = 0 y = 16 w = 16 h = 16 Serial.print("tft_output: x = "); Serial.print(x); Serial.print(" y = "); @@ -69,11 +157,31 @@ bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) // Stop further decoding as image is running off bottom of screen if (y >= display.height()) + { + Serial.println("y is out of display range!"); return 0; + } // This might work instead if you adapt the sketch to use the Adafruit_GFX library display.drawRGBBitmap(x, y, bitmap, w, h); + int16_t _y = y; + for (int16_t j = 0; j < h; j++, _y++) + { + for (int16_t i = 0; i < w; i++) + { + // geht richtig + //display.writePixel(x + i, y, bitmap[j * w + i]); + + // geht auch aber letzte zeil fehlt + on_drawPixel(x + i, _y, bitmap[j * w + i]); + } + } + if (false && y == 0) + { + Serial.println(pixelCount); + } + // Return 1 to decode next block return 1; } \ No newline at end of file