From 17f6478a32043db28d29e23d01bdb189cb87030e Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Sun, 14 Feb 2021 15:19:13 +0100
Subject: [PATCH] change(blit): Allow to blit images with alpha channel

---
 bootloader/bootloader-display.c |   3 +-
 epicardium/epicardium.h         |  24 +++--
 epicardium/main.c               |   9 +-
 epicardium/modules/display.c    | 108 +++++++++++++---------
 epicardium/modules/panic.c      |   3 +-
 hw-tests/dual-core/main.c       |   3 +-
 hw-tests/hello-world/main.c     |   3 +-
 hw-tests/ips/main.c             |   6 +-
 lib/gfx/framebuffer.c           |  18 ++++
 lib/gfx/framebuffer.h           |   1 +
 lib/gfx/gfx.c                   | 153 ++++++++++++++++++--------------
 lib/gfx/gfx.h                   |  14 +--
 pycardium/modules/py/display.py |  38 ++++----
 pycardium/modules/sys_display.c |  56 ++----------
 14 files changed, 228 insertions(+), 211 deletions(-)

diff --git a/bootloader/bootloader-display.c b/bootloader/bootloader-display.c
index d04db551d..9b4b66fb4 100644
--- a/bootloader/bootloader-display.c
+++ b/bootloader/bootloader-display.c
@@ -8,13 +8,12 @@
 
 static void bootloader_display_splash(void)
 {
-	gfx_copy_region(
+	gfx_copy_region_rle_mono(
 		&display_screen,
 		0,
 		0,
 		160,
 		80,
-		GFX_RLE_MONO,
 		sizeof(splash),
 		(const void *)(splash)
 	);
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 2cbe812e4..33edc9e61 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -1652,6 +1652,16 @@ enum disp_font_name {
 	DISP_FONT24 = 4,
 };
 
+/*
+ * Image data type
+ */
+enum epic_rgb_format {
+	EPIC_RGB8     = 0,
+	EPIC_RGBA8    = 1,
+	EPIC_RGB565   = 2,
+	EPIC_RGBA5551 = 3,
+ };
+
 /**
  * Prints a string into the display framebuffer with font type selectable
  *
@@ -1699,22 +1709,22 @@ API(API_DISP_PIXEL, int epic_disp_pixel(
 ));
 
 /**
- * Blit an image buffer to display
+ * Blits an image buffer to the 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.
+ * :param w: Image width
+ * :param h: Image height
+ * :param img: Image data
+ * :param format: Format of the image data. One of :c:type:`epic_rgb_format`.
  */
 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
+	void *img,
+	enum epic_rgb_format format
 ));
 
 /**
diff --git a/epicardium/main.c b/epicardium/main.c
index 270f2b0a8..f4c7d9d94 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -48,14 +48,7 @@ int main(void)
 	epic_disp_clear(0x0000);
 
 	gfx_copy_region(
-		&display_screen,
-		0,
-		0,
-		160,
-		80,
-		GFX_RAW,
-		sizeof(version_splash),
-		version_splash
+		&display_screen, 0, 0, 160, 80, GFX_RGB565, version_splash
 	);
 
 	if (strcmp(CARD10_VERSION, "v1.16") != 0) {
diff --git a/epicardium/modules/display.c b/epicardium/modules/display.c
index d7607a202..05b0eaec1 100644
--- a/epicardium/modules/display.c
+++ b/epicardium/modules/display.c
@@ -92,61 +92,81 @@ int epic_disp_blit(
 	int16_t pos_y,
 	int16_t width,
 	int16_t height,
-	uint16_t *img,
-	uint8_t *alpha
+	void *img,
+	enum epic_rgb_format format
 ) {
-	/* 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;
-		}
+	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;
+	}
+
+	size_t bpp;
+	enum gfx_encoding encoding;
+
+	switch (format) {
+	case EPIC_RGB565:
+		bpp      = 2;
+		encoding = GFX_RGB565;
+		break;
+	case EPIC_RGBA5551:
+		bpp      = 2;
+		encoding = GFX_RGBA5551;
+		break;
+	case EPIC_RGB8:
+		bpp      = 3;
+		encoding = GFX_RGB8;
+		break;
+	case EPIC_RGBA8:
+		bpp      = 4;
+		encoding = GFX_RGBA8;
+		break;
+	default:
+		return -1;
+		break;
+	}
 
-		if (offset_x == 0 && offset_y == 0 && count_x == width &&
-		    count_y == height) {
-			/* Simply copy full image, no cropping or alpha blending */
+	if (offset_x == 0 && offset_y == 0 && count_x == width &&
+	    count_y == height) {
+		/* Copy full image. No cropping.*/
+		gfx_copy_region(
+			&display_screen,
+			pos_x,
+			pos_y,
+			width,
+			height,
+			encoding,
+			img
+		);
+	} else {
+		/* Copy cropped image line by line. */
+		int16_t curr_y;
+		for (curr_y = offset_y; curr_y < offset_y + count_y; curr_y++) {
+			uint8_t *line = img + (curr_y * width + offset_x) * bpp;
 			gfx_copy_region(
 				&display_screen,
-				pos_x,
-				pos_y,
-				width,
-				height,
-				GFX_RAW,
-				width * height * 2,
-				img
+				pos_x + offset_x,
+				pos_y + curr_y,
+				count_x,
+				1,
+				encoding,
+				line
 			);
-		} 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;
 	}
+
+	return 0;
 }
 
 int epic_disp_line(
diff --git a/epicardium/modules/panic.c b/epicardium/modules/panic.c
index ed4575a56..b365b223d 100644
--- a/epicardium/modules/panic.c
+++ b/epicardium/modules/panic.c
@@ -120,13 +120,12 @@ static void faultsplash(const char *msg)
 {
 	LCD_SetBacklight(100);
 
-	gfx_copy_region(
+	gfx_copy_region_rle_mono(
 		&display_screen,
 		0,
 		0,
 		160,
 		80,
-		GFX_RLE_MONO,
 		sizeof(faultsplash_rle),
 		faultsplash_rle
 	);
diff --git a/hw-tests/dual-core/main.c b/hw-tests/dual-core/main.c
index 30026b805..3de7f4715 100644
--- a/hw-tests/dual-core/main.c
+++ b/hw-tests/dual-core/main.c
@@ -28,8 +28,7 @@ int main(void)
 		0,
 		160,
 		80,
-		GFX_RAW,
-		sizeof(Heart),
+		GFX_RGB565,
 		(const void *)(Heart)
 	);
 	gfx_update(&display_screen);
diff --git a/hw-tests/hello-world/main.c b/hw-tests/hello-world/main.c
index 5f2a82aad..39a75e35f 100644
--- a/hw-tests/hello-world/main.c
+++ b/hw-tests/hello-world/main.c
@@ -36,8 +36,7 @@ int main(void)
 		0,
 		160,
 		80,
-		GFX_RAW,
-		sizeof(Heart),
+		GFX_RGB565,
 		(const void *)(Heart)
 	);
 	gfx_update(&display_screen);
diff --git a/hw-tests/ips/main.c b/hw-tests/ips/main.c
index b638a7832..e1ff5fa16 100644
--- a/hw-tests/ips/main.c
+++ b/hw-tests/ips/main.c
@@ -43,8 +43,7 @@ int main(void)
 		0,
 		40,
 		40,
-		GFX_RAW,
-		40 * 40 * 2,
+		GFX_RGB565,
 		(const void *)(gImage_40X40)
 	);
 	gfx_copy_region(
@@ -53,8 +52,7 @@ int main(void)
 		0,
 		160,
 		80,
-		GFX_RAW,
-		160 * 80 * 2,
+		GFX_RGB565,
 		(const void *)(gImage_160X80)
 	);
 	gfx_update(&display_screen);
diff --git a/lib/gfx/framebuffer.c b/lib/gfx/framebuffer.c
index 6c8dc3aac..314f3e2f0 100644
--- a/lib/gfx/framebuffer.c
+++ b/lib/gfx/framebuffer.c
@@ -99,3 +99,21 @@ void fb_setpixel(struct framebuffer *fb, int x, int y, Color c)
 		pixel[0] = color[1];
 	}
 }
+
+Color fb_getpixel(struct framebuffer *fb, int x, int y)
+{
+	uint8_t *pixel = fb_pixel(fb, x, y);
+	if (pixel == NULL)
+		return 0;
+
+	Color c;
+	uint8_t *color   = (uint8_t *)(&c);
+	const size_t bpp = fb_bytes_per_pixel(fb);
+	switch (bpp) {
+	default:
+	case 2:
+		color[0] = pixel[1];
+		color[1] = pixel[0];
+	}
+	return c;
+}
diff --git a/lib/gfx/framebuffer.h b/lib/gfx/framebuffer.h
index e2358c734..0bd0a593a 100644
--- a/lib/gfx/framebuffer.h
+++ b/lib/gfx/framebuffer.h
@@ -27,6 +27,7 @@ struct framebuffer {
 size_t fb_bytes_per_pixel(const struct framebuffer *fb);
 void *fb_pixel(struct framebuffer *fb, int x, int y);
 void fb_setpixel(struct framebuffer *fb, int x, int y, Color c);
+Color fb_getpixel(struct framebuffer *fb, int x, int y);
 void fb_clear_to_color(struct framebuffer *fb, Color c);
 void fb_clear(struct framebuffer *fb);
 Color fb_encode_color_rgb(struct framebuffer *fb, int r, int g, int b);
diff --git a/lib/gfx/gfx.c b/lib/gfx/gfx.c
index 886ecdeeb..172dc9079 100644
--- a/lib/gfx/gfx.c
+++ b/lib/gfx/gfx.c
@@ -13,6 +13,42 @@ const struct gfx_color_rgb gfx_colors_rgb[COLORS] = {
 	{ 255, 255, 0 }    /* YELLOW */
 };
 
+static inline uint16_t rgb8_to_rgb565(const uint8_t *bytes)
+{
+	return ((bytes[0] & 0b11111000) << 8) | ((bytes[1] & 0b11111100) << 3) |
+	       (bytes[2] >> 3);
+}
+
+static inline void rgb565_to_rgb8(uint16_t c, uint8_t *bytes)
+{
+	bytes[0] = (c & 0b1111100000000000) >> 8;
+	bytes[1] = (c & 0b0000011111100000) >> 3;
+	bytes[2] = (c & 0b0000000000011111) << 3;
+}
+
+static inline uint16_t rgba5551_to_rgb565(const uint8_t *bytes)
+{
+	return (bytes[1] << 8) | (bytes[0] & 0b11000000) |
+	       ((bytes[0] & 0b00111110) >> 1);
+}
+
+static inline uint8_t apply_alpha(uint8_t in, uint8_t bg, uint8_t alpha)
+{
+	/* Not sure if it is worth (or even a good idea) to have
+	 * the special cases here. */
+	if (bg == 0) {
+		return (in * alpha) / 255;
+	}
+
+	uint8_t beta = 255 - alpha;
+
+	if (bg == 255) {
+		return ((in * alpha) / 255) + beta;
+	}
+
+	return (in * alpha + bg * beta) / 255;
+}
+
 void gfx_setpixel(struct gfx_region *r, int x, int y, Color c)
 {
 	if (x < 0 || y < 0)
@@ -23,6 +59,25 @@ void gfx_setpixel(struct gfx_region *r, int x, int y, Color c)
 	fb_setpixel(r->fb, r->x + x, r->y + y, c);
 }
 
+void gfx_setpixel_rgba(struct gfx_region *r, int x, int y, const uint8_t *c)
+{
+	if (x < 0 || y < 0)
+		return;
+	if ((size_t)x >= r->width || (size_t)y >= r->height)
+		return;
+
+	uint8_t pixel[3];
+	Color p = fb_getpixel(r->fb, r->x + x, r->y + y);
+	rgb565_to_rgb8(p, pixel);
+
+	uint8_t alpha = c[3];
+	pixel[0]      = apply_alpha(c[0], pixel[0], alpha);
+	pixel[1]      = apply_alpha(c[1], pixel[1], alpha);
+	pixel[2]      = apply_alpha(c[2], pixel[2], alpha);
+
+	fb_setpixel(r->fb, r->x + x, r->y + y, rgb8_to_rgb565(pixel));
+}
+
 struct gfx_region gfx_screen(struct framebuffer *fb)
 {
 	struct gfx_region r = { .fb     = fb,
@@ -270,61 +325,48 @@ Color gfx_color(struct gfx_region *reg, enum gfx_color color)
 	return gfx_color_rgb(reg, c->r, c->g, c->b);
 }
 
-static void gfx_copy_region_raw(
+void gfx_copy_region(
 	struct gfx_region *reg,
 	int x,
 	int y,
 	int w,
 	int h,
-	size_t size,
-	const void *p
+	enum gfx_encoding encoding,
+	const uint8_t *p
 ) {
-	size_t bpp = size / (w * h);
-
 	for (int y_ = 0; y_ < h; y_++) {
 		for (int x_ = 0; x_ < w; x_++) {
 			Color c;
+			uint8_t alpha;
 
-			switch (bpp) {
-			default:
-			case 2:
+			switch (encoding) {
+			case GFX_RGB565:
+				/* Assuming alignment here */
 				c = *(const uint16_t *)(p);
+				gfx_setpixel(reg, x + x_, y + y_, c);
+				p += 2;
+				break;
+			case GFX_RGB8:
+				c = rgb8_to_rgb565(p);
+				gfx_setpixel(reg, x + x_, y + y_, c);
+				p += 3;
+				break;
+			case GFX_RGBA5551:
+				c     = rgba5551_to_rgb565(p);
+				alpha = (*p) & 1;
+				if (alpha) {
+					gfx_setpixel(reg, x + x_, y + y_, c);
+				}
+				p += 2;
+				break;
+			case GFX_RGBA8:
+				gfx_setpixel_rgba(reg, x + x_, y + y_, p);
+				p += 4;
+				break;
+			default:
+				return;
 				break;
 			}
-
-			gfx_setpixel(reg, x + x_, y + y_, c);
-			p += bpp;
-		}
-	}
-}
-
-static void gfx_copy_region_mono(
-	struct gfx_region *reg,
-	int x,
-	int y,
-	int w,
-	int h,
-	size_t size,
-	const void *p
-) {
-	const char *bp = p;
-	int bit        = 0;
-	Color white    = gfx_color(reg, WHITE);
-	Color black    = gfx_color(reg, BLACK);
-
-	for (int y_ = 0; y_ < h; y_++) {
-		for (int x_ = 0; x_ < w; x_++) {
-			int value = *bp & (1 << bit);
-			if (++bit >= 8) {
-				bp++;
-				bit %= 8;
-
-				if ((const void *)(bp) >= (p + size))
-					return;
-			}
-
-			Color c = value ? white : black;
-			gfx_setpixel(reg, x + x_, y + y_, c);
 		}
 	}
 }
@@ -336,7 +378,7 @@ static void gfx_copy_region_mono(
  * significant bit determines the color, the remaining 7 bits determine the
  * amount.
  */
-static void gfx_copy_region_rle_mono(
+void gfx_copy_region_rle_mono(
 	struct gfx_region *reg,
 	int x,
 	int y,
@@ -363,31 +405,6 @@ static void gfx_copy_region_rle_mono(
 	}
 }
 
-void gfx_copy_region(
-	struct gfx_region *reg,
-	int x,
-	int y,
-	int w,
-	int h,
-	enum gfx_encoding encoding,
-	size_t size,
-	const void *p
-) {
-	switch (encoding) {
-	case GFX_RAW:
-		gfx_copy_region_raw(reg, x, y, w, h, size, p);
-		break;
-	case GFX_MONO:
-		gfx_copy_region_mono(reg, x, y, w, h, size, p);
-		break;
-	case GFX_RLE_MONO:
-		gfx_copy_region_rle_mono(reg, x, y, w, h, size, p);
-		break;
-	default:
-		break;
-	}
-}
-
 void gfx_copy_raw(struct gfx_region *reg, const void *p, size_t size)
 {
 	fb_copy_raw(reg->fb, p, size);
diff --git a/lib/gfx/gfx.h b/lib/gfx/gfx.h
index 4c9a16e50..c785b73d8 100644
--- a/lib/gfx/gfx.h
+++ b/lib/gfx/gfx.h
@@ -44,9 +44,12 @@ enum gfx_color {
 };
 
 enum gfx_encoding {
-	GFX_RAW,
+	GFX_RGB565,
 	GFX_MONO,
-	GFX_RLE_MONO
+	GFX_RLE_MONO,
+	GFX_RGB8,
+	GFX_RGBA8,
+	GFX_RGBA5551
 };
 
 struct gfx_color_rgb {
@@ -57,9 +60,10 @@ struct gfx_color_rgb {
 
 Color gfx_color(struct gfx_region *reg, enum gfx_color color);
 
-void gfx_copy_region(struct gfx_region *reg, int x, int y, int w, int h,
-				enum gfx_encoding encoding, size_t size,
-							 const void *p);
+void gfx_copy_region_rle_mono(struct gfx_region *reg, int x, int y, int w, int h,
+						size_t size, const void *p);
+void gfx_copy_region( struct gfx_region *reg, int x, int y, int w, int h,
+						enum gfx_encoding encoding, const uint8_t *p);
 void gfx_copy_raw(struct gfx_region *reg, const void *p, size_t size);
 
 #endif
diff --git a/pycardium/modules/py/display.py b/pycardium/modules/py/display.py
index 1c94d47b3..4884b1e7d 100644
--- a/pycardium/modules/py/display.py
+++ b/pycardium/modules/py/display.py
@@ -8,6 +8,11 @@ FONT16 = 2
 FONT20 = 3
 FONT24 = 4
 
+RGB8 = 0
+RGBA8 = 1
+RGB565 = 2
+RGBA5551 = 3
+
 
 class Display:
     """
@@ -120,7 +125,7 @@ class Display:
         sys_display.pixel(x, y, col)
         return self
 
-    def blit(self, x, y, w, h, img, rgb565=False, alpha=None):
+    def blit(self, x, y, w, h, img, format=RGB8):
         """
         Draws an image on the display.
 
@@ -128,16 +133,20 @@ class Display:
         :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.
+        :param img: Buffer with pixel data
+        :param format: Format of the RGB data. One of ``display.RGB8``, ``
+
+           - ``display.RGB8``: 24 bit RGB.
+           - ``display.RGBA8``: 24 bit RGB + 8 bit alpha.
+           - ``display.RGB565``: 16 bit RGB. This consumes 1 byte less RAM per pixel than ``display.RGB8``.
+           - ``display.RGBA5551``: 15 bit RGB + 1 bit alpha.
+
+           Default is ``display.RGB8``.
 
-        .. note::
-           Alpha mask support is not yet implemented.
 
         .. versionadded:: 1.17
 
-        **Example with RGB data:**
+        **Example with RGB8 data:**
 
         .. code-block:: python
 
@@ -153,7 +162,7 @@ class Display:
                d.update()
 
 
-        **Example with rgb565 data:**
+        **Example with RGB565 data:**
 
         .. code-block:: python
 
@@ -165,7 +174,7 @@ class Display:
            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.blit(10, 10, 32, 20, img, format=display.RGB565)
                d.update()
 
 
@@ -180,20 +189,13 @@ class 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.blit(0, 0, 160, 80, f, format=display.RGB565)
                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)
+        sys_display.blit(x, y, w, h, img, format)
 
         return self
 
diff --git a/pycardium/modules/sys_display.c b/pycardium/modules/sys_display.c
index 37011cae8..60a99aadd 100644
--- a/pycardium/modules/sys_display.c
+++ b/pycardium/modules/sys_display.c
@@ -97,14 +97,11 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
 /* 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]);
+	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]);
+	enum epic_rgb_format format = mp_obj_get_int(args[5]);
 	mp_buffer_info_t img;
 
 	int res = 0;
@@ -114,46 +111,7 @@ static mp_obj_t mp_display_blit(size_t n_args, const mp_obj_t *args)
 		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 (!rgb565) {
-		/* Do not free rgb565 data. It is owned by the caller */
-		m_free(buf);
-	}
+	res = epic_disp_blit(pos_x, pos_y, width, height, img.buf, format);
 
 	if (res < 0) {
 		mp_raise_OSError(-res);
@@ -162,7 +120,7 @@ static mp_obj_t mp_display_blit(size_t n_args, const mp_obj_t *args)
 	return mp_const_none;
 }
 static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
-	display_blit_obj, 5, 6, mp_display_blit
+	display_blit_obj, 6, 6, mp_display_blit
 );
 
 /* set display backlight brightness */
-- 
GitLab