Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PNGdec: Add support for palette offsets and greyscale copy mode #919

Merged
merged 4 commits into from
Apr 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions micropython/modules/pngdec/pngdec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ typedef struct _PNG_decode_target {
Rect source = {0, 0, 0, 0};
Point scale = {1, 1};
int rotation = 0;
uint8_t palette_offset = 0;
} _PNG_decode_target;

typedef struct _PNG_obj_t {
Expand Down Expand Up @@ -126,6 +127,7 @@ mp_event_handle_nowait();
PicoGraphics *current_graphics = (PicoGraphics *)target->target;
Point current_position = target->position;
uint8_t current_mode = target->mode;
uint8_t current_palette_offset = target->palette_offset;
Point scale = target->scale;
int rotation = target->rotation;
Point step = {0, 0};
Expand Down Expand Up @@ -161,22 +163,15 @@ mp_event_handle_nowait();

//mp_printf(&mp_plat_print, "Drawing scanline at %d, %dbpp, type: %d, width: %d pitch: %d alpha: %d\n", pDraw->y , pDraw->iBpp, pDraw->iPixelType, pDraw->iWidth, pDraw->iPitch, pDraw->iHasAlpha);
uint8_t *pixel = (uint8_t *)pDraw->pPixels;
if(pDraw->iPixelType == PNG_PIXEL_TRUECOLOR ) {
if(pDraw->iPixelType == PNG_PIXEL_TRUECOLOR || pDraw->iPixelType == PNG_PIXEL_TRUECOLOR_ALPHA) {
for(int x = 0; x < pDraw->iWidth; x++) {
uint8_t r = *pixel++;
uint8_t g = *pixel++;
uint8_t b = *pixel++;
if(x < target->source.x || x >= target->source.x + target->source.w) continue;
current_graphics->set_pen(r, g, b);
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
current_position += step;
}
} else if (pDraw->iPixelType == PNG_PIXEL_TRUECOLOR_ALPHA) {
for(int x = 0; x < pDraw->iWidth; x++) {
uint8_t r = *pixel++;
uint8_t g = *pixel++;
uint8_t b = *pixel++;
uint8_t a = *pixel++;
uint8_t a = 1;
if (pDraw->iHasAlpha) {
a = *pixel++;
}
if(x < target->source.x || x >= target->source.x + target->source.w) continue;
if (a) {
current_graphics->set_pen(r, g, b);
Expand All @@ -194,26 +189,46 @@ mp_event_handle_nowait();
i >>= (x & 0b1) ? 0 : 4;
i &= 0xf;
if (x & 1) pixel++;
i = (i << 4) | i;
// Just copy the colour into the upper and lower nibble
if(current_mode != MODE_COPY) {
i = (i << 4) | i;
}
} else if (pDraw->iBpp == 2) { // 2bpp
i = *pixel;
i >>= 6 - ((x & 0b11) << 1);
i &= 0x3;
if ((x & 0b11) == 0b11) pixel++;
// Evenly spaced 4-colour palette
i = (0xFFB86800 >> (i * 8)) & 0xFF;
if(current_mode != MODE_COPY) {
i = (0xFFB86800 >> (i * 8)) & 0xFF;
}
} else { // 1bpp
i = *pixel;
i >>= 7 - (x & 0b111);
i &= 0b1;
if ((x & 0b111) == 0b111) pixel++;
i = i ? 255 : 0;
if(current_mode != MODE_COPY) {
i = i ? 255 : 0;
}
}
if(x < target->source.x || x >= target->source.x + target->source.w) continue;

//mp_printf(&mp_plat_print, "Drawing pixel at %dx%d, %dbpp, value %d\n", current_position.x, current_position.y, pDraw->iBpp, i);
if (current_mode != MODE_PEN) {
current_graphics->set_pen(i, i, i);
// Allow greyscale PNGs to be copied just like an indexed PNG
// since we might want to offset and recolour them.
if(current_mode == MODE_COPY
&& (current_graphics->pen_type == PicoGraphics::PEN_P8
|| current_graphics->pen_type == PicoGraphics::PEN_P4
|| current_graphics->pen_type == PicoGraphics::PEN_3BIT
|| current_graphics->pen_type == PicoGraphics::PEN_INKY7)) {
if(current_palette_offset > 0) {
i = ((int16_t)(i) + current_palette_offset) & 0xff;
}
current_graphics->set_pen(i);
} else {
current_graphics->set_pen(i, i, i);
}
}
if (current_mode != MODE_PEN || i == 0) {
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
Expand Down Expand Up @@ -269,6 +284,9 @@ mp_event_handle_nowait();

// Copy raw palette indexes over
if(current_mode == MODE_COPY) {
if(current_palette_offset > 0) {
i = ((int16_t)(i) + current_palette_offset) & 0xff;
}
current_graphics->set_pen(i);
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
// Posterized output to the available palete
Expand Down Expand Up @@ -364,7 +382,7 @@ mp_obj_t _PNG_openRAM(mp_obj_t self_in, mp_obj_t buffer) {

// decode
mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_mode, ARG_source, ARG_rotate };
enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_mode, ARG_source, ARG_rotate, ARG_palette_offset };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_INT, {.u_int = 0} },
Expand All @@ -373,6 +391,7 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_source, MP_ARG_OBJ, {.u_obj = nullptr} },
{ MP_QSTR_rotate, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_palette_offset, MP_ARG_INT, {.u_int = 0} },
};

mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
Expand Down Expand Up @@ -432,6 +451,8 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)

self->decode_target->position = {args[ARG_x].u_int, args[ARG_y].u_int};

self->decode_target->palette_offset = args[ARG_palette_offset].u_int;

// Just-in-time open of the filename/buffer we stored in self->file via open_RAM or open_file

// Source is a filename
Expand Down
Loading