Pure Python library for saving and loading PNG images without external dependencies
—
Comprehensive PNG decoding capabilities with format conversion, chunk access, and metadata extraction. The Reader class supports all PNG color types and bit depths with automatic format detection and conversion options.
The Reader class provides the primary interface for reading PNG files from various sources including files, file objects, and byte data.
class Reader:
def __init__(self, _guess=None, filename=None, file=None, bytes=None):
"""
Initialize PNG reader from file, file object, or bytes.
Parameters:
- filename: str, path to PNG file
- file: file-like object with PNG data
- bytes: bytes object containing PNG data
- _guess: deprecated, for internal use
"""
def read(self, lenient=False):
"""
Read PNG file and return image data.
Parameters:
- lenient: bool, whether to ignore some PNG specification violations
Returns:
tuple: (width, height, rows, info) where:
- width: int, image width in pixels
- height: int, image height in pixels
- rows: iterator of pixel rows
- info: dict with PNG metadata
"""
def read_flat(self):
"""
Read PNG into single flat array.
Returns:
tuple: (width, height, pixels, info) where pixels is 1D array
"""Convert PNG data to specific color formats regardless of the original PNG color type.
def asRGB(self):
"""
Convert image to RGB format (3 values per pixel).
Returns:
tuple: (width, height, rows, info) with RGB pixel data
"""
def asRGBA(self):
"""
Convert image to RGBA format (4 values per pixel).
Returns:
tuple: (width, height, rows, info) with RGBA pixel data
"""
def asRGB8(self):
"""
Convert to RGB with 8-bits per sample.
Returns:
tuple: (width, height, rows, info) with 8-bit RGB data
"""
def asRGBA8(self):
"""
Convert to RGBA with 8-bits per sample.
Returns:
tuple: (width, height, rows, info) with 8-bit RGBA data
"""
def asDirect(self):
"""
Return direct array representation without palette indirection.
Returns:
tuple: (width, height, rows, info) with direct color values
"""Extract and manipulate color palettes from palette-based PNG images.
def palette(self, alpha='natural'):
"""
Extract palette as RGB or RGBA tuples.
Parameters:
- alpha: str, how to handle alpha channel ('natural', 'force', 'remove')
Returns:
list: RGB 3-tuples or RGBA 4-tuples
"""Direct access to PNG chunks for advanced PNG manipulation and metadata extraction.
def chunk(self, lenient=False):
"""
Read next PNG chunk.
Parameters:
- lenient: bool, whether to ignore specification violations
Returns:
tuple: (chunk_type, chunk_data) or None if no more chunks
"""
def chunks(self):
"""
Iterator over all PNG chunks.
Yields:
tuple: (chunk_type, chunk_data) for each chunk
"""
def preamble(self, lenient=False):
"""
Read PNG header and return image metadata.
Parameters:
- lenient: bool, whether to ignore specification violations
Returns:
dict: PNG header information (width, height, bit depth, etc.)
"""import png
# Read from file
reader = png.Reader(filename='image.png')
width, height, rows, info = reader.read()
# Process pixel data
for row in rows:
# Each row is an array of pixel values
print(f"Row has {len(row)} values")import png
# Read PNG and convert to specific format
reader = png.Reader(filename='palette_image.png')
width, height, rows, info = reader.asRGBA()
# Now all pixels are RGBA regardless of original format
for row in rows:
# Each pixel has 4 values: R, G, B, A
pixels = list(row)
for i in range(0, len(pixels), 4):
r, g, b, a = pixels[i:i+4]
print(f"Pixel: R={r}, G={g}, B={b}, A={a}")import png
# Extract palette from palette-based PNG
reader = png.Reader(filename='palette_image.png')
palette = reader.palette()
print(f"Palette has {len(palette)} colors:")
for i, color in enumerate(palette):
if len(color) == 3:
r, g, b = color
print(f"Color {i}: RGB({r}, {g}, {b})")
else:
r, g, b, a = color
print(f"Color {i}: RGBA({r}, {g}, {b}, {a})")import png
# Examine PNG chunks
reader = png.Reader(filename='image.png')
for chunk_type, chunk_data in reader.chunks():
print(f"Chunk: {chunk_type}, Size: {len(chunk_data)} bytes")
# Handle specific chunk types
if chunk_type == b'tEXt':
# Text chunk contains key-value metadata
text_data = chunk_data.decode('latin1')
print(f"Text: {text_data}")
elif chunk_type == b'gAMA':
# Gamma chunk
gamma = int.from_bytes(chunk_data, 'big') / 100000.0
print(f"Gamma: {gamma}")Install with Tessl CLI
npx tessl i tessl/pypi-pypng