perceptimg
Perceptual, policy-driven image optimization for modern workflows
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.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support the Project
If you find perceptimg useful, consider supporting its development:
License
This project is licensed under the MIT License - see the LICENSE file for details.
Attribution Required:
- Author: Marc Rivero | @seifreed
- Repository: github.com/seifreed/perceptimg
Made with dedication for the image optimization community
Metadata
Release files for perceptimg 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| perceptimg-0.1.2.tar.gz | 109.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| perceptimg-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 207.7 kB
Release files / perceptimg-0.1.2.tar.gz
| Download URL | perceptimg-0.1.2.tar.gz |
|---|---|
| Size | 109.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a7ff2c8c2be1323a3f1856a7fba2e6fb85197606ee7cc8c5441e40f15439ab31
|
|
BLAKE2b-256 checksum How to use checksums |
842d677ec90a5317d6771f4a29a747ebb3ed734266eecf94ca1d6cb345d01d01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 10, 2026.
Transparency logRelease files / perceptimg-0.1.2-py3-none-any.whl
| Download URL | perceptimg-0.1.2-py3-none-any.whl |
|---|---|
| Size | 97.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
15e80ecaea9020b34f05971ce9928479ffc586255ab76353aca2b701e2d680fc
|
|
BLAKE2b-256 checksum How to use checksums |
46fbb54dba889a942bdef62907d87a1962f16c230a0939edbcac26de9bbe2c73
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 10, 2026.
Transparency log