8000 extmod/modframebuf Enable blit between different formats. by peterhinch · Pull Request #7666 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

extmod/modframebuf Enable blit between different formats. #7666

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
15 changes: 11 additions & 4 deletions docs/library/framebuf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,23 @@ Other methods
Shift the contents of the FrameBuffer by the given vector. This may
leave a footprint of the previous colors in the FrameBuffer.

.. method:: FrameBuffer.blit(fbuf, x, y[, key])
.. method:: FrameBuffer.blit(fbuf, x, y, key=-1, palette=None)

Draw another FrameBuffer on top of the current one at the given coordinates.
If *key* is specified then it should be a color integer and the
corresponding color will be considered transparent: all pixels with that
color value will not be drawn.

This method works between FrameBuffer instances utilising different formats,
but the resulting colors may be unexpected due to the mismatch in color
formats.
The *palette* argument enables blitting between FrameBuffers with differing
formats. Typical usage is to render a monochrome or grayscale glyph/icon to
a color display. The *palette* is a FrameBuffer instance whose format is
that of the current FrameBuffer. The *palette* height is one pixel and its
pixel width is the number of colors in the source FrameBuffer. The *palette*
for an N-bit source needs 2**N pixels; the *palette* for a monochrome source
would have 2 pixels representing background and foreground colors. The
application assigns a color to each pixel in the *palette*. The color of the
current pixel will be that of that *palette* pixel whose x position is the
color of the corresponding source pixel.

Constants
---------
Expand Down
11 changes: 9 additions & 2 deletions extmod/modframebuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,11 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
if (n_args > 4) {
key = mp_obj_get_int(args[4]);
}

mp_obj_framebuf_t *palette = MP_OBJ_NULL;
if (n_args > 5 && args[5] != mp_const_none) {
mp_obj_t palette_in = mp_obj_cast_to_native_base(args[5], MP_OBJ_FROM_PTR(&mp_type_framebuf));
palette = MP_OBJ_TO_PTR(palette_in);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mp_obj_cast_to_native_base can return mp_const_none, but that's not the same as MP_OBJ_NULL.

So needs to be

if (palette_in != mp_const_none) {
  palette = MP_OBJ_TO_PTR(palette_in);
}

in order to make the code below work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if I'm being dumb here but I'm afraid I don't understand this.

This check worked if I didn't pass palette or I explicitly passed a palette value None:

if (n_args > 5 && args[5] != mp_const_none)

Are you saying that I need an additional check after the above, or that the above check should only be on n_args and be followed by this subsequent check? I'm not clear about the circumstances in which palette_in is mp_const_none.

if (palette_in != mp_const_none) {
  palette = MP_OBJ_TO_PTR(palette_in);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case that this matters for is if palette is non-None but isn't derived from FrameBuffer.

But I said completely the wrong thing -- mp_obj_cast_to_native_base does actually return MP_OBJ_NULL in this case. Which means the code as you have it is exactly correct. Sorry!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! That's fortuitous as I hadn't considered that case :)

}
if (
(x >= self->width) ||
(y >= self->height) ||
Expand All @@ -514,6 +518,9 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
int cx1 = x1;
for (int cx0 = x0; cx0 < x0end; ++cx0) {
uint32_t col = getpixel(source, cx1, y1);
if (palette != MP_OBJ_NULL) {
col = getpixel(palette, col, 0);
}
if (col != (uint32_t)key) {
setpixel(self, cx0, y0, col);
}
Expand All @@ -523,7 +530,7 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 6, framebuf_blit);

STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
Expand Down
2 changes: 1 addition & 1 deletion lib/pico-sdk
Submodule pico-sdk updated 192 files
2 changes: 1 addition & 1 deletion lib/tinyusb
Submodule tinyusb updated 545 files
35 changes: 35 additions & 0 deletions tests/extmod/framebuf_palette.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Test blit between different color spaces
try:
import framebuf, usys
except ImportError:
print("SKIP")
raise SystemExit

# Monochrome glyph/icon
w = 8
h = 8
cbuf = bytearray(w * h // 8)
fbc = framebuf.FrameBuffer(cbuf, w, h, framebuf.MONO_HLSB)
fbc.line(0, 0, 7, 7, 1)

# RGB565 destination
wd = 16
hd = 16
dest = bytearray(wd * hd * 2)
fbd = framebuf.FrameBuffer(dest, wd, hd, framebuf.RGB565)

wp = 2
bg = 0x1234
fg = 0xF800
pal = bytearray(wp * 2)
palette = framebuf.FrameBuffer(pal, wp, 1, framebuf.RGB565)
palette.pixel(0, 0, bg)
palette.pixel(1, 0, fg)

fbd.blit(fbc, 0, 0, -1, palette)

print(fbd.pixel(0, 0) == fg)
print(fbd.pixel(7, 7) == fg)
print(fbd.pixel(8, 8) == 0) # Ouside blit
print(fbd.pixel(0, 1) == bg)
print(fbd.pixel(1, 0) == bg)
5 changes: 5 additions & 0 deletions tests/extmod/framebuf_palette.py.exp
45BD
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
True
True
True
True
True
0