Pure Python library for saving and loading PNG images without external dependencies
—
Comprehensive PNG encoding capabilities with full format control, metadata support, and optimization options. The Writer class handles all PNG color types, bit depths, and optional chunks for professional-quality PNG creation.
The Writer class provides complete control over PNG creation with extensive format and metadata options.
class Writer:
def __init__(self, width=None, height=None, size=None, greyscale=Default,
alpha=False, bitdepth=8, palette=None, transparent=None,
background=None, gamma=None, compression=None, interlace=False,
planes=None, colormap=None, maxval=None, chunk_limit=2**20,
x_pixels_per_unit=None, y_pixels_per_unit=None, unit_is_meter=False):
"""
Initialize PNG writer with format and metadata options.
Parameters:
- width, height: int, image dimensions in pixels
- size: tuple, alternative way to specify (width, height)
- greyscale: bool or Default, whether to create greyscale image
- alpha: bool, whether to include alpha channel
- bitdepth: int, bits per sample (1, 2, 4, 8, 16)
- palette: list, RGB or RGBA tuples for palette images
- transparent: color value or index for transparency
- background: color value for default background
- gamma: float, gamma correction value
- compression: int, zlib compression level (0-9)
- interlace: bool, whether to use Adam7 interlacing
- planes: int, deprecated, use greyscale and alpha instead
- colormap: dict, deprecated, use palette instead
- maxval: int, maximum pixel value for scaling
- chunk_limit: int, maximum chunk size in bytes
- x_pixels_per_unit, y_pixels_per_unit: int, resolution information
- unit_is_meter: bool, whether resolution units are meters (vs. unknown)
"""Multiple methods for writing PNG data from different Python data structures.
def write(self, outfile, rows):
"""
Write PNG from row iterator.
Parameters:
- outfile: file-like object opened in binary write mode
- rows: iterable of pixel rows, each row is sequence of pixel values
"""
def write_array(self, outfile, pixels):
"""
Write PNG from 2D array or nested sequences.
Parameters:
- outfile: file-like object opened in binary write mode
- pixels: 2D array-like structure of pixel data
"""
def write_packed(self, outfile, rows):
"""
Write PNG from pre-packed byte rows.
Parameters:
- outfile: file-like object opened in binary write mode
- rows: iterable of byte strings representing packed pixel rows
"""
def write_passes(self, outfile, rows):
"""
Write PNG with interlacing support.
Parameters:
- outfile: file-like object opened in binary write mode
- rows: iterable of pixel rows for interlaced writing
"""import png
# Create a simple RGB image
width, height = 256, 256
pixels = []
# Generate gradient pattern
for y in range(height):
row = []
for x in range(width):
# RGB gradient
r = (x * 255) // width
g = (y * 255) // height
b = 128
row.extend([r, g, b])
pixels.append(row)
# Write PNG
writer = png.Writer(width=width, height=height, greyscale=False)
with open('gradient.png', 'wb') as f:
writer.write_array(f, pixels)import png
# Create greyscale image
width, height = 100, 100
pixels = []
for y in range(height):
row = []
for x in range(width):
# Simple checkerboard pattern
if (x // 10 + y // 10) % 2:
grey = 255 # White
else:
grey = 0 # Black
row.append(grey)
pixels.append(row)
# Write greyscale PNG
writer = png.Writer(width=width, height=height, greyscale=True, bitdepth=8)
with open('checkerboard.png', 'wb') as f:
writer.write_array(f, pixels)import png
# Create RGBA image with transparency
width, height = 64, 64
pixels = []
for y in range(height):
row = []
for x in range(width):
# Create a circle with alpha blending
center_x, center_y = width // 2, height // 2
distance = ((x - center_x) ** 2 + (y - center_y) ** 2) ** 0.5
if distance < width // 3:
# Inside circle - solid color
r, g, b, a = 255, 100, 50, 255
elif distance < width // 2:
# Edge of circle - fade out
alpha = int(255 * (1 - (distance - width//3) / (width//2 - width//3)))
r, g, b, a = 255, 100, 50, alpha
else:
# Outside circle - transparent
r, g, b, a = 0, 0, 0, 0
row.extend([r, g, b, a])
pixels.append(row)
# Write RGBA PNG
writer = png.Writer(width=width, height=height, greyscale=False, alpha=True)
with open('circle_alpha.png', 'wb') as f:
writer.write_array(f, pixels)import png
# Define color palette
palette = [
(255, 0, 0), # Red
(0, 255, 0), # Green
(0, 0, 255), # Blue
(255, 255, 0), # Yellow
(255, 0, 255), # Magenta
(0, 255, 255), # Cyan
(255, 255, 255), # White
(0, 0, 0) # Black
]
# Create image using palette indices
width, height = 32, 32
pixels = []
for y in range(height):
row = []
for x in range(width):
# Use palette index based on position
palette_index = (x // 4 + y // 4) % len(palette)
row.append(palette_index)
pixels.append(row)
# Write palette PNG
writer = png.Writer(width=width, height=height, palette=palette, bitdepth=8)
with open('palette_image.png', 'wb') as f:
writer.write_array(f, pixels)import png
# Create 16-bit per channel image
width, height = 64, 64
pixels = []
for y in range(height):
row = []
for x in range(width):
# Use full 16-bit range (0-65535)
r = (x * 65535) // width
g = (y * 65535) // height
b = 32768 # Mid-range value
row.extend([r, g, b])
pixels.append(row)
# Write 16-bit RGB PNG
writer = png.Writer(width=width, height=height, greyscale=False, bitdepth=16)
with open('high_bit_depth.png', 'wb') as f:
writer.write_array(f, pixels)import png
# Create simple image
width, height = 32, 32
pixels = [[y * 8 for x in range(width)] for y in range(height)]
# Write PNG with gamma correction and resolution metadata
writer = png.Writer(
width=width,
height=height,
greyscale=True,
gamma=2.2, # Gamma correction
x_pixels_per_unit=2835, # 72 DPI in pixels per meter
y_pixels_per_unit=2835,
unit_is_meter=True
)
with open('metadata_image.png', 'wb') as f:
writer.write_array(f, pixels)import png
def generate_rows(width, height):
"""Generator function that yields rows on demand"""
for y in range(height):
row = []
for x in range(width):
# Generate pixel data on-the-fly
value = (x + y) % 256
row.append(value)
yield row
# Write PNG using row generator (memory efficient for large images)
width, height = 1000, 1000
writer = png.Writer(width=width, height=height, greyscale=True)
with open('large_generated.png', 'wb') as f:
writer.write(f, generate_rows(width, height))Install with Tessl CLI
npx tessl i tessl/pypi-pypng