Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
4b03c99
extmod/modframebuf.c: Add byte-swapped RGB565 format.
corranwebster Nov 14, 2025
eb96c71
tests/extmod/framebuf16_bs.py
corranwebster Nov 14, 2025
19ba0e0
extmod/modframebuf.c: Add RGB565_BS to valid format cases.
corranwebster Nov 17, 2025
845dcad
tests/extmod/framebuf16_bs.py: Correct buffer type.
corranwebster Nov 17, 2025
86ce41d
run-tests.py: Skip framebuf16_bs tests on platforms without slicing.
corranwebster Nov 17, 2025
e197cd4
docs/framebuf.rst: Add documentation for new format.
corranwebster Nov 17, 2025
91cfa99
examples/natmod/framebuf.c: Add RGB565_BS to example native module.
corranwebster Nov 17, 2025
7b66bd1
extmod/modframebuf.c: Reduce codesize.
corranwebster Nov 17, 2025
700085e
extmod/modframbeuf.c: Completely remove byteswapped fill rect.
corranwebster Nov 17, 2025
1948f36
extmod/modframebuf.c: Make RGB565 endianness explicit.
corranwebster Nov 17, 2025
f1f616d
extmod/modframebuf.c: Fix code style
corranwebster Nov 17, 2025
eaf625c
Add blit with alpha mask method.
corranwebster Nov 18, 2025
27d8ccc
Fix code formatting and add ew blit routine to module.
corranwebster Nov 18, 2025
301842d
Try merged version of blit methods.
corranwebster Nov 18, 2025
03eca9d
Add an alpha paramter.
corranwebster Nov 18, 2025
87daa74
Add flag for alpha support.
corranwebster Nov 18, 2025
46de420
Add flags properly; optimize a bit.
corranwebster Nov 18, 2025
1cdd46d
More fixes, make tests pass on unix.
corranwebster Nov 18, 2025
6964f3b
Add a simple test for fixed alpha.
corranwebster Nov 18, 2025
4e3021c
Add more tests.
corranwebster Nov 18, 2025
13e6204
Do something sensible for small masks.
corranwebster Nov 18, 2025
ed78bdf
Fix codestyle.
corranwebster Nov 18, 2025
05b55c9
Attempt to fix problem with mod on ESP8266.
corranwebster Nov 18, 2025
7ce6632
Revert wrapping of masks.
corranwebster Nov 18, 2025
450e04c
Add alpha argument to pixel method.
corranwebster Nov 18, 2025
ea094f5
Properly handle case where no alpha turned on.
corranwebster Nov 18, 2025
8d89f5e
Fix arguments, codestyle.
corranwebster Nov 19, 2025
4e395df
Refactoring; make fill_rect() and pixel() work; tests.
corranwebster Nov 19, 2025
564b857
Add alpha for vline, hline, rect; tests.
corranwebster Nov 19, 2025
c586302
Add alpha for text; tests for same.
corranwebster Nov 19, 2025
324832b
Add a macro for standard alpha args.
corranwebster Nov 19, 2025
3897b79
Refactor macro to remove temp vars in most cases.
corranwebster Nov 19, 2025
0a97e27
Add alpha for ellipses.
corranwebster Nov 19, 2025
1e55a9e
Test turning alpha off, for size.
corranwebster Nov 20, 2025
6e29873
Add alpha for lines and polygons; polygons aren't perfect.
corranwebster Nov 20, 2025
978a246
Restore alpha blending code.
corranwebster Nov 20, 2025
3368af0
Add antialiased lines.
corranwebster Nov 20, 2025
cc00da8
Add A-buffer based polygons; update tests.
corranwebster Nov 20, 2025
e7f5793
Refactor polygon code for speed and clarity.
corranwebster Nov 21, 2025
ed1451e
See if uint16_t has better popcount support.
corranwebster Nov 21, 2025
963ddca
Try 32-bit popcount?
corranwebster Nov 21, 2025
887f4c7
Use micropython's popcount helper.
corranwebster Nov 21, 2025
1fdd84e
Test polygons on low-bit framebuffers and adapt 1-bit rendering.
corranwebster Nov 22, 2025
7ecb61a
Try some things to get failing tests working.
corranwebster Nov 22, 2025
574decf
Use completely self-contained popcount.
corranwebster Nov 23, 2025
24f8f85
Be particular about left shifts of negatives for fixed point.
corranwebster Nov 23, 2025
5e084e7
Code clean-up.
corranwebster Nov 23, 2025
35f98aa
Some more minor clean-up.
corranwebster Nov 23, 2025
231c207
Check codesize when alpha is turned off.
corranwebster Nov 23, 2025
3b3d936
Some more code reorganization; allow 1-bit masks in blit.
corranwebster Nov 23, 2025
4cc8119
Add documentation for the alpha parameter.
corranwebster Nov 23, 2025
9bcc5ee
Re-word for clarity.
corranwebster Nov 23, 2025
a93e411
Refactoring to make comparison easier. Fix some tests.
corranwebster Nov 23, 2025
40e7d14
A few more fixed after refactor.
corranwebster Nov 23, 2025
1897e95
Careful refactoring of alpha application for correctness.
corranwebster Nov 24, 2025
2aa8061
Fix tests and codeformat.
corranwebster Nov 24, 2025
a889490
Fix missing line.
corranwebster Nov 24, 2025
4762175
Merge branch 'feat/RGB565-byteswapped-format' into feat/alpha-minimal
corranwebster Nov 24, 2025
f294739
Add support for RGB565_BS to alpha blending code.
corranwebster Nov 24, 2025
737a9be
Try to square the circle on byteswapped RGB565.
corranwebster Nov 25, 2025
245ed63
Fix corner case of double-drawn ellipse points.
corranwebster Nov 26, 2025
50ae97a
Fix missing formats in case statement, minor style fixes.
corranwebster Nov 26, 2025
d5ea392
Merge branch 'master' into feat/alpha-minimal
corranwebster Nov 26, 2025
64e74c8
Be more careful with 32-bit non-native vs 16-bit non-native.
corranwebster Nov 26, 2025
a51cd7c
Be really precise about byteswapping.
corranwebster Nov 26, 2025
0622bf1
More tweaking.
corranwebster Nov 26, 2025
80cb48c
Make alpha tests endian-independent, other fussing around.
corranwebster Nov 27, 2025
cbf6c22
Fix expected test values.
corranwebster Nov 27, 2025
1787b44
More playing with tests and endianness.
corranwebster Nov 27, 2025
d0bb26d
Fix expected results.
corranwebster Nov 27, 2025
97b9a90
Introspect setting of values in fill.
corranwebster Nov 27, 2025
8978562
Make it clear when doing big vs little endian fill.
corranwebster Nov 27, 2025
4af3cd5
More clarity with big/little calls.
corranwebster Nov 27, 2025
6f1470b
Fix native module; start backing out changes to main module.
corranwebster Nov 27, 2025
f728e2a
Revert to earlier good version.
corranwebster Nov 27, 2025
5542513
Tighten up code, improve documentation.
corranwebster Nov 27, 2025
abe2f5d
Fic error with alpha in 1-bit mask mode. Fix codestyle.
corranwebster Nov 27, 2025
535f6d3
Some builds unhappy with fall-through switch,
corranwebster Nov 27, 2025
2b55b7d
Clean up code comments.
corranwebster Nov 27, 2025
e71650c
Remove some unused variables.
corranwebster Nov 27, 2025
bd36222
extmod/modframebuf: Add tests to improve coverage of framebuf changes.
corranwebster Nov 28, 2025
ea5b147
tests/extmod/framebuf_polygon_alpha: Add tests for offscreen polys.
corranwebster Nov 28, 2025
6d168d6
extmod/modframebuf: Rationalize RGB565 modes.
corranwebster Nov 28, 2025
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
132 changes: 116 additions & 16 deletions docs/library/framebuf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,42 @@ The following methods draw shapes onto the FrameBuffer.

Fill the entire FrameBuffer with the specified color.

.. method:: FrameBuffer.pixel(x, y[, c])
.. method:: FrameBuffer.pixel(x, y[, c, alpha=0xFF])

If *c* is not given, get the color value of the specified pixel.
If *c* is given, set the specified pixel to the given color.

.. method:: FrameBuffer.hline(x, y, w, c)
.. method:: FrameBuffer.vline(x, y, h, c)
.. method:: FrameBuffer.line(x1, y1, x2, y2, c)
The optional *alpha* parameter is a value from 0 to 255 which
indicates the transparency to use when setting the pixel (0 is
completely transparent, 255 is completely opaque). The if not
specified, the pixel is drawn opaquely.

.. method:: FrameBuffer.hline(x, y, w, c[, alpha=0xFF])
.. method:: FrameBuffer.vline(x, y, h, c[, alpha=0xFF])
.. method:: FrameBuffer.line(x1, y1, x2, y2, c[, alpha=0xFF])

Draw a line from a set of coordinates using the given color and
a thickness of 1 pixel. The `line` method draws the line up to
a second set of coordinates whereas the `hline` and `vline`
methods draw horizontal and vertical lines respectively up to
a given length.

.. method:: FrameBuffer.rect(x, y, w, h, c[, f])
The optional *alpha* parameter is a value from 0 to 255 which
indicates the transparency to use when drawing the line. The
default is 255 (completely opaque).

.. method:: FrameBuffer.rect(x, y, w, h, c[, f, alpha=0xFF])

Draw a rectangle at the given location, size and color.
Draw a rectangle at the given location, size, color and transparency.

The optional *f* parameter can be set to ``True`` to fill the rectangle.
Otherwise just a one pixel outline is drawn.

.. method:: FrameBuffer.ellipse(x, y, xr, yr, c[, f, m])
The optional *alpha* parameter is a value from 0 to 255 which
indicates the transparency to use when drawing the rectangle. The
default is 255 (completely opaque).

.. method:: FrameBuffer.ellipse(x, y, xr, yr, c[, f, m, alpha=0xFF])

Draw an ellipse at the given location. Radii *xr* and *yr* define the
geometry; equal values cause a circle to be drawn. The *c* parameter
Expand All @@ -98,7 +111,11 @@ The following methods draw shapes onto the FrameBuffer.
to be drawn, with bit 0 specifying Q1, b1 Q2, b2 Q3 and b3 Q4. Quadrants
are numbered counterclockwise with Q1 being top right.

.. method:: FrameBuffer.poly(x, y, coords, c[, f])
The optional *alpha* parameter is a value from 0 to 255 which
indicates the transparency to use when drawing the ellipse. The
default is 255 (completely opaque).

.. method:: FrameBuffer.poly(x, y, coords, c[, f, alpha=0xFF])

Given a list of coordinates, draw an arbitrary (convex or concave) closed
polygon at the given x, y location using the given color.
Expand All @@ -109,16 +126,23 @@ The following methods draw shapes onto the FrameBuffer.
The optional *f* parameter can be set to ``True`` to fill the polygon.
Otherwise just a one pixel outline is drawn.

The optional *alpha* parameter is a value from 0 to 255 which
indicates the transparency to use when drawing the polygon. The
default is 255 (completely opaque).

Drawing text
------------

.. method:: FrameBuffer.text(s, x, y[, c])
.. method:: FrameBuffer.text(s, x, y[, c, alpha=0xFF])

Write text to the FrameBuffer using the coordinates as the upper-left
corner of the text. The color of the text can be defined by the optional
argument but is otherwise a default value of 1. All characters have
dimensions of 8x8 pixels and there is currently no way to change the font.

The optional *alpha* parameter is a value from 0 to 255 which
indicates the transparency to use when drawing the text. The
default is 255 (completely opaque).

Other methods
-------------
Expand All @@ -128,14 +152,9 @@ 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=-1, palette=None)
.. method:: FrameBuffer.blit(fbuf, x, y, key=-1, palette=None, alpha=0xFF)

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. (If the *palette* is specified then the *key*
is compared to the value from *palette*, not to the value directly from
*fbuf*.)

*fbuf* can be another FrameBuffer instance, or a tuple or list of the form::

Expand All @@ -149,6 +168,12 @@ Other methods
of the tuple/list are the same as the arguments to the constructor except that
the *buffer* here can be read-only.

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. (If the *palette* is specified then the *key*
is compared to the value from *palette*, not to the value directly from
*fbuf*.)

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
Expand All @@ -160,6 +185,16 @@ Other methods
current pixel will be that of that *palette* pixel whose x position is the
color of the corresponding source pixel.

The *alpha* parameter is either a value from 0 to 255 which indicates the
transparency to use when overlaying the buffer, or is a monochrome or
grayscale mask buffer of the same size as the buffer being drawn, indicating
the transparency for each pixel. The mask buffer can either be another
FrameBuffer or a tuple as described above for the *fbuf* parameter. If both
*key* and *alpha* are used, any pixels of the *key* color will be transparent
and the *alpha* value will be ignored for those pixels.

An alpha mask buffer cannot have the RGB565 pixel format.

Constants
---------

Expand Down Expand Up @@ -192,7 +227,29 @@ Constants

.. data:: framebuf.RGB565

Red Green Blue (16-bit, 5+6+5) color format
Red Green Blue (16-bit, 5+6+5, native) color format in native byte-order.

.. data:: framebuf.RGB565_BS

Red Green Blue (16-bit, 5+6+5, non-native) color format. This format uses
color values supplied with a non-native bit-pattern (ie. instead of
``rrrrrggggggbbbbb`` the values are byte-swapped ``gggbbbbbrrrrrggg`` where
the least-significant bits of the green channel occur first). This is a
legacy format to ease migration for the common case of systems which used
displays with an opposite byte-order to microcontroller.

.. data:: framebuf.RGB565_LE

Red Green Blue (16-bit, 5+6+5, little-endian) color format in little-endian
byte order. This defines a 16-bit format where the bytes are stored in
little-endian order. If the system is little-endian, this is the same as
``RGB565``.

.. data:: framebuf.RGB565_BE

Red Green Blue (16-bit, 5+6+5, big-endian) color format in big-endian byte
order. This defines a 16-bit format where the bytes are stored in
big-endian order. If the system is big-endian, this is the same as ``RGB565``.

.. data:: framebuf.GS2_HMSB

Expand All @@ -205,3 +262,46 @@ Constants
.. data:: framebuf.GS8

Grayscale (8-bit) color format

.. data:: framebuf.ALPHA

Whether or not the framebuf module was compiled with support for alpha
values.

If this is False, all alpha parameters will be ignored, lines and
polygons will be rendered with non-anti-aliasing algorithms, and drawing
will be done full opaquely. In the ``framebuf.blit`` method a monochrome
buffer can be used as the *alpha* parameter to provide a binary mask (0
is transparent, 1 is opaque), but other values are ignored or are errors.

If this is True, alpha parameters will act as specified in the descriptions,
anti-aliased algorithms will be used for rendering lines and polygons, and
``framebuf.blit`` can use grayscale masks.

There is currently no support for rendering antialiased ellipses.

.. note::
In Micropython 1.26 and earlier, the RGB565 format did not need
to know aout the internal color channels within each 16-bit value.
As a result, it did not care about the byte-order of the values stored
as pixels. Many display devices use big-endian RGB565, and so code that
used them from little-endian microcontrollers would simply provide colors
as big-endian RGB565 values (ie. using ``0b00000000_11111000`` for red
instead of ``0b11111000_00000000``).

The introduction of support for alpha blending means that the RGB565 format
is assuming native byte-order for the layout of color channels within the
16-bits of a pixel. This breaks code that uses byte-swapped color values,
but it can be adapted either by:

* using firmware compiled with alpha support disabled via the
``MICROPY_PY_FRAMEBUF_ALPHA`` flag; or

* replacing the use of ``RGB565`` format with the byte-swapped
``RGB565_BS`` format; or

* using ``RGB565_BE`` or ``RGB565_LE`` as appropriate for the target
hardware and change color values to use native byte-order.

New code which needs to support buffers of a particular byte-order should
use the last option.
5 changes: 5 additions & 0 deletions examples/natmod/framebuf/framebuf.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_FRAMEBUF (1)
#define MICROPY_PY_FRAMEBUF_ALPHA (1)

#include "py/dynruntime.h"

Expand Down Expand Up @@ -44,11 +45,15 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB));
mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB));
mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565));
mp_store_global(MP_QSTR_RGB565_BS, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565_BS));
mp_store_global(MP_QSTR_RGB565_BE, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565_BE));
mp_store_global(MP_QSTR_RGB565_LE, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565_LE));
mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB));
mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB));
mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8));
mp_store_global(MP_QSTR_MONO_HLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB));
mp_store_global(MP_QSTR_MONO_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB));
mp_store_global(MP_QSTR_ALPHA, MP_OBJ_NEW_SMALL_INT(MICROPY_PY_FRAMEBUF_ALPHA));

MP_DYNRUNTIME_INIT_EXIT
}
Loading
Loading