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
PicoGraphics: Add support for PNG decoding. #802
Conversation
38b64d7
to
1d3b396
Compare
1d3b396
to
1630ddb
Compare
@bitbank2 before I melt my brain looking into this, do you know off the top of your head if you can decode PNG graphics starting from a particular offset? Specific use case would be grabbing portions of a spritesheet. Thank you! |
I did that with my TIFF_G4 library to allow for scaling/decoding huge files into a small device, but I hadn't seen a need with PNG images. It's a good idea to add to a future version :) |
Sooo theoretically possible, then? 👀 😆 |
Certainly possible. It's not hard to selectively use a small area of an image decoded from a larger one. You can already do that with the callback structure I use. You still have to decode the full width of the image, but you can stop decoding when you hit the bottom line of the part you want. |
Ooh, I'd forgotten I can- I think- return a status from the callback function to stop decoding. I was mostly thinking along the lines of scanning ahead in the file to a specific set of coordinates, but I don't know enough about how PNG decompression/decoding works. I should probably handle bounds checking on the drawing area, and it'll make that easier. |
Unfortunately you can't scan ahead in PNG files because each line uses a filter which might be the pixel differences of the line above it. One wrong pixel and the image from that point down is corrupted. There's no concept of "restart markers" like in JPEG. |
Clearly I need to re-read https://ucnv.github.io/pnglitch/ 😆 Thank you! |
c6f2e7c
to
6db7a9a
Compare
One last comment - you can get PNGs to decode with less RAM. If the PNG resultant size is very small, then you won't need a 32k sliding window. Also, you can tell the PNG encoder to use a smaller sliding window and then the decoder will use the same. |
Palette cycling demo for Pico Display 2.0: import time
import pngdec
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2 as DISPLAY, PEN_P8 as PEN
graphics = PicoGraphics(DISPLAY, pen_type=PEN, rotate=0)
png = pngdec.PNG(graphics)
png.open_file("fire.png")
palette = png.get_palette()
graphics.set_pen(0x59)
graphics.clear()
png.decode(0, -10, mode=pngdec.PNG_COPY, scale=(5, 4))
while True:
for offset in (16, 32, 48):
gradient = palette[offset:offset + 12]
gradient.insert(0, gradient.pop())
palette[offset:offset + 12] = gradient
graphics.set_palette(palette)
graphics.update()
time.sleep(1.0 / 30) The fire.png is borrowed from here: https://github.com/32blit/32blit-sdk/blob/master/examples/palette-cycle/assets/fire.png |
Should work roughly the same as JPEGDEC except it uses slightly more RAM and handles indexed PNGs. Maybe need an option to simply copy over the indexes rather than try any palette mapping so you can prepare assets with a specific palette and then just load that palette into P4 or P8 mode.
PNG decoding uses about 47K of RAM. Most of this is the zlib
inflate_state
which is 7K, plus 32K of fixed sliding window buffer inpng_image_tag / ucZLIB
. There might be a way we can - optionally - sacrifice performance for less RAM usage, but I'm not sure.