I'm not sure what you mean? The whole page is about the BMP file format (which I assume is the one OutoftheBOTS_ means when saying 'save it as a BMP file') and only mentions some related formats exist without much further description. Or maybe I'm missing something.
converting png file to bytearray
Re: converting png file to bytearray
-
- Posts: 847
- Joined: Mon Nov 20, 2017 10:18 am
Re: converting png file to bytearray
I have used this little bit of info here http://paulbourke.net/dataformats/bmp/ as a basis for my use of BMP images and so far it has got the job done that I needed without any hiccups.
In the end the original question was for someone to be able to load an image on a epaper screen. I have definitely found the simplest way to do this is from a BMP file again see my example of a 16 bit bmp file being loaded onto a SPI TFT here https://www.youtube.com/watch?v=4OeWaat3jZs and the waveshare wiki also suggest easiest way is using 1 bit BMP file for their epaper screens see https://www.waveshare.com/wiki/1.54inch_e-Paper_Module
In the end the original question was for someone to be able to load an image on a epaper screen. I have definitely found the simplest way to do this is from a BMP file again see my example of a 16 bit bmp file being loaded onto a SPI TFT here https://www.youtube.com/watch?v=4OeWaat3jZs and the waveshare wiki also suggest easiest way is using 1 bit BMP file for their epaper screens see https://www.waveshare.com/wiki/1.54inch_e-Paper_Module
-
- Posts: 847
- Joined: Mon Nov 20, 2017 10:18 am
Re: converting png file to bytearray
I am still waiting for some hardware to arrive so I haven't yet played with a epaper but did do a quick read over the datasheet for the hardware that I plan to use and I remember the epaper do have 2 memory buffers (when reading it I though it was a bit strange). Off memory it had something to do with they way the epaper screens do their update of the image.devnull wrote: ↑Thu May 17, 2018 10:02 amOK, I am now using mono-bitmaps and are able to convert the image to a bytearray using PIL (pillow.image).
I can also write the image (icon) to the screen at whatever position I require, but when I use the writer class to add text next to it, it appears to overwrite the icon, and vice versa.
But if I repeatedly issue the display_frame() function, then the page toggles between just the icon, and the text frames, it almost appears that there are 2 separate pages.
The epaper screens are definitely a bit more complex to use than the TFTs
-
- Posts: 847
- Joined: Mon Nov 20, 2017 10:18 am
Re: converting png file to bytearray
here from the waveshare wiki
the process is: SetFrameMemory --> DisplayFrame --> SetFrameMemory --> DisplayFrame, i.e. set and update twice.
So looking at it you have to write everything twice or you get the problem you haveDisplay a Frame (DisplayFrame)
DisplayFrame is used to display the data from the frame memory.
Note:
The module has two memory areas. Once DisplayFrame is invoked, the following function SetFrameMemory will set the other memory area, e.g. to set all the two memory areas, the process is: SetFrameMemory --> DisplayFrame --> SetFrameMemory --> DisplayFrame, i.e. set and update twice.
The data from SPI interface is first saved into the memory and then updated if the module received the update command.
The module will flicker during full update.
The module won't flicker during partial update, however, it may retain a "ghost image" of the last page.
the process is: SetFrameMemory --> DisplayFrame --> SetFrameMemory --> DisplayFrame, i.e. set and update twice.
Re: converting png file to bytearray
By jpeg byte array, you mean you literally have the image encoded as a jpeg? If so, just dump the bytes to a file and read it back in with
- MostlyHarmless
- Posts: 166
- Joined: Thu Nov 21, 2019 6:25 pm
- Location: Pennsylvania, USA
Re: converting png file to bytearray
Correct me if I'm wrong, but all this sounds like you want to display some pixmap or bitmap via a framebuf interface.
If that assumption is wrong, the following might still help someone else.
But if that is what you are asking, then why not use a framebuf object in the source code right away? To demonstrate what I mean I created this little Smile in my favorite bitmap editor (pinta): Saved that as a .BMP file. Now I convert that into a very old bitmap format (binary PBM file format 'P4' by Jef Poskanzer). That stuff dates back to the 1980's, but the fun here is that the data of that bitmap is arranged EXACTLY as it is in a MONO_HLSB type MicroPython FrameBuffer.
That convert(1) command comes from ImageMagick, a highly recommended toolbox on Unix if you do anything with images at all.
The smile1.pbm file will contain two '\n' terminated lines. The first one identifying the file format 'P4' (monochrome bitmap binary) and the second '<width> <height>' in decimal, space separated. The remaining bytes in that file are the binary bitmap data.
Yeah, I couldn't even draw a perfect circle and note that one pixel on the left cheek is missing ... darn.
Anyhow, that file format is trivial to read, so a rather simple Python script
will convert that smile1.pbm file into the following output:
Now fb_smile1 is a FrameBuffer object, 24x23 pixels in MONO_HLSB format. So the MicroPython script
will produce this display (still missing one pixel on the left cheek):
Is that what you were looking for?
I am sure the same technique could be adopted for display types with more bits per pixel (grayscale or color). Although the conversion might get a bit more complicated than this monochrome example. It might also help to convert the FrameBuffer to the display's native format (the SSD1306 is MONO_VLSB, not MONO_HLSB), but I haven't studied the FrameBuffer C code enough to say for sure.
Regards, Jan
If that assumption is wrong, the following might still help someone else.
But if that is what you are asking, then why not use a framebuf object in the source code right away? To demonstrate what I mean I created this little Smile in my favorite bitmap editor (pinta): Saved that as a .BMP file. Now I convert that into a very old bitmap format (binary PBM file format 'P4' by Jef Poskanzer). That stuff dates back to the 1980's, but the fun here is that the data of that bitmap is arranged EXACTLY as it is in a MONO_HLSB type MicroPython FrameBuffer.
Code: Select all
convert smile1.bmp smile1.pbm
The smile1.pbm file will contain two '\n' terminated lines. The first one identifying the file format 'P4' (monochrome bitmap binary) and the second '<width> <height>' in decimal, space separated. The remaining bytes in that file are the binary bitmap data.
Code: Select all
$ head -2 smile1.pbm
P4
24 23
Anyhow, that file format is trivial to read, so a rather simple Python script
Code: Select all
#!/usr/bin/env python
import sys
import os
def main():
if len(sys.argv) != 2:
usage()
return 2
with open(sys.argv[1], 'rb') as fd:
pbm_format = fd.readline().strip()
if pbm_format != b'P4':
print("ERROR: input file must be binary PBM (type P4)",
file = sys.stderr)
return 1
pbm_dims = [int(d) for d in fd.readline().strip().split()]
pbm_data = fd.read()
fbbase = "fb_{0}".format(os.path.basename(sys.argv[1]))
fbname = os.path.splitext(fbbase)[0]
with sys.stdout as fd:
f = "{0} = framebuf.FrameBuffer(bytearray({1}), {2}, {3}, framebuf.MONO_HLSB)\n"
fd.write(f.format(fbname, str(pbm_data), pbm_dims[0], pbm_dims[1]))
def usage():
print("""usage: {0} PBM_FILE""".format(os.path.basename(sys.argv[0])),
file = sys.stderr)
if __name__ == '__main__':
main()
Code: Select all
fb_smile1 = framebuf.FrameBuffer(bytearray(b'\x00~\x00\x03\xff\xc0\x07\x81\xe0\x1e\x00x8\x00\x1c0\x00\x0c`\x00\x0ea\xc3\x86\xe0\x00\x07\xc0\x00\x03\xc0\x00\x03\xc0\x00\x02\xc0\x00\x03\xc0\x00\x03\xe0B\x07`<\x06`\x00\x060\x00\x0c8\x00\x1c\x1e\x00x\x07\x81\xe0\x03\xff\xc0\x00\xff\x00'), 24, 23, framebuf.MONO_HLSB)
Code: Select all
from machine import I2C, Pin
import ssd1306
import framebuf
i2c = I2C(-1, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
fb_smile1 = framebuf.FrameBuffer(bytearray(b'\x00~\x00\x03\xff\xc0\x07\x81\xe0\x1e\x00x8\x00\x1c0\x00\x0c`\x00\x0ea\xc3\x86\xe0\x00\x07\xc0\x00\x03\xc0\x00\x03\xc0\x00\x02\xc0\x00\x03\xc0\x00\x03\xe0B\x07`<\x06`\x00\x060\x00\x0c8\x00\x1c\x1e\x00x\x07\x81\xe0\x03\xff\xc0\x00\xff\x00'), 24, 23, framebuf.MONO_HLSB)
oled.fill(0)
oled.framebuf.blit(fb_smile1, 0, 20)
oled.text("Hello", 30, 20)
oled.text("MicroPython", 30, 28)
oled.show()
Is that what you were looking for?
I am sure the same technique could be adopted for display types with more bits per pixel (grayscale or color). Although the conversion might get a bit more complicated than this monochrome example. It might also help to convert the FrameBuffer to the display's native format (the SSD1306 is MONO_VLSB, not MONO_HLSB), but I haven't studied the FrameBuffer C code enough to say for sure.
Regards, Jan
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: converting png file to bytearray
Very useful.
If you wanted to take your idea further, your conversion utility could output Python source, like font_to_py and data_to_py. The idea behind these utilities is that, with suitable design of the output format, the Python source can be frozen as bytecode so that the data uses almost no RAM on the target. The key is to use memoryview objects.
There is a significant roadblock when it comes to colour displays.
I use the same technique as you for rendering fonts created using font_to_py: glyphs are rendered to a framebuf then copied to the display's framebuf using the blit method. It's fast and efficient provided your display is monochrome.
Alas there is a problem with colour. The blit method doesn't work properly when the source and destination buffers have different colour maps. This has been discussed several times - a full solution is nontrivial. A restricted solution where a monochrome source is mapped onto a colour destination would work fine for fonts and be easily implemented but my offer to do so was not taken up, presumably because the long term aim is to provide a full solution.
In consequence rendering a mono glyph onto a colour display has to be done pixel-by-pixel.
If you wanted to take your idea further, your conversion utility could output Python source, like font_to_py and data_to_py. The idea behind these utilities is that, with suitable design of the output format, the Python source can be frozen as bytecode so that the data uses almost no RAM on the target. The key is to use memoryview objects.
There is a significant roadblock when it comes to colour displays.
I use the same technique as you for rendering fonts created using font_to_py: glyphs are rendered to a framebuf then copied to the display's framebuf using the blit method. It's fast and efficient provided your display is monochrome.
Alas there is a problem with colour. The blit method doesn't work properly when the source and destination buffers have different colour maps. This has been discussed several times - a full solution is nontrivial. A restricted solution where a monochrome source is mapped onto a colour destination would work fine for fonts and be easily implemented but my offer to do so was not taken up, presumably because the long term aim is to provide a full solution.
In consequence rendering a mono glyph onto a colour display has to be done pixel-by-pixel.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
- MostlyHarmless
- Posts: 166
- Joined: Thu Nov 21, 2019 6:25 pm
- Location: Pennsylvania, USA
Re: converting png file to bytearray
I'd like to, but there are design questions to ponder first.pythoncoder wrote: ↑Thu Dec 26, 2019 7:39 amVery useful.
If you wanted to take your idea further, your conversion utility could output Python source, like font_to_py and data_to_py. The idea behind these utilities is that, with suitable design of the output format, the Python source can be frozen as bytecode so that the data uses almost no RAM on the target. The key is to use memoryview objects.
For number one I am still new to MicroPython. Let's assume freezing for all of the following (bitmaps that eventually make it onto a display once in a while should not be kept in RAM).
I took a look at the courier20.py file, included in your font_to_py. I presume that creating _font=b'...' on the module level creates one dict entry '_font' in RAM on import, but the bytes themselves stay in flash. The memoryview object '_mvfont' then creates another dict entry in RAM, but allows to copy a single glyph into RAM via get_ch() without first loading the entire _font object. Correct?
The next question is how to best make many bitmaps available with minimal resources. In a font the ord of a character translated to an index is a natural choice. However, that will not work for bitmaps as they are more user friendly if referred to by name. I would still like to copy your design in a way, but instead of using the _index data, generate individual functions per bitmap. So given multiple input bitmap files, the utility would create output like:
Code: Select all
_bmdata = b'...'
_mvdata = memoryview(_bmdata)
def get_<filename1>():
return _mvdata[<start>, <end>], <width>, <height>
def get_<filename2>():
return _mvdata[<start>, <end>], <width>, <height>
Another idea is to expand this with "indexed" bitmap versions. Think of a "battery" symbol that has 5 different states. 0%, 25%, 50%, 75% and 100%. It would be very convenient to get the right bitmap with
Code: Select all
mybitmaps.get_battery(round(bat_level / 25))
Supporting color with all this is definitely going to be a challenge. At this point I presume that the Python code has to be generated with a specific target display type, and cannot be converted on the fly on board. Restricting text display to a single color per write is a compromise I can live with. Rendering an actual image that way is not and converting between color spaces per pixel is going to be too CPU expensive.pythoncoder wrote: ↑Thu Dec 26, 2019 7:39 amIn consequence rendering a mono glyph onto a colour display has to be done pixel-by-pixel.
Thanks, Jan
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: converting png file to bytearray
OK so far, butMostlyHarmless wrote: ↑Thu Dec 26, 2019 3:06 pm...I presume that creating _font=b'...' on the module level creates one dict entry '_font' in RAM on import, but the bytes themselves stay in flash. The memoryview object '_mvfont' then creates another dict entry in RAM...
The wonder of a memoryview is allocation-free slicing: the glyph remains in Flash with Python working on pointers into the ROM. RAM use is zero!allows to copy a single glyph into RAM via get_ch() without first loading the entire _font object
I'll think over how to index bitmaps. If you used numeric indices you could, of course, use a simple indexing scheme. Mine which is crafted for managing sparse number spaces; your indices would be contiguous. You could get round the unfriendliness of numbers with named constants. The utility would produce two files, one with Python source and the other with text like:
Code: Select all
_HAPPY = const(0)
_SAD = const(1)
...
You may think this is clunky. I'll think about this some more...
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
- MostlyHarmless
- Posts: 166
- Joined: Thu Nov 21, 2019 6:25 pm
- Location: Pennsylvania, USA
Re: converting png file to bytearray
Even better. I like that!pythoncoder wrote: ↑Thu Dec 26, 2019 4:01 pmThe wonder of a memoryview is allocation-free slicing: the glyph remains in Flash with Python working on pointers into the ROM. RAM use is zero!
The top goal about this design aspect is to conserve resources (RAM primarily). So "clunky" is OK with me.pythoncoder wrote: ↑Thu Dec 26, 2019 4:01 pmI'll think over how to index bitmaps. If you used numeric indices you could, of course, use a simple indexing scheme. Mine which is crafted for managing sparse number spaces; your indices would be contiguous. You could get round the unfriendliness of numbers with named constants. The utility would produce two files, one with Python source and the other with text like:Your user code would include the constants by cutting and pasting the text into your source. The point here is that constants with a leading underscore use no RAM whatsoever. This is because of the Python rule about names with leading underscores, which is the reason why you must cut and paste rather than importing the module.Code: Select all
_HAPPY = const(0) _SAD = const(1) ...
You may think this is clunky. I'll think about this some more...
The thing I don't like about this approach is that with generated code, the numbers associated with a given bitmap tend to change, which will completely mess up the source code that copy/pasted those const() declarations.
This makes two of us thinking more about it.
Thanks a lot, Jan