Skip to content
Snippets Groups Projects
Commit 9a70773d authored by schneider's avatar schneider
Browse files

Merge branch 'led02/display/blit' into 'master'

Add blitting function to display

See merge request !349
parents 8eecf0a0 4d37d43b
Branches
Tags
1 merge request!349Add blitting function to display
Pipeline #5093 passed
...@@ -56,6 +56,7 @@ typedef _Bool bool; ...@@ -56,6 +56,7 @@ typedef _Bool bool;
#define API_DISP_FRAMEBUFFER 0x29 #define API_DISP_FRAMEBUFFER 0x29
#define API_DISP_BACKLIGHT 0x2a #define API_DISP_BACKLIGHT 0x2a
#define API_DISP_PRINT_ADV 0x2b #define API_DISP_PRINT_ADV 0x2b
#define API_DISP_BLIT 0x2d
/* API_BATTERY_VOLTAGE 0x30 */ /* API_BATTERY_VOLTAGE 0x30 */
#define API_BATTERY_CURRENT 0x31 #define API_BATTERY_CURRENT 0x31
...@@ -1670,6 +1671,25 @@ API(API_DISP_PIXEL, int epic_disp_pixel( ...@@ -1670,6 +1671,25 @@ API(API_DISP_PIXEL, int epic_disp_pixel(
int16_t x, int16_t y, uint16_t color int16_t x, int16_t y, uint16_t color
)); ));
/**
* Blit an image buffer to display
*
* :param x: x position
* :param y: y position
* :param w: image width
* :param h: image height
* :param img: image data (rgb565)
* :param alpha: 8 bit alpha channel. Currently unused.
*/
API(API_DISP_BLIT, int epic_disp_blit(
int16_t x,
int16_t y,
int16_t w,
int16_t h,
uint16_t *img,
uint8_t *alpha
));
/** /**
* Draws a line on the display * Draws a line on the display
* *
......
...@@ -87,6 +87,68 @@ int epic_disp_pixel(int16_t x, int16_t y, uint16_t color) ...@@ -87,6 +87,68 @@ int epic_disp_pixel(int16_t x, int16_t y, uint16_t color)
} }
} }
int epic_disp_blit(
int16_t pos_x,
int16_t pos_y,
int16_t width,
int16_t height,
uint16_t *img,
uint8_t *alpha
) {
/* TODO: alpha is not supported yet */
int cl = check_lock();
if (cl < 0) {
return cl;
} else {
int16_t offset_x = (pos_x < 0) ? -pos_x : 0;
int16_t count_x = width - offset_x;
int16_t offset_y = (pos_y < 0) ? -pos_y : 0;
int16_t count_y = height - offset_y;
if (pos_x + width >= 160) {
count_x -= (pos_x + width) % 160;
}
if (pos_y + height >= 80) {
count_y -= (pos_y + height) % 80;
}
if (offset_x == 0 && offset_y == 0 && count_x == width &&
count_y == height) {
/* Simply copy full image, no cropping or alpha blending */
gfx_copy_region(
&display_screen,
pos_x,
pos_y,
width,
height,
GFX_RAW,
width * height * 2,
img
);
} else {
/* Copy cropped image line by line */
for (int16_t curr_y = offset_y;
curr_y < offset_y + count_y;
curr_y++) {
uint16_t *curr_img =
img + (curr_y * width + offset_x);
gfx_copy_region(
&display_screen,
pos_x + offset_x,
pos_y + curr_y,
count_x,
1,
GFX_RAW,
count_x * 2,
curr_img
);
}
}
return 0;
}
}
int epic_disp_line( int epic_disp_line(
int16_t xstart, int16_t xstart,
int16_t ystart, int16_t ystart,
......
...@@ -120,6 +120,83 @@ class Display: ...@@ -120,6 +120,83 @@ class Display:
sys_display.pixel(x, y, col) sys_display.pixel(x, y, col)
return self return self
def blit(self, x, y, w, h, img, rgb565=False, alpha=None):
"""
Draws an image on the display.
:param x: X coordinate
:param y: Y coordinate
:param w: Image width
:param h: Image height
:param img: Buffer with pixel data. Default format is RGB with 8 bits per channel.
:param alpha: Alpha mask for `img`
:param rgb565: Set to `True` if the data supplied is in rgb565 format instead of 8 bit RGB.
.. note::
Alpha mask support is not yet implemented.
.. versionadded:: 1.17
**Example with RGB data:**
.. code-block:: python
import display
import color
# Draw a blue 32x20 pixel rectangle:
# Each pixel is 3 bytes big. Order is red, green, blue
img = bytes(color.BLUE) * 32 * 20
with display.open() as d:
d.clear()
d.blit(10, 10, 32, 20, img)
d.update()
**Example with rgb565 data:**
.. code-block:: python
import array
import display
# Draw a green 32x20 pixel rectangle:
# 0x07E0 has all bits for green set to 1. Order is RRRR RGGG GGGB BBBB
img = array.array('H', [0x07E0 for x in range(32 * 20)])
with display.open() as d:
d.clear()
d.blit(10, 10, 32, 20, img, rgb565=True)
d.update()
**Example with a MicroPython FrameBuffer:**
.. code-block:: python
import framebuf
import display
# Create a 160x80 pixel frame buffer and write "Hello World" on the display
f = framebuf.FrameBuffer(bytearray(160 * 80 * 2), 160, 80, framebuf.RGB565)
with display.open() as d:
f.text("Hello World", 0, 0, 0xF800) # red
d.blit(0, 0, 160, 80, f, rgb565=True)
d.update()
"""
# TODO: alpha is not yet supported by epicardium
if alpha is not None:
raise ValueError("alpha not yet supported")
if alpha is None:
sys_display.blit(x, y, w, h, img, rgb565)
else:
sys_display.blit(x, y, w, h, img, rgb565, alpha)
return self
def backlight(self, brightness): def backlight(self, brightness):
""" """
Set display backlight brightness Set display backlight brightness
......
...@@ -98,6 +98,7 @@ Q(display) ...@@ -98,6 +98,7 @@ Q(display)
Q(print) Q(print)
Q(print_adv) Q(print_adv)
Q(pixel) Q(pixel)
Q(blit)
Q(backlight) Q(backlight)
Q(line) Q(line)
Q(rect) Q(rect)
......
...@@ -94,6 +94,76 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( ...@@ -94,6 +94,76 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
display_pixel_obj, 3, 3, mp_display_pixel display_pixel_obj, 3, 3, mp_display_pixel
); );
/* blit image to display */
static mp_obj_t mp_display_blit(size_t n_args, const mp_obj_t *args)
{
/* Required arguments: posx, posy (on display),
width, height (of image),
buffer (rgb data of image) */
int pos_x = mp_obj_get_int(args[0]);
int pos_y = mp_obj_get_int(args[1]);
int width = mp_obj_get_int(args[2]);
int height = mp_obj_get_int(args[3]);
bool rgb565 = mp_obj_is_true(args[5]);
mp_buffer_info_t img;
int res = 0;
/* Load buffer and ensure it contains enough data */
if (!mp_get_buffer(args[4], &img, MP_BUFFER_READ)) {
mp_raise_TypeError("'img' does not support buffer protocol.");
}
int bpp = rgb565 ? 2 : 3;
if ((int)img.len < width * height * bpp) {
mp_raise_ValueError("'img' is too small.");
}
uint16_t *buf = NULL;
if (rgb565) {
buf = (uint16_t *)img.buf;
} else {
/* Will raise an exception if out of memory: */
buf = m_malloc(width * height * bpp);
for (int i = 0; i < width * height; i++) {
buf[i] = rgb888_to_rgb565(((uint8_t *)img.buf) + 3 * i);
}
}
if (n_args > 6) {
mp_buffer_info_t alpha;
/* Load alpha buffer and check size */
if (!mp_get_buffer(args[6], &alpha, MP_BUFFER_READ)) {
mp_raise_TypeError(
"'alpha' does not support buffer protocol."
);
}
if ((int)alpha.len < width * height) {
mp_raise_ValueError("'alpha' is too small.");
}
res = epic_disp_blit(
pos_x, pos_y, width, height, buf, (uint8_t *)alpha.buf
);
} else {
res = epic_disp_blit(pos_x, pos_y, width, height, buf, NULL);
}
if (buf) {
m_free(buf);
}
if (res < 0) {
mp_raise_OSError(-res);
}
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
display_blit_obj, 5, 6, mp_display_blit
);
/* set display backlight brightness */ /* set display backlight brightness */
static mp_obj_t mp_display_backlight(size_t n_args, const mp_obj_t *args) static mp_obj_t mp_display_backlight(size_t n_args, const mp_obj_t *args)
{ {
...@@ -233,6 +303,7 @@ static const mp_rom_map_elem_t display_module_globals_table[] = { ...@@ -233,6 +303,7 @@ static const mp_rom_map_elem_t display_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&display_print_obj) }, { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&display_print_obj) },
{ MP_ROM_QSTR(MP_QSTR_print_adv), MP_ROM_PTR(&display_print_adv_obj) }, { MP_ROM_QSTR(MP_QSTR_print_adv), MP_ROM_PTR(&display_print_adv_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&display_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&display_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&display_blit_obj) },
{ MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&display_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&display_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_line_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_line_obj) },
{ MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_rect_obj) }, { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_rect_obj) },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment