From bea90dfd604253a8fabf6e2d716caf690556db13 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 22 Feb 2023 15:17:38 +0000 Subject: [PATCH] JPEGDEC: Experimental 3bit/4bit palette no-dither. --- .../inky_frame/inky_frame_day_planner.cmake | 28 +++++++++++---- .../inky_frame/inky_frame_day_planner.cpp | 4 +++ examples/inky_frame/inky_frame_jpeg_image.cpp | 35 +++++++++++++++++-- libraries/pico_graphics/pico_graphics.cpp | 3 ++ libraries/pico_graphics/pico_graphics.hpp | 18 ++++++++-- micropython/modules/jpegdec/jpegdec.cpp | 11 +++++- 6 files changed, 87 insertions(+), 12 deletions(-) diff --git a/examples/inky_frame/inky_frame_day_planner.cmake b/examples/inky_frame/inky_frame_day_planner.cmake index 3019d630..7b914208 100644 --- a/examples/inky_frame/inky_frame_day_planner.cmake +++ b/examples/inky_frame/inky_frame_day_planner.cmake @@ -1,14 +1,30 @@ -set(OUTPUT_NAME inky_frame_day_planner) - +# Inky Frame 5.7" add_executable( - ${OUTPUT_NAME} + inky_frame_day_planner inky_frame_day_planner.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib inky_frame hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics) +target_link_libraries(inky_frame_day_planner pico_stdlib inky_frame hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics) -pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_usb(inky_frame_day_planner 1) # create map/bin/hex file etc. -pico_add_extra_outputs(${OUTPUT_NAME}) +pico_add_extra_outputs(inky_frame_day_planner) + +# Inky Frame 7.3" +add_executable( + inky_frame_7_day_planner + inky_frame_day_planner.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(inky_frame_7_day_planner pico_stdlib inky_frame_7 hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics) + +pico_enable_stdio_usb(inky_frame_7_day_planner 1) + +# create map/bin/hex file etc. +pico_add_extra_outputs(inky_frame_7_day_planner) + +target_compile_definitions(inky_frame_7_day_planner PUBLIC INKY_FRAME_7) + diff --git a/examples/inky_frame/inky_frame_day_planner.cpp b/examples/inky_frame/inky_frame_day_planner.cpp index 5ab2a8e5..363ec3ba 100644 --- a/examples/inky_frame/inky_frame_day_planner.cpp +++ b/examples/inky_frame/inky_frame_day_planner.cpp @@ -4,7 +4,11 @@ #include #include "pico/stdlib.h" +#ifdef INKY_FRAME_7 +#include "libraries/inky_frame_7/inky_frame_7.hpp" +#else #include "libraries/inky_frame/inky_frame.hpp" +#endif using namespace pimoroni; diff --git a/examples/inky_frame/inky_frame_jpeg_image.cpp b/examples/inky_frame/inky_frame_jpeg_image.cpp index 2efea15a..000e1617 100644 --- a/examples/inky_frame/inky_frame_jpeg_image.cpp +++ b/examples/inky_frame/inky_frame_jpeg_image.cpp @@ -69,6 +69,36 @@ int jpegdec_draw_callback(JPEGDRAW *draw) { return 1; // continue drawing } +// Draw to the nearest colour instead of dithering +int jpegdec_draw_posterize_callback(JPEGDRAW *draw) { + uint16_t *p = draw->pPixels; + + int xo = jpeg_decode_options.x; + int yo = jpeg_decode_options.y; + + for(int y = 0; y < draw->iHeight; y++) { + for(int x = 0; x < draw->iWidth; x++) { + int sx = ((draw->x + x + xo) * jpeg_decode_options.w) / jpeg.getWidth(); + int sy = ((draw->y + y + yo) * jpeg_decode_options.h) / jpeg.getHeight(); + + if(xo + sx > 0 && xo + sx < inky.bounds.w && yo + sy > 0 && yo + sy < inky.bounds.h) { + int closest = RGB(RGB565(*p)).closest(inky.palette, inky.palette_size); + if (closest != -1) { + inky.set_pen(closest); + inky.set_pixel({xo + sx, yo + sy}); + } else { + inky.set_pen(0); + inky.set_pixel({xo + sx, yo + sy}); + } + } + + p++; + } + } + + return 1; // continue drawing +} + void draw_jpeg(std::string filename, int x, int y, int w, int h) { // TODO: this is a horrible way to do it but we need to pass some parameters @@ -85,7 +115,8 @@ void draw_jpeg(std::string filename, int x, int y, int w, int h) { jpegdec_close_callback, jpegdec_read_callback, jpegdec_seek_callback, - jpegdec_draw_callback); + jpegdec_draw_callback // Try jpegdec_draw_posterize_callback + ); jpeg.setPixelType(RGB565_BIG_ENDIAN); @@ -134,7 +165,7 @@ int main() { }; // Wait for debugger } - filename = "butterfly-600x448.jpg"; + filename = "shutterstock_172537049.jpg"; //inky.led(InkyFrame::LED_E, 255); //sleep_ms(1000); diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 92edeab4..674b3850 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -32,6 +32,9 @@ namespace pimoroni { void PicoGraphics::frame_convert(PenType type, conversion_callback_func callback) {}; void PicoGraphics::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) {}; + int PicoGraphics::get_palette_size() {return 0;} + RGB* PicoGraphics::get_palette() {return nullptr;} + void PicoGraphics::set_dimensions(int width, int height) { bounds = clip = {0, 0, width, height}; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 98bcb965..5ee9ea9e 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -178,9 +178,6 @@ namespace pimoroni { Rect clip; uint thickness = 1; - - - typedef std::function conversion_callback_func; typedef std::function next_pixel_func; typedef std::function next_pixel_func_rgb888; @@ -233,6 +230,9 @@ namespace pimoroni { virtual void set_pixel_span(const Point &p, uint l) = 0; virtual void set_thickness(uint t) = 0; + virtual int get_palette_size(); + virtual RGB* get_palette(); + virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual int create_pen_hsv(float h, float s, float v); virtual int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); @@ -344,6 +344,9 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_thickness(uint t) override {}; + int get_palette_size() override {return palette_size;}; + RGB* get_palette() override {return palette;}; + void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); @@ -375,6 +378,9 @@ namespace pimoroni { int create_pen_hsv(float h, float s, float v) override; int reset_pen(uint8_t i) override; + int get_palette_size() override {return palette_size;}; + RGB* get_palette() override {return palette;}; + void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); @@ -406,6 +412,9 @@ namespace pimoroni { int create_pen_hsv(float h, float s, float v) override; int reset_pen(uint8_t i) override; + int get_palette_size() override {return palette_size;}; + RGB* get_palette() override {return palette;}; + void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); @@ -542,6 +551,9 @@ namespace pimoroni { void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; + int get_palette_size() override {return palette_size;}; + RGB* get_palette() override {return palette;}; + void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); void set_pixel_dither(const Point &p, const RGB &c) override; diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 3b22452a..8c3c12a7 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -149,7 +149,16 @@ MICROPY_EVENT_POLL_HOOK || current_graphics->pen_type == PicoGraphics::PEN_P4 || current_graphics->pen_type == PicoGraphics::PEN_3BIT || current_graphics->pen_type == PicoGraphics::PEN_INKY7) { - current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, RGB((RGB565)pDraw->pPixels[i])); + if (current_flags & FLAG_NO_DITHER) { + int closest = RGB((RGB565)pDraw->pPixels[i]).closest(current_graphics->get_palette(), current_graphics->get_palette_size()); + if (closest == -1) { + closest = 0; + } + current_graphics->set_pen(closest); + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + } else { + current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, RGB((RGB565)pDraw->pPixels[i])); + } } else { current_graphics->set_pen(pDraw->pPixels[i]); current_graphics->pixel({pDraw->x + x, pDraw->y + y});