@@ -20,7 +20,7 @@ typedef struct _ModPicoGraphics_obj_t {
20
20
21
21
typedef struct _PNG_decode_target {
22
22
void *target;
23
- uint8_t flags = 0 ;
23
+ uint8_t mode = 0 ;
24
24
Point position = {0 , 0 };
25
25
Rect source = {0 , 0 , 0 , 0 };
26
26
Point scale = {1 , 1 };
@@ -39,8 +39,10 @@ typedef struct _PNG_obj_t {
39
39
int height;
40
40
} _PNG_obj_t;
41
41
42
- enum FLAGS : uint8_t {
43
- FLAG_NO_DITHER = 1u
42
+ enum DECODE_MODE : uint8_t {
43
+ MODE_POSTERIZE = 0u ,
44
+ MODE_DITHER = 1u ,
45
+ MODE_COPY = 2u ,
44
46
};
45
47
46
48
void *pngdec_open_callback (const char *filename, int32_t *size) {
@@ -121,7 +123,7 @@ MICROPY_EVENT_POLL_HOOK
121
123
_PNG_decode_target *target = (_PNG_decode_target*)pDraw->pUser ;
122
124
PicoGraphics *current_graphics = (PicoGraphics *)target->target ;
123
125
Point current_position = target->position ;
124
- uint8_t current_flags = target->flags ;
126
+ uint8_t current_mode = target->mode ;
125
127
Point scale = target->scale ;
126
128
// "pixel" is slow and clipped,
127
129
// guaranteeing we wont draw png data out of the framebuffer..
@@ -175,7 +177,7 @@ MICROPY_EVENT_POLL_HOOK
175
177
uint8_t a = pDraw->iHasAlpha ? pDraw->pPalette [768 + i] : 1 ;
176
178
if (a) {
177
179
if (current_graphics->pen_type == PicoGraphics::PEN_RGB332) {
178
- if (current_flags & FLAG_NO_DITHER ) {
180
+ if (current_mode == MODE_POSTERIZE || current_mode == MODE_COPY ) {
179
181
// Posterized output to RGB332
180
182
current_graphics->set_pen (RGB (r, g, b).to_rgb332 ());
181
183
current_graphics->rectangle ({current_position.x , current_position.y , scale.x , scale.y });
@@ -192,7 +194,12 @@ MICROPY_EVENT_POLL_HOOK
192
194
|| current_graphics->pen_type == PicoGraphics::PEN_3BIT
193
195
|| current_graphics->pen_type == PicoGraphics::PEN_INKY7) {
194
196
195
- if (current_flags & FLAG_NO_DITHER) {
197
+ // Copy raw palette indexes over
198
+ if (current_mode == MODE_COPY) {
199
+ current_graphics->set_pen (i);
200
+ current_graphics->rectangle ({current_position.x , current_position.y , scale.x , scale.y });
201
+ // Posterized output to the available palete
202
+ } else if (current_mode == MODE_POSTERIZE) {
196
203
int closest = RGB (r, g, b).closest (current_graphics->get_palette (), current_graphics->get_palette_size ());
197
204
if (closest == -1 ) {
198
205
closest = 0 ;
@@ -285,32 +292,58 @@ mp_obj_t _PNG_openRAM(mp_obj_t self_in, mp_obj_t buffer) {
285
292
286
293
// decode
287
294
mp_obj_t _PNG_decode (size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
288
- enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_dither,
289
- ARG_source_x, ARG_source_y, ARG_source_w, ARG_source_h,
290
- ARG_scale_x, ARG_scale_y };
295
+ enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_mode, ARG_source };
291
296
static const mp_arg_t allowed_args[] = {
292
297
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
293
298
{ MP_QSTR_x, MP_ARG_INT, {.u_int = 0 } },
294
299
{ MP_QSTR_y, MP_ARG_INT, {.u_int = 0 } },
295
- { MP_QSTR_scale, MP_ARG_INT, {.u_int = 0 } },
296
- { MP_QSTR_dither, MP_ARG_OBJ, {.u_obj = mp_const_true} },
297
- { MP_QSTR_source_x, MP_ARG_INT, {.u_int = 0 } },
298
- { MP_QSTR_source_y, MP_ARG_INT, {.u_int = 0 } },
299
- { MP_QSTR_source_w, MP_ARG_INT, {.u_int = -1 } },
300
- { MP_QSTR_source_h, MP_ARG_INT, {.u_int = -1 } },
301
- { MP_QSTR_scale_x, MP_ARG_INT, {.u_int = 1 } },
302
- { MP_QSTR_scale_y, MP_ARG_INT, {.u_int = 1 } },
300
+ { MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = nullptr } },
301
+ { MP_QSTR_mode, MP_ARG_INT, {.u_int = 0 } },
302
+ { MP_QSTR_source, MP_ARG_OBJ, {.u_obj = nullptr } },
303
303
};
304
304
305
305
mp_arg_val_t args[MP_ARRAY_SIZE (allowed_args)];
306
306
mp_arg_parse_all (n_args, pos_args, kw_args, MP_ARRAY_SIZE (allowed_args), allowed_args, args);
307
307
308
308
_PNG_obj_t *self = MP_OBJ_TO_PTR2 (args[ARG_self].u_obj , _PNG_obj_t);
309
309
310
- // TODO: Implement integer 1x/2x/3x scaling by repeating pixels?
311
- // int f = args[ARG_scale].u_int;
310
+ if (mp_obj_is_type (args[ARG_source].u_obj , &mp_type_tuple)){
311
+ mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2 (args[ARG_source].u_obj , mp_obj_tuple_t );
312
+
313
+ if (tuple->len != 4 ) mp_raise_ValueError (" decode(): source tuple must contain (x, y, w, h)" );
314
+
315
+ self->decode_target ->source = {
316
+ mp_obj_get_int (tuple->items [0 ]),
317
+ mp_obj_get_int (tuple->items [1 ]),
318
+ mp_obj_get_int (tuple->items [2 ]),
319
+ mp_obj_get_int (tuple->items [3 ])
320
+ };
321
+ } else {
322
+ self->decode_target ->source = {0 , 0 , self->width , self->height };
323
+ }
324
+
325
+ // Scale is a single int, corresponds to both width/height
326
+ if (mp_obj_is_int (args[ARG_scale].u_obj )) {
327
+ self->decode_target ->scale = {
328
+ mp_obj_get_int (args[ARG_scale].u_obj ),
329
+ mp_obj_get_int (args[ARG_scale].u_obj )
330
+ };
331
+ // Scale is a tuple, separate scales for width/height
332
+ } else if (mp_obj_is_type (args[ARG_scale].u_obj , &mp_type_tuple)){
333
+ mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2 (args[ARG_scale].u_obj , mp_obj_tuple_t );
334
+
335
+ if (tuple->len != 2 ) mp_raise_ValueError (" decode(): scale tuple must contain (scale_x, scale_y)" );
336
+
337
+ self->decode_target ->scale = {
338
+ mp_obj_get_int (tuple->items [0 ]),
339
+ mp_obj_get_int (tuple->items [1 ])
340
+ };
341
+ // Something else, just roll with the default
342
+ } else {
343
+ self->decode_target ->scale = {1 , 1 };
344
+ }
312
345
313
- self->decode_target ->flags = args[ARG_dither]. u_obj == mp_const_false ? FLAG_NO_DITHER : 0 ;
346
+ self->decode_target ->mode = args[ARG_mode]. u_int ;
314
347
315
348
self->decode_target ->position = {args[ARG_x].u_int , args[ARG_y].u_int };
316
349
@@ -321,15 +354,6 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
321
354
322
355
pngdec_open_helper (self);
323
356
324
- int source_x = args[ARG_source_x].u_int ;
325
- int source_y = args[ARG_source_y].u_int ;
326
- int source_w = args[ARG_source_w].u_int == -1 ? self->width : args[ARG_source_w].u_int ;
327
- int source_h = args[ARG_source_h].u_int == -1 ? self->height : args[ARG_source_h].u_int ;
328
-
329
- self->decode_target ->source = {source_x, source_y, source_w, source_h};
330
-
331
- self->decode_target ->scale = {args[ARG_scale_x].u_int , args[ARG_scale_y].u_int };
332
-
333
357
result = self->png ->decode (self->decode_target , 0 );
334
358
335
359
// Close the file since we've opened it on-demand
@@ -350,4 +374,29 @@ mp_obj_t _PNG_getHeight(mp_obj_t self_in) {
350
374
return mp_obj_new_int (self->height );
351
375
}
352
376
377
+ // get_height
378
+ mp_obj_t _PNG_getPalette (mp_obj_t self_in) {
379
+ _PNG_obj_t *self = MP_OBJ_TO_PTR2 (self_in, _PNG_obj_t);
380
+ pngdec_open_helper (self);
381
+
382
+ self->png ->decode (nullptr , 0 );
383
+
384
+ uint8_t *palette = self->png ->getPalette ();
385
+
386
+ mp_obj_t palette_out[256 ];
387
+
388
+ for (auto i = 0u ; i < 256 ; i++) {
389
+ mp_obj_t entry[3 ] = {
390
+ mp_obj_new_int (*palette++),
391
+ mp_obj_new_int (*palette++),
392
+ mp_obj_new_int (*palette++)
393
+ };
394
+ palette_out[i] = mp_obj_new_tuple (3 , entry);
395
+ }
396
+
397
+ self->png ->close ();
398
+
399
+ return mp_obj_new_list (256 , palette_out);
400
+ }
401
+
353
402
}
0 commit comments