Skip to main content

Perceptual, policy-driven image optimization engine for modern workflows

Project description

perceptimg

perceptimg

Perceptual, policy-driven image optimization for modern workflows

PyPI Version Python Versions License CI Status Coverage

GitHub Stars GitHub Issues Buy Me a Coffee


Overview

perceptimg is a Python library for perceptual, policy-driven image optimization. Unlike traditional tools that optimize for file size or a single quality knob, perceptimg analyzes image content, interprets declarative policies, tests multiple strategies, and selects the best candidate based on perceptual quality metrics.

Key Features

Feature Description
Policy-Driven Declarative constraints for size, quality, and use case
Content-Aware Analyzes images for text, faces, and edge density
Multi-Format JPEG, PNG, WebP, AVIF, JXL, HEIF, GIF, TIFF, APNG
Perceptual Metrics SSIM, PSNR, and weighted perceptual scoring
Explainable Results Full decision trail for every optimization
Batch Processing Parallel processing with progress callbacks
Enterprise Ready Checkpointing, retry, rate limiting, Prometheus metrics
Clean Architecture Dependency inversion, modular engines, extensible

Supported Formats

Core Formats     JPEG, PNG, TIFF, GIF (always available via Pillow)
Modern Formats   WebP, AVIF, JPEG XL (JXL), HEIF/HEIC, APNG (codec-dependent)

Installation

From PyPI (Recommended)

pip install perceptimg

From Source

git clone https://github.com/seifreed/perceptimg.git
cd perceptimg
python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install -e ".[dev]"

Releases

Releases are created from version tags and are published by .github/workflows/release.yml.

git tag v0.1.2
git push origin v0.1.2

The release workflow:

  • builds the wheel and sdist from the tagged commit,
  • publishes to PyPI with Trusted Publishing / OIDC,
  • attaches the built artifacts to the GitHub Release.

Before the first publish, add a PyPI trusted publisher for this repository using the workflow file release.yml and the GitHub environment pypi. The tag version must match project.version in pyproject.toml.


Quick Start

from perceptimg import optimize, Policy

# Define policy constraints
policy = Policy(
    max_size_kb=150,
    min_ssim=0.97,
    preserve_text=True,
    target_use_case="web"
)

# Optimize image
result = optimize("input.png", policy)

# Access results
print(f"Format: {result.report.chosen_format}")
print(f"Size: {result.report.size_before_kb:.1f}KB → {result.report.size_after_kb:.1f}KB")
print(f"SSIM: {result.report.ssim:.4f}")
print(f"Reasons: {result.report.reasons}")

Usage

Command Line Interface

# Basic optimization
perceptimg input.png --policy policy.json --out output.webp

# With inline constraints
perceptimg input.png --max-size-kb 100 --min-ssim 0.95 --formats webp,avif

# JSON output
perceptimg input.png --policy policy.json --log-json

# Batch processing with shell-expanded globs
perceptimg --batch images/*.png --output-dir optimized/

Available Options

Option Description
--policy Path to JSON policy file
--out Output file path for single-image mode only
--max-size-kb Maximum output size in KB
--min-ssim Minimum SSIM threshold (0.0-1.0)
--formats Preferred formats (comma-separated)
--preserve-text Prefer text clarity
--preserve-faces Prefer face quality
--log-json Structured JSON logging
--log-level Log level (DEBUG, INFO, WARNING)

For batch processing, use --output-dir instead of --out. Use either --input-dir or positional input paths/globs for batch input, not both.


Policy Configuration

Python API

from perceptimg import Policy

policy = Policy(
    max_size_kb=120,
    min_ssim=0.98,
    preserve_text=True,
    preserve_faces=True,
    allow_lossy=True,
    preferred_formats=("webp", "avif", "jpeg"),
    target_use_case="mobile",
)

JSON Configuration

{
  "max_size_kb": 150,
  "min_ssim": 0.97,
  "preserve_text": true,
  "preserve_faces": false,
  "allow_lossy": true,
  "preferred_formats": ["webp", "avif", "jpeg"],
  "target_use_case": "web"
}

Batch Processing

Basic Batch

from perceptimg import Policy, optimize_batch

policy = Policy(max_size_kb=100, min_ssim=0.9)
images = ["img1.png", "img2.png", "img3.png"]

result = optimize_batch(images, policy)
print(f"Success: {len(result.successful)}/{result.total}")
print(f"Success rate: {result.success_rate:.1%}")

Async Processing

import asyncio
from perceptimg import Policy, optimize_batch_async

async def main():
    policy = Policy(max_size_kb=100)
    result = await optimize_batch_async(images, policy)
    print(f"Processed {result.total} images")

asyncio.run(main())

Memory-Efficient Streaming

from perceptimg import Policy, optimize_lazy

policy = Policy(max_size_kb=100)

for path, result in optimize_lazy(large_image_list, policy):
    if isinstance(result, Exception):
        print(f"Error {path}: {result}")
    else:
        print(f"OK {path}: {result.report.size_after_kb:.1f}KB")

Enterprise Features

Checkpoint/Resume

from perceptimg import Policy, optimize_batch_with_checkpoint

result = optimize_batch_with_checkpoint(
    images,
    policy,
    checkpoint_path="checkpoint.json",
    checkpoint_interval=10,  # Save every 10 images
)
# Resume after interruption by calling again with same checkpoint_path

Retry with Exponential Backoff

from perceptimg import Policy, optimize_batch_with_retry
from perceptimg.core.retry import RetryConfig

retry_config = RetryConfig(max_retries=3, base_delay_ms=100)

result = optimize_batch_with_retry(
    images,
    policy,
    retry_config=retry_config,
    continue_on_error=True,
)

Rate Limiting

from perceptimg import Policy, optimize_batch_with_rate_limit
from perceptimg.core.rate_limiter import RateLimitConfig

rate_limit = RateLimitConfig(requests_per_second=5)

result = optimize_batch_with_rate_limit(
    images,
    policy,
    rate_limit=rate_limit,
)

Prometheus Metrics

from perceptimg import Policy, optimize_batch_with_metrics
from perceptimg.core.metrics_exporter import MetricsCollector

metrics = MetricsCollector()
result, stats = optimize_batch_with_metrics(images, policy, metrics=metrics)

print(f"Average SSIM: {stats['average_ssim']:.2f}")
print(f"Compression ratio: {stats['average_compression_ratio']:.1%}")

Architecture

perceptimg/
├── adapters/           # Framework adapters (PIL)
│   └── pil_adapter.py
├── core/               # Domain logic
│   ├── interfaces.py   # Abstractions (ImageAdapter Protocol)
│   ├── analyzer.py     # Content analysis
│   ├── metrics.py      # SSIM, PSNR, perceptual scoring
│   ├── optimizer.py    # Orchestration
│   ├── policy.py       # Declarative constraints
│   ├── strategy.py     # Candidate generation
│   └── batch/          # Batch processing
├── engines/            # Format-specific encoders
│   ├── webp_engine.py
│   ├── avif_engine.py
│   └── ...
└── utils/              # IO, heuristics, logging

Clean Architecture Compliance

Layer Responsibility
Core Business logic, domain models, policies
Adapters Framework-specific implementations
Engines Format-specific encoding
Utils Infrastructure services

Extensibility

Custom Optimization Engine

from perceptimg.engines.base import OptimizationEngine, EngineResult
from perceptimg.core.optimizer import Optimizer, register_engine

class MyCustomEngine(OptimizationEngine):
    format = "custom"
    priority = 100
    
    @property
    def is_available(self) -> bool:
        return True
    
    def optimize(self, image, strategy) -> EngineResult:
        # Custom optimization logic
        return EngineResult(data=optimized_bytes, format="custom", quality=90)

# Register custom engine
optimizer = Optimizer()
register_engine(optimizer, MyCustomEngine())

Custom Analyzer

from perceptimg.core.analyzer import Analyzer

class CustomAnalyzer(Analyzer):
    def analyze(self, image):
        result = super().analyze(image)
        # Add custom heuristics
        result.custom_score = self._compute_custom(image)
        return result

API Reference

OptimizationResult

Field Type Description
image_bytes bytes Optimized image data
image PIL.Image Pillow image object
report OptimizationReport Detailed results

OptimizationReport

Field Type Description
chosen_format str Selected format
quality int Quality setting
size_before_kb float Original size
size_after_kb float Optimized size
ssim float SSIM score
psnr float PSNR score
perceptual_score float Weighted quality score
reasons list[str] Decision trail

Requirements

  • Python 3.13+
  • Pillow (PIL fork)
  • NumPy
  • scikit-image
  • See pyproject.toml for full dependencies

Quality

This project enforces:

Tool Purpose
ruff Linting
black Formatting
mypy Type checking
bandit Security analysis
pytest Testing (145 tests)
# Run all quality checks
ruff check perceptimg tests
black perceptimg tests --check
mypy perceptimg --ignore-missing-imports
bandit -r perceptimg -q --exclude perceptimg/tests
pytest tests/

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support the Project

If you find perceptimg useful, consider supporting its development:

Buy Me A Coffee

License

This project is licensed under the MIT License - see the LICENSE file for details.

Attribution Required:


Made with dedication for the image optimization community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

perceptimg-0.1.2.tar.gz (109.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

perceptimg-0.1.2-py3-none-any.whl (97.9 kB view details)

Uploaded Python 3

File details

Details for the file perceptimg-0.1.2.tar.gz.

File metadata

  • Download URL: perceptimg-0.1.2.tar.gz
  • Upload date:
  • Size: 109.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for perceptimg-0.1.2.tar.gz
Algorithm Hash digest
SHA256 a7ff2c8c2be1323a3f1856a7fba2e6fb85197606ee7cc8c5441e40f15439ab31
MD5 af9a369cb9db10fb947c20f3a18b3b8b
BLAKE2b-256 842d677ec90a5317d6771f4a29a747ebb3ed734266eecf94ca1d6cb345d01d01

See more details on using hashes here.

Provenance

The following attestation bundles were made for perceptimg-0.1.2.tar.gz:

Publisher: release.yml on seifreed/perceptimg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file perceptimg-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: perceptimg-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 97.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for perceptimg-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 15e80ecaea9020b34f05971ce9928479ffc586255ab76353aca2b701e2d680fc
MD5 4fb24f596623adf3c4a6e4497707d77f
BLAKE2b-256 46fbb54dba889a942bdef62907d87a1962f16c230a0939edbcac26de9bbe2c73

See more details on using hashes here.

Provenance

The following attestation bundles were made for perceptimg-0.1.2-py3-none-any.whl:

Publisher: release.yml on seifreed/perceptimg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page