CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pypng

Pure Python library for saving and loading PNG images without external dependencies

Pending
Overview
Eval results
Files

image-container.mddocs/

Image Container Operations

The Image class provides a convenient container for PNG image data with automatic format handling and multiple output methods. It bridges PNG reading and writing operations with a simple, high-level interface.

Capabilities

Image Container Class

The Image class encapsulates PNG image data and metadata, providing convenient methods for saving and manipulating image data.

class Image:
    def __init__(self, rows, info):
        """
        Initialize Image container with pixel data and metadata.
        
        Parameters:
        - rows: iterable of pixel rows
        - info: dict containing PNG metadata (width, height, bitdepth, etc.)
        
        Note: This constructor is not intended for direct use. Create Image 
        objects using png.from_array() or Reader methods that return Images.
        """
        
    def save(self, file):
        """
        Save image to a named file.
        
        Parameters:
        - file: str, path to output PNG file
        """
        
    def write(self, file):
        """
        Write image to an open file object.
        
        Parameters:
        - file: file-like object opened in binary write mode
        """
        
    def stream(self):
        """
        Convert row iterator to accessible list.
        
        Returns:
        list: List of pixel rows, where each row is a sequence of pixel values
        
        Note: This method consumes the row iterator, so it can only be called once.
        """

Usage Examples

Creating Images from Arrays

import png

# Create Image from 2D array
pixel_data = [
    [255, 0, 0, 255, 255, 0],      # Red, Yellow pixels (RGB)
    [0, 255, 0, 0, 0, 255],        # Green, Blue pixels  
    [128, 128, 128, 64, 64, 64]    # Two grey pixels
]

# Create Image object
image = png.from_array(pixel_data, 'RGB')

# Save to file
image.save('array_image.png')

Working with Image Data

import png

# Create a simple greyscale gradient
width, height = 64, 64
pixels = []
for y in range(height):
    row = []
    for x in range(width):
        # Diagonal gradient
        value = int(255 * (x + y) / (width + height - 2))
        row.append(value)
    pixels.append(row)

# Create Image
image = png.from_array(pixels, 'L')  # 'L' for greyscale

# Access pixel data as list
pixel_rows = image.stream()
print(f"Image has {len(pixel_rows)} rows")
print(f"First row has {len(pixel_rows[0])} pixels")
print(f"Top-left pixel value: {pixel_rows[0][0]}")
print(f"Bottom-right pixel value: {pixel_rows[-1][-1]}")

Converting Between Formats

import png

# Read existing PNG as Image
reader = png.Reader(filename='input.png')
width, height, rows, info = reader.read()

# Create Image container
image = png.Image(rows, info)

# Save with different filename
image.save('copy.png')

# Or write to file object with custom handling
with open('processed.png', 'wb') as f:
    image.write(f)

Processing Image Data

import png

# Create test image
original_data = [
    [100, 150, 200],  # Row 1
    [120, 170, 220],  # Row 2  
    [140, 190, 240]   # Row 3
]

image = png.from_array(original_data, 'L')

# Get pixel data for processing
rows = image.stream()

# Process pixels (brighten by 20%)
processed_rows = []
for row in rows:
    new_row = []
    for pixel in row:
        # Brighten pixel, clamp to 255
        new_pixel = min(255, int(pixel * 1.2))
        new_row.append(new_pixel)
    processed_rows.append(new_row)

# Create new image with processed data
processed_image = png.from_array(processed_rows, 'L')
processed_image.save('brightened.png')

Memory-Efficient Image Handling

import png

def process_large_image(input_file, output_file):
    """Process large PNG file without loading entire image into memory"""
    
    # Read image metadata without loading all pixel data
    reader = png.Reader(filename=input_file)
    width, height, rows, info = reader.read()
    
    # Process rows one at a time
    def processed_rows():
        for row in rows:
            # Apply some processing to each row
            processed_row = [min(255, pixel + 50) for pixel in row]
            yield processed_row
    
    # Write processed image
    writer = png.Writer(width=width, height=height, **info)
    with open(output_file, 'wb') as f:
        writer.write(f, processed_rows())

# Usage
process_large_image('large_input.png', 'large_output.png')

Image Information Access

import png

# Create image with metadata
pixels = [[x for x in range(100)] for y in range(50)]
image = png.from_array(pixels, 'L')

# The Image object contains the info dict with metadata
# Access through the internal structure (for advanced use)
print("Image dimensions available through save/write operations")

# To access metadata, work with Reader directly
reader = png.Reader(filename='test.png')
width, height, rows, info = reader.read()

print(f"Width: {width}")
print(f"Height: {height}")
print(f"Bit depth: {info.get('bitdepth', 'unknown')}")
print(f"Color type: {info.get('greyscale', 'color')}")
print(f"Has alpha: {info.get('alpha', False)}")
print(f"Interlaced: {info.get('interlace', False)}")

Chaining Operations

import png

# Chain Image operations for fluent workflow
def create_test_pattern():
    """Create a test pattern image"""
    width, height = 32, 32
    pixels = []
    
    for y in range(height):
        row = []
        for x in range(width):
            # Create checkerboard pattern
            if (x // 4 + y // 4) % 2:
                r, g, b = 255, 255, 255  # White
            else:
                r, g, b = 0, 0, 0        # Black
            row.extend([r, g, b])
        pixels.append(row)
    
    return png.from_array(pixels, 'RGB')

# Create and save in one operation
test_image = create_test_pattern()
test_image.save('test_pattern.png')

# Or use for further processing
pixel_data = test_image.stream()
print(f"Created {len(pixel_data)}x{len(pixel_data[0])//3} RGB image")

Install with Tessl CLI

npx tessl i tessl/pypi-pypng

docs

convenience.md

image-container.md

index.md

reading.md

writing.md

tile.json