Skip to content

Implement filters for indexed PNG #98

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

Merged
merged 2 commits into from
Feb 21, 2025
Merged
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
44 changes: 40 additions & 4 deletions adafruit_imageload/png.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import struct
import zlib

__version__ = "0.0.0-auto.0"
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"


Expand Down Expand Up @@ -106,20 +106,56 @@ def load( # noqa: PLR0912, PLR0915, Too many branches, Too many statements
if mode == 3: # indexed
bmp = bitmap(width, height, 1 << depth)
pixels_per_byte = 8 // depth
src = 1
src_b = 1
src = 0
pixmask = (1 << depth) - 1
line = bytearray(scanline)
prev = bytearray(scanline)
for y in range(height):
filter_ = data_bytes[src]
src_b = src + 1
for x in range(0, width, pixels_per_byte):
# relative position on the line
pos = x // pixels_per_byte
byte = data_bytes[src_b]
if filter_ == 0:
pass
elif filter_ == 1: # sub
prev_b = line[pos - unit] if pos >= unit else 0
byte = (byte + prev_b) & 0xFF
elif filter_ == 2: # up
byte = (byte + prev[pos]) & 0xFF
elif filter_ == 3: # average
prev_b = line[pos - unit] if pos >= unit else 0
byte = (byte + (prev_b + prev[pos]) // 2) & 0xFF
elif filter_ == 4: # paeth
a = line[pos - unit] if pos >= unit else 0
if y > 0:
b = prev[pos]
c = prev[pos - unit] if pos >= unit else 0
else:
b = c = 0
p = a + b - c
pa = abs(p - a)
pb = abs(p - b)
pc = abs(p - c)
if pa <= pb and pa <= pc:
p = a
elif pb <= pc:
p = b
else:
p = c
byte = (byte + p) & 0xFF
else:
raise ValueError("Wrong filter.")
line[pos] = byte
for pixel in range(pixels_per_byte):
if x + pixel < width:
bmp[x + pixel, y] = (
byte >> ((pixels_per_byte - pixel - 1) * depth)
) & pixmask
src_b += 1
src += scanline + 1
src_b = src
prev, line = line, prev
return bmp, pal
# RGB, RGBA or Grayscale
import displayio
Expand Down