Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 9 additions & 2 deletions docs/graphics-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Built into `pygraphics` — see the [graphics guide](graphics-guide.md):
| `pygraphics.pbm_to_framebuffer(path)` | PBM (1-bit) |
| `pygraphics.pgm_to_framebuffer(path)` | PGM (grayscale) |
| `pygraphics.load_image(path)` | Auto-detect PBM/PGM/BMP from header |
| `pygraphics.save_image(fb, path)` | Write PBM/PGM/BMP for supported formats |
| `pygraphics.save_image(fb, path)` | Write PBM/PGM/BMP for supported formats, or PNG for a `.png` name |
| `pygraphics.FrameBuffer.from_file(path)` | Same as `load_image` |
| `pygraphics.FrameBuffer.save(path)` | Same as `save_image` |
| `pygraphics.FrameBuffer.export(path)` / `export_framebuffer` | **Pure-Python only.** Write importable `.py` module (`BITMAP = bytearray(...)`) |
Expand All @@ -38,6 +38,8 @@ build, import them from the pure package (`lib/pygraphics/`) instead — see
| `GS4_HMSB` | PGM (P5, max 15) | 4-bit grayscale |
| `GS8` | PGM (P5, max 255) | 8-bit grayscale |
| `RGB565` | BMP | 16-bit RGB565 Windows BMP |
| `RGB888` | PNG | Always PNG |
| `RGB565`, `GS8`, `MONO_HLSB` | PNG | When the name ends in `.png` |

`MONO_VLSB`, `MONO_HMSB`, and other display-native formats are not saved directly — convert or blit to a supported buffer first.

Expand Down Expand Up @@ -71,4 +73,9 @@ From @russhughes st7789py_mpy:

## PNG

Experimental support in utils — probe with [`tools/png_test.py`](https://github.com/PyDevices/pdwidgets/blob/main/tools/png_test.py) in the pdwidgets repo (CPython only; requires sibling pydevices-examples, `pypng`, and a local checkout of [material-design-icons](https://github.com/google/material-design-icons) with its `png/` tree, or `PDWIDGETS_PNG_DIR`).
`save_image(fb, "shot.png")` writes PNG through
[pngio](https://github.com/PyDevices/micropython-pydevices/tree/main/modules/pngio),
not an encoder of pygraphics' own. PyDevices MicroPython firmware has pngio
built in. On CPython it comes with `pydevices-desktop` and needs Pillow
(`pip install pillow`). Without it, saving a PNG raises an `ImportError` that
says what to install. Every other format works without it.
3 changes: 0 additions & 3 deletions lib/pygraphics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@
"pbm_to_framebuffer": ("_files", "pbm_to_framebuffer"),
"pgm_to_framebuffer": ("_files", "pgm_to_framebuffer"),
"save_image": ("_files", "save_image"),
"encode_png": ("_png", "encode_png"),
"write_png_file": ("_png", "write_png_file"),
}


Expand Down Expand Up @@ -128,7 +126,6 @@ def implementation():
"rect",
"round_rect",
"save_image",
"encode_png",
"text",
"text8",
"text14",
Expand Down
40 changes: 36 additions & 4 deletions lib/pygraphics/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
RGB888,
FrameBuffer,
)
from ._png import encode_png, write_png_file

# Framebuffer formats that ``save_image`` can write, keyed by file extension.
_SAVE_FORMATS = {
Expand Down Expand Up @@ -73,6 +72,38 @@ def load_image(filename):
raise ValueError(f"Unsupported image file {filename!r} (header {header!r})")


def _save_png(fb, filename):
"""PNG through pngio: MicroPython's built-in module, or on CPython
pydevices-desktop's, over Pillow. pygraphics has no PNG encoder of its own."""
try:
import pngio
except ImportError:
raise ImportError(
"saving PNG needs pngio: PyDevices MicroPython firmware has it built in; "
"on CPython install pydevices-desktop and Pillow (pip install pillow)"
) from None
w, h = fb.width, fb.height
if fb.format == RGB565:
fmt, buf = pngio.RGB565, fb.buffer
elif fb.format == RGB888:
fmt, buf = pngio.RGB888, fb.buffer
elif fb.format == GS8:
fmt, buf = pngio.GS8, fb.buffer
elif fb.format == MONO_HLSB:
# one bit a pixel, widened to grey
fmt, buf, row = pngio.GS8, bytearray(w * h), (w + 7) // 8
src = fb.buffer
for y in range(h):
for x in range(w):
if (src[y * row + (x >> 3)] >> (7 - (x & 7))) & 1:
buf[y * w + x] = 255
else:
raise ValueError(f"PNG save not supported for format {fb.format}")
data = pngio.PngEncoder().encode(buf, w, h, format=fmt)
with open(filename, "wb") as f:
f.write(data)


def save_image(fb, filename=None):
"""Save a ``FrameBuffer`` to PBM, PGM, BMP, or PNG based on format or filename.

Expand All @@ -83,9 +114,10 @@ def save_image(fb, filename=None):
filename = "screenshot"

file_ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else None
if file_ext == "png":
with open(filename, "wb") as f:
write_png_file(f, fb)
if file_ext == "png" or fb.format == RGB888:
if file_ext != "png":
filename += ".png"
_save_png(fb, filename)
return filename

ext = _SAVE_FORMATS.get(fb.format)
Expand Down
10 changes: 0 additions & 10 deletions lib/pygraphics/_framebuf_plus.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,16 +617,6 @@ def save(self, filename=None):

return _files.save_image(self, filename)

def to_png(self):
"""Encode this framebuffer as standard PNG bytes in memory.

Returns:
bytes: Complete PNG file contents.
"""
from . import _png

return _png.encode_png(self)

def export(self, filename):
"""Export this framebuffer as an importable ``.py`` bitmap module.

Expand Down
237 changes: 0 additions & 237 deletions lib/pygraphics/_png.py

This file was deleted.

1 change: 0 additions & 1 deletion pygraphics.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/_font_8x16.py" = "/lib/pygraphics/_font_8x16.py"
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/_font_8x8.py" = "/lib/pygraphics/_font_8x8.py"
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/_framebuf_plus.py" = "/lib/pygraphics/_framebuf_plus.py"
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/_png.py" = "/lib/pygraphics/_png.py"
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/_shapes.py" = "/lib/pygraphics/_shapes.py"
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/_trig.py" = "/lib/pygraphics/_trig.py"
"https://raw.githubusercontent.com/PyDevices/pygraphics/main/lib/pygraphics/framebuf.py" = "/lib/pygraphics/framebuf.py"
Loading
Loading