Family Photos vs 256 Kb RAM(laplab.me)
laplab.me
Family Photos vs 256 Kb RAM
https://laplab.me/posts/family-photos-vs-256-kb-ram/
26 comments
> Our examples show large JPEGs being loaded in MicroPython no problem. For example this one from our examples is 100kB:
A 100kB JPEG is hardly a "large" JPEG in 2023. From the linked sales page (https://shop.pimoroni.com/products/inky-frame-5-7?variant=40...) the first line of the description states:
"A large Pico W powered E Ink® photo frame ..."
From this, many are going to assume that they can simply load JPEG photo files from their cell phone and/or camera directly onto the device. JPEG photos from my cell phone range anywhere from 1Meg to 7-8Meg depending upon the scene being photographed. All of those photos begin at a compressed size substantially larger than 256Kbyte. This is the size JPEG that someone is going to think that a "photo frame" can process and display.
Additionally, the pixel resolution of the e-ink is stated as "600 x 448 pixels" (same sales page). Again due to the "photo frame" advertising, even if someone took their JPEG photos and scaled them down to 600x448, they would not likely also quantize to 7 colors at the same time (unless your docs give them very clear instructions to do so somewhere). So they would end up with a RGB 600x448 image, and 600 * 448 * 3 is 806,400 bytes just to hold the uncompressed bitmap from a JPEG of that pixel resolution and 3 bytes per pixel. That size is a bit over three times the amount of RAM quoted for the PI (256kB).
A 100kB JPEG is hardly a "large" JPEG in 2023. From the linked sales page (https://shop.pimoroni.com/products/inky-frame-5-7?variant=40...) the first line of the description states:
"A large Pico W powered E Ink® photo frame ..."
From this, many are going to assume that they can simply load JPEG photo files from their cell phone and/or camera directly onto the device. JPEG photos from my cell phone range anywhere from 1Meg to 7-8Meg depending upon the scene being photographed. All of those photos begin at a compressed size substantially larger than 256Kbyte. This is the size JPEG that someone is going to think that a "photo frame" can process and display.
Additionally, the pixel resolution of the e-ink is stated as "600 x 448 pixels" (same sales page). Again due to the "photo frame" advertising, even if someone took their JPEG photos and scaled them down to 600x448, they would not likely also quantize to 7 colors at the same time (unless your docs give them very clear instructions to do so somewhere). So they would end up with a RGB 600x448 image, and 600 * 448 * 3 is 806,400 bytes just to hold the uncompressed bitmap from a JPEG of that pixel resolution and 3 bytes per pixel. That size is a bit over three times the amount of RAM quoted for the PI (256kB).
I used 100kB as an example purely because it was in the ball park of the images talked about in the article - not because it's a hard limit!
Inky Frame has an SD card slot on board which can store huge images if needed. JPEG also can be decoded in chunks so there is never any need to store the entire image in memory, simply scale and encode the chunks and store the result in the framebuffer - in principle there is nothing stopping you displaying multi megabyte images on Inky Frame.
You do seem to misunderstand our product range - it is targeted at Makers who want to take the base hardware and modify the software (and possibly to some degree the hardware) to create their own inventions and scratch their own itches. It's not really mass market stuff where you straight up plug and play.
Inky Frame has an SD card slot on board which can store huge images if needed. JPEG also can be decoded in chunks so there is never any need to store the entire image in memory, simply scale and encode the chunks and store the result in the framebuffer - in principle there is nothing stopping you displaying multi megabyte images on Inky Frame.
You do seem to misunderstand our product range - it is targeted at Makers who want to take the base hardware and modify the software (and possibly to some degree the hardware) to create their own inventions and scratch their own itches. It's not really mass market stuff where you straight up plug and play.
Exactly! You'll be downvoted for pointing that out though...
The "many" you refer to is disingenuous, the target market for "send photos from phone to frame" isn't the same target market as "get hacky e-ink display and boot up micropython" ...
They clearly show the product (named Frame) displaying photos. Ergo, photo frame. The fact that you're trying to frame the Inky Frame as the equivalent of some underspecced 1080p screen or tablet used as a frame is mendacious and unreasonable.
It's as much a "plug in to micropython and learn to do stuff with it" product as any of the other e-ink frames or badges that Pimoroni sells -- it's absolutely not the sort of product you'd find at a supermarket, or buy for your grandmother to put photos on.
Docs and Github examples by Pimoroni are pretty darn clear and well-written, not to mention having YouTube videos and customer support available too.
It's worth noting that OP's conclusion includes, "I am pretty happy with how this project turned out" -- and that they admit they're unsure of who the target market is (suggesting they made similar incorrect assumptions as you).
They clearly show the product (named Frame) displaying photos. Ergo, photo frame. The fact that you're trying to frame the Inky Frame as the equivalent of some underspecced 1080p screen or tablet used as a frame is mendacious and unreasonable.
It's as much a "plug in to micropython and learn to do stuff with it" product as any of the other e-ink frames or badges that Pimoroni sells -- it's absolutely not the sort of product you'd find at a supermarket, or buy for your grandmother to put photos on.
Docs and Github examples by Pimoroni are pretty darn clear and well-written, not to mention having YouTube videos and customer support available too.
It's worth noting that OP's conclusion includes, "I am pretty happy with how this project turned out" -- and that they admit they're unsure of who the target market is (suggesting they made similar incorrect assumptions as you).
Worth noting that many of these low spec screens allow you to read pixels back.
Ie. you can write pixels direct to the screen (one at a time, or sometimes in blocks), and use the screen itself as your framebuffer. Some screens then have a "go" command that will do the actual refresh when you say so.
If you so wish, you can use the screen itself as scratch space for code, data, or partially rendered stuff and the user won't see it.
Often to find out about this stuff you'll need to go deep into the datasheets - you probably won't find the supplied libraries cover it.
I think screen manufacturers do this because they need to have a framebuffer anyway (depending on the screen technology), and they want devices to be able to use their big screens even if they have tiny microcontrollers.
Ie. you can write pixels direct to the screen (one at a time, or sometimes in blocks), and use the screen itself as your framebuffer. Some screens then have a "go" command that will do the actual refresh when you say so.
If you so wish, you can use the screen itself as scratch space for code, data, or partially rendered stuff and the user won't see it.
Often to find out about this stuff you'll need to go deep into the datasheets - you probably won't find the supplied libraries cover it.
I think screen manufacturers do this because they need to have a framebuffer anyway (depending on the screen technology), and they want devices to be able to use their big screens even if they have tiny microcontrollers.
It's common for the lowest power sleep mode of a chip to not maintain RAM.
That means whenever you sleep(1 minute) in the code, the system gets entirely restarted.
Yes, it's inconvenient, but the benefit is you can sleep for years on a tiny battery. As a programmer, all you need to do is save a few flags of state to persistent memory - eg. EEPROM, and then at startup check those flags to return to whatever task you should be doing.
You should check how often you'll be doing this - because EEPROM typically can only be programmed 1000 - 100,000 times in the lifetime of the device. So you might need a cleverer scheme where the first byte of eeprom is a pointer to another place where you store the actual state. Whenever the area of memory where you store the state starts to fail, you change the pointer to a new location.
That means whenever you sleep(1 minute) in the code, the system gets entirely restarted.
Yes, it's inconvenient, but the benefit is you can sleep for years on a tiny battery. As a programmer, all you need to do is save a few flags of state to persistent memory - eg. EEPROM, and then at startup check those flags to return to whatever task you should be doing.
You should check how often you'll be doing this - because EEPROM typically can only be programmed 1000 - 100,000 times in the lifetime of the device. So you might need a cleverer scheme where the first byte of eeprom is a pointer to another place where you store the actual state. Whenever the area of memory where you store the state starts to fail, you change the pointer to a new location.
There are often some RTC registers that get preserved during standby, so you can use that instead of flash or EEPROM.
Main reason for the 56 bytes or whatever above the clock and calendar register :P
You cannot turn this buffer off, probably because writing the stream of bytes into the eInk screen directly is a very nich use case.
Is it? IMHO that's one of the biggest advantages of EPDs like eInk --- you don't need a framebuffer, since the display itself is a "write-only memory" and only needs lines shifted into it.
On the other hand, I suspect EPD companies try to keep the low-level details (like driving waveforms) secret because that's a large part of their IP. They want to be able to sell controllers for them too.
The most unfortunate part is that line-based JPEG decoding and even downscaling is a solved problem, but the bloat of today's software and comparatively limitless computing resources seems to have lead us to forget how to write software efficiently.
Is it? IMHO that's one of the biggest advantages of EPDs like eInk --- you don't need a framebuffer, since the display itself is a "write-only memory" and only needs lines shifted into it.
On the other hand, I suspect EPD companies try to keep the low-level details (like driving waveforms) secret because that's a large part of their IP. They want to be able to sell controllers for them too.
The most unfortunate part is that line-based JPEG decoding and even downscaling is a solved problem, but the bloat of today's software and comparatively limitless computing resources seems to have lead us to forget how to write software efficiently.
> On the other hand, I suspect EPD companies try to keep the low-level details (like driving waveforms) secret because that's a large part of their IP. They want to be able to sell controllers for them too.
Could you share what evidence this is based on?
Could you share what evidence this is based on?
OP is using Berkeley Mono[1]—first time I've seen a paid typeface on a blog.
[1]: https://berkeleygraphics.com/typefaces/berkeley-mono/
[1]: https://berkeleygraphics.com/typefaces/berkeley-mono/
These are the kinds of issues I've been working on solving with my code libraries. My JPEG decoder only needs about 22K of RAM and my e-ink code can work incrementally to write the image in strips.
https://github.com/bitbank2/JPEGDEC
https://github.com/bitbank2/OneBitDisplay
Let me know if I can help...
https://github.com/bitbank2/JPEGDEC
https://github.com/bitbank2/OneBitDisplay
Let me know if I can help...
Regarding slowness, are there no better primitives available here than setBitByIndex and set_pixel? You end up doing lots of calls per pixel, reading bytes, modifying some bits in them, writing the bytes back over and over.
For example, if you worked on monochrome bitplanes (8 pixels per byte) for each of R, G and B, you would handle 8 pixels at a time by just writing the 3 bytes. IFF ILBM is a file format (supported e.g. by ImageMagick) for sharing such image data: https://en.wikipedia.org/wiki/ILBM
For example, if you worked on monochrome bitplanes (8 pixels per byte) for each of R, G and B, you would handle 8 pixels at a time by just writing the 3 bytes. IFF ILBM is a file format (supported e.g. by ImageMagick) for sharing such image data: https://en.wikipedia.org/wiki/ILBM
I wonder how this differs from inkplate. I bought a inkplate 2 just for fun and received it yesterday, and I was flabbergasted at how long it took to clear the screen. I mean it flashes the screen well over 20 times... I can't imagine thats really required. I just want to basically display some temperatures from my Home Assistant instead of from my standard wireless thermometer, on a bigger display.
I love my “old” Inky Impression, just to add some positivity. Just a few days added some new images and posted pictures on Twitter: https://twitter.com/berenguel/status/1662857260043829250
Looks nice, you might get also want to try out error diffusion dithering for a better result.
It takes some time to decode, but I can grab- for example- this 259k JPEG: http://placekitten.com/3840/2160
And display it from the microSD card with this code: https://gist.github.com/Gadgetoid/0b8e352e377135d743338c9483...
As more or less demonstrated by this example: https://github.com/pimoroni/pimoroni-pico/blob/main/micropyt...
Decoding is done via Larry Bank's JPEGDEC: https://github.com/bitbank2/JPEGDEC
It uses roughly 20k RAM to provide the necessary buffers both for decoding JPEGs into blocks which are passed to a drawing routine that handles copying the data into the display RAM buffer (on our larger Inky display this is backed by PSRAM). I don't believe there's a hard limit to the size of the JPEGs you can display. The main bottlenecks are decoding time and the relatively limited scaling options: FULL, HALF, QUARTER, EIGHTH.
This aside, the authors solution is actually quite elegant. As long as you have control over the image pipeline there's no real reason to encumber the device with handling large (both in bytes and pixel dimensions) files. You'll also get much better dithering results writing your own routine to convert files from JPG to the raw 4-bits per pixel format for the display. Our built-in dithering is just a plain ordered dither matrix and, while quaint and retro, it leaves much to be desired visually.
If you're trying to use a public API you can also make GitHub actions automate the whole image conversion process and publish the results to GitHub pages. This works great for, for example, the daily XKCD, serving both to reformat the strip for the display, credit the author, extract the "alt" text and avoid excess requests to the origin. Eg: https://pimoroni.github.io/feed2image/xkcd-800x480-daily.jpg. Though the astute will notice I still opted for jpeg in this case.
And display it from the microSD card with this code: https://gist.github.com/Gadgetoid/0b8e352e377135d743338c9483...
As more or less demonstrated by this example: https://github.com/pimoroni/pimoroni-pico/blob/main/micropyt...
Decoding is done via Larry Bank's JPEGDEC: https://github.com/bitbank2/JPEGDEC
It uses roughly 20k RAM to provide the necessary buffers both for decoding JPEGs into blocks which are passed to a drawing routine that handles copying the data into the display RAM buffer (on our larger Inky display this is backed by PSRAM). I don't believe there's a hard limit to the size of the JPEGs you can display. The main bottlenecks are decoding time and the relatively limited scaling options: FULL, HALF, QUARTER, EIGHTH.
This aside, the authors solution is actually quite elegant. As long as you have control over the image pipeline there's no real reason to encumber the device with handling large (both in bytes and pixel dimensions) files. You'll also get much better dithering results writing your own routine to convert files from JPG to the raw 4-bits per pixel format for the display. Our built-in dithering is just a plain ordered dither matrix and, while quaint and retro, it leaves much to be desired visually.
If you're trying to use a public API you can also make GitHub actions automate the whole image conversion process and publish the results to GitHub pages. This works great for, for example, the daily XKCD, serving both to reformat the strip for the display, credit the author, extract the "alt" text and avoid excess requests to the origin. Eg: https://pimoroni.github.io/feed2image/xkcd-800x480-daily.jpg. Though the astute will notice I still opted for jpeg in this case.
Cool use case. The kerning on that alt text would drive me crazy though.
So much effort for what?
Precompute the jpeg to eink bitstream and store that directly on flash. Write a program that converts the jpeg to what the eink display protocol wants to recv and store that.
Then stream this "image" format directly into the display, problem solved.
cat eink.protocol.bin > /dev/eink
Precompute the jpeg to eink bitstream and store that directly on flash. Write a program that converts the jpeg to what the eink display protocol wants to recv and store that.
Then stream this "image" format directly into the display, problem solved.
cat eink.protocol.bin > /dev/eink
Looks like Dunmore head (Kerry, Ireland) in the photo
https://www.flickr.com/photos/missus_magik/9982718923/
Does cranking the compression down not get you small enough? I think cranking the compression down can get the image to a very small file size (at the expense of looking terrible).
That seems good,Good job!
Great read.
I feel like something is missing here but I don't know what.
Our examples show large JPEGs being loaded in MicroPython no problem. For example this one from our examples is 100kB: https://github.com/pimoroni/pimoroni-pico/blob/main/micropyt...
During testing I worked with many images that were larger than that and never ran into issues either. I think the examples provided are pretty clear and demonstrate how to use the product reasonably.
We focus on MicroPython because the C++ SDK for connectivity is pretty gnarly for most people to work with - it is our intention you should never have to leave MicroPython to use this product.
No idea what the battery issue could be but I've never heard of any problem like that before and we've shipped thousands of this product over the past year. We'd be happy to get the unit back and test it for you if you want - or just replace it!
Please drop me a line if you want to discuss these issues further and I'll do my best to help!