@@ -348,17 +348,133 @@ const mp_obj_property_t displayio_display_bus_obj = {
348348};
349349
350350
351+ //| .. attribute:: screenshot
352+ //|
353+ //| Take a screenshot.
354+ //|
355+ //|
356+ /* STATIC mp_obj_t displayio_display_obj_get_screenshot(mp_obj_t self_in) { */
357+ /* displayio_display_obj_t *self = native_display(self_in); */
358+ /* return mp_const_none; */
359+ /* } */
360+ /* MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_screenshot_obj, displayio_display_obj_get_screenshot); */
361+
362+ /* const mp_obj_property_t displayio_display_screenshot_obj = { */
363+ /* .base.type = &mp_type_property, */
364+ /* .proxy = {(mp_obj_t)&displayio_display_get_screenshot_obj, */
365+ /* (mp_obj_t)&mp_const_none_obj, */
366+ /* (mp_obj_t)&mp_const_none_obj}, */
367+ /* }; */
368+
369+
370+ #include "py/objarray.h"
371+ mp_obj_array_t * array_new (char typecode , size_t n );
372+ mp_obj_t array_subscr (mp_obj_t self_in , mp_obj_t index_in , mp_obj_t value );
373+
374+ //| .. method:: fill_area(x, y, w, h)
375+ //|
376+ //| Switches to displaying the given group of layers. When group is None, the default
377+ //| CircuitPython terminal will be shown.
378+ //|
379+ //| :param int x: The left edge of the area
380+ //| :param int y: The top edge of the area
381+ //| :param int w: The width of the area
382+ //| :param int h: The height of the area
383+ STATIC mp_obj_t displayio_display_obj_fill_area (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
384+ enum { ARG_x , ARG_y , ARG_width , ARG_height };
385+ static const mp_arg_t allowed_args [] = {
386+ { MP_QSTR_x , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = -1 } },
387+ { MP_QSTR_y , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = -1 } },
388+ { MP_QSTR_width , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = -1 } },
389+ { MP_QSTR_height , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = -1 } },
390+ };
391+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
392+ mp_arg_parse_all (n_args - 1 , pos_args + 1 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
393+
394+ displayio_display_obj_t * self = native_display (pos_args [0 ]);
395+ mp_int_t x = args [ARG_x ].u_int ;
396+ mp_int_t y = args [ARG_y ].u_int ;
397+ mp_int_t w = args [ARG_width ].u_int ;
398+ mp_int_t h = args [ARG_height ].u_int ;
399+
400+ uint16_t buffer_size = 128 ; // In uint32_ts
401+ displayio_area_t area = {
402+ .x1 = x ,
403+ .y1 = y ,
404+ .x2 = x + w ,
405+ .y2 = y + h
406+ };
407+ displayio_area_t clipped ;
408+ // Clip the area to the display by overlapping the areas. If there is no overlap then we're done.
409+ if (!displayio_display_clip_area (self , & area , & clipped )) {
410+ return mp_const_none ;
411+ }
412+ uint16_t subrectangles = 1 ;
413+ uint16_t rows_per_buffer = displayio_area_height (& clipped );
414+ uint8_t pixels_per_word = (sizeof (uint32_t ) * 8 ) / self -> colorspace .depth ;
415+ uint16_t pixels_per_buffer = displayio_area_size (& clipped );
416+ if (displayio_area_size (& clipped ) > buffer_size * pixels_per_word ) {
417+ rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width (& clipped );
418+ if (rows_per_buffer == 0 ) {
419+ rows_per_buffer = 1 ;
420+ }
421+ // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary.
422+ if (self -> colorspace .depth < 8 && !self -> colorspace .pixels_in_byte_share_row ) {
423+ uint8_t pixels_per_byte = 8 / self -> colorspace .depth ;
424+ if (rows_per_buffer % pixels_per_byte != 0 ) {
425+ rows_per_buffer -= rows_per_buffer % pixels_per_byte ;
426+ }
427+ }
428+ subrectangles = displayio_area_height (& clipped ) / rows_per_buffer ;
429+ if (displayio_area_height (& clipped ) % rows_per_buffer != 0 ) {
430+ subrectangles ++ ;
431+ }
432+ pixels_per_buffer = rows_per_buffer * displayio_area_width (& clipped );
433+ buffer_size = pixels_per_buffer / pixels_per_word ;
434+ if (pixels_per_buffer % pixels_per_word ) {
435+ buffer_size += 1 ;
436+ }
437+ }
438+
439+ // Allocated and shared as a uint32_t array so the compiler knows the
440+ // alignment everywhere.
441+ uint32_t buffer [buffer_size ];
442+ volatile uint32_t mask_length = (pixels_per_buffer / 32 ) + 1 ;
443+ uint32_t mask [mask_length ];
444+
445+ for (uint16_t k = 0 ; k < mask_length ; k ++ ) {
446+ mask [k ] = 0x00000000 ;
447+ }
448+ for (uint16_t k = 0 ; k < buffer_size ; k ++ ) {
449+ buffer [k ] = 0x00000000 ;
450+ }
451+
452+ displayio_display_fill_area (self , & area , mask , buffer );
453+
454+ mp_obj_array_t * result = array_new (BYTEARRAY_TYPECODE , buffer_size );
455+ for (int offset = 0 ; offset < buffer_size ; offset ++ ) {
456+ array_subscr (result , MP_OBJ_NEW_SMALL_INT (offset ), MP_OBJ_NEW_SMALL_INT (buffer [offset ]));
457+ }
458+ return result ;
459+ }
460+ MP_DEFINE_CONST_FUN_OBJ_KW (displayio_display_fill_area_obj , 1 , displayio_display_obj_fill_area );
461+
462+
463+
464+
351465STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table [] = {
352466 { MP_ROM_QSTR (MP_QSTR_show ), MP_ROM_PTR (& displayio_display_show_obj ) },
353467 { MP_ROM_QSTR (MP_QSTR_refresh_soon ), MP_ROM_PTR (& displayio_display_refresh_soon_obj ) },
354468 { MP_ROM_QSTR (MP_QSTR_wait_for_frame ), MP_ROM_PTR (& displayio_display_wait_for_frame_obj ) },
469+ { MP_ROM_QSTR (MP_QSTR_fill_area ), MP_ROM_PTR (& displayio_display_fill_area_obj ) },
355470
356471 { MP_ROM_QSTR (MP_QSTR_brightness ), MP_ROM_PTR (& displayio_display_brightness_obj ) },
357472 { MP_ROM_QSTR (MP_QSTR_auto_brightness ), MP_ROM_PTR (& displayio_display_auto_brightness_obj ) },
358473
359474 { MP_ROM_QSTR (MP_QSTR_width ), MP_ROM_PTR (& displayio_display_width_obj ) },
360475 { MP_ROM_QSTR (MP_QSTR_height ), MP_ROM_PTR (& displayio_display_height_obj ) },
361476 { MP_ROM_QSTR (MP_QSTR_bus ), MP_ROM_PTR (& displayio_display_bus_obj ) },
477+ // { MP_ROM_QSTR(MP_QSTR_screenshot), MP_ROM_PTR(&displayio_display_screenshot_obj) },
362478};
363479STATIC MP_DEFINE_CONST_DICT (displayio_display_locals_dict , displayio_display_locals_dict_table );
364480
0 commit comments