extend framebuf.blit method with parameters to select a rectangle from the source
I am trying to implement font rendering. I have loaded a single bitmap of all letters, and now I want to blit each letter to the destination. However, there is currently no framebuf method for blitting a partial framebuf.
Currently its blit(fbuf, x, y, [key])
I suggest blit(fbuf, x, y, [key], [sx,sy,sw,sh]) although I'm not clear on whether width & height are better than right and bottom.
It would bring major performance gains to do partial blitting in C over Python, and I don't want to allocate a tiny framebuf for every letter of the alphabet.
extmod/modframebuf: Add support for blit'ing read-only data.
Summary
Currently the FrameBuffer.blit(buf, x, y) method requires the buf argument to be another FrameBuffer, which is quite restrictive because it doesn't allow blit'ing read-only memory/data.
This PR extends blit() to allow the buf argument to be a tuple or list of the form:
(buffer, width, height, format[, stride])
where buffer can be anything with the buffer protocol and may be read-only, eg bytes.
Also, the palette argument to blit() may be of the same form.
The form of this tuple/list was chosen to be the same as the signature of the FrameBuffer constructor (that saves quite a bit of code size doing it that way).
Testing
A test is added to CI that tests this new capability.
Trade-offs and Alternatives
This is an alternative to #15285, which added a new StaticBuffer type that was a FrameBuffer without any methods and could have a read-only buffer.
The advantage of the approach in this PR is:
- It's smaller code size.
- It doesn't require creating a new
StaticBufferobject each time the underlying data changes, because one can use a list and change its elements each time the data/width/height changes. Eg when drawing text using a custom font, a single 4-list object can be created at the start and reused for each character. That allows drawing text with the font stored in ROM without allocating any extra memory.
The disadvantage of this PR is:
- It's arguably less Pythonic, it would probably be more ergonomic to have a new
StaticBuffertype rather than a tuple. - It uses a little more C stack in the blit code, because the source and palette frame buffer objects are now full struct's, not pointers to structs.